5 static char hstates[] = "nrewE";
6 static char hxfers[] = " x";
7 static int _hflush(Hio*, int, int);
10 hinit(Hio *h, int fd, int mode)
12 if(fd == -1 || mode != Hread && mode != Hwrite)
18 h->start = h->buf + 16; /* leave space for chunk length */
19 h->stop = h->pos = h->start;
24 h->stop = h->start + Hsize;
31 return h->state == Herr;
47 if(!hreadbuf(h, p) || h->pos == h->stop)
57 else if(h->state == Hread)
59 if(h->pos < h->start || h->state != Hread){
68 * fill the buffer, saving contents from vsave onwards.
69 * nothing is saved if vsave is nil.
70 * returns the beginning of the buffer.
72 * understands message body sizes and chunked transfer encoding
75 hreadbuf(Hio *h, void *vsave)
82 if(save && (save < h->start || save > h->stop)
83 || h->state != Hread && h->state != Hend){
90 if(save && h->pos > save)
95 memmove(h->start, save, cpy);
97 h->seek += h->stop - h->start - cpy;
98 h->pos = h->start + dpos;
103 else if(in > h->bodylen)
107 * for chunked encoding, fill buffer,
108 * then read in new chunk length and wipe out that line
112 if(!in && h->xferenc && h->state != Hend){
125 while((c = hgetc(hh)) != '\n'){
126 if(c >= '0' && c <= '9')
128 else if(c >= 'a' && c <= 'f')
130 else if(c >= 'A' && c <= 'F')
151 while(hh->pos + in > hh->stop){
152 if(hreadbuf(hh, hh->pos) == nil){
158 memmove(h->start + cpy, hh->pos, in);
162 if((in = read(h->fd, h->start + cpy, in)) < 0){
173 h->stop = h->start + cpy + in;
175 if(h->pos == h->stop)
181 hbuflen(Hio *h, void *p)
183 return h->stop - (uchar*)p;
187 * prepare to receive a message body
188 * len is the content length (~0 => unspecified)
189 * te is the transfer encoding
190 * returns < 0 if setup failed
193 hbodypush(Hio *hh, ulong len, HFields *te)
198 if(hh->state != Hread)
202 if(te->params != nil || te->next != nil)
204 if(cistrcmp(te->s, "chunked") == 0){
207 }else if(cistrcmp(te->s, "identity") == 0){
213 h = malloc(sizeof *h);
222 h->start = h->buf + 16; /* leave space for chunk length */
223 h->stop = h->pos = h->start;
230 * dump the state of the io buffer into a string
235 uchar *p, *t, *stop, *buf;
240 for(p = h->pos; p < stop; p++){
247 n = (stop - p) + ne + 3;
251 buf[0] = hstates[h->state];
252 buf[1] = hxfers[h->xferenc];
255 for(; p < stop; p++){
257 if(c == 0 || c == 0x80){
271 * read the io buffer state from a string
274 hload(Hio *h, char *buf)
280 s = strchr(hstates, buf[0]);
283 h->state = s - hstates;
285 s = strchr(hxfers, buf[1]);
288 h->xferenc = s - hxfers;
292 for(p = (uchar*)&buf[2]; c = *p; p++){
314 if(h->state == Hwrite)
318 h->stop = h->pos = nil;
323 * flush the buffer and possibly change encoding modes
326 hxferenc(Hio *h, int on)
328 if(h->xferenc && !on && h->pos != h->start)
330 if(_hflush(h, 1, 0) < 0)
348 return *h->pos++ = c;
367 hvprint(Hio *h, char *fmt, va_list args)
379 // fmtlocaleinit(&f, nil, nil, nil);
380 n = fmtvprint(&f, fmt, args);
386 hprint(Hio *h, char *fmt, ...)
392 n = hvprint(h, fmt, arg);
398 _hflush(Hio *h, int force, int dolength)
405 if(h->state != Hwrite){
418 *--s = "0123456789abcdef"[w & 0xf];
426 fprint(h->fd, "Content-Length: %d\r\n\r\n", w);
427 if(write(h->fd, s, w) != w){
440 return _hflush(h, 0, 0);
446 return _hflush(h, 0, 1);
450 hwrite(Hio *h, void *vbuf, int len)
457 if(n < 0 || h->state != Hwrite){
462 if(h->pos + n >= h->stop){
463 if(h->start != h->pos)
466 while(h->pos + n >= h->stop){
467 m = h->stop - h->pos;
469 memmove(h->pos, buf, m);
474 if(write(h->fd, buf, m) != m){
485 memmove(h->pos, buf, n);