URI:
       thio.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       thio.c (7538B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <httpd.h>
            4 
            5 static        char        hstates[] = "nrewE";
            6 static        char        hxfers[] = " x";
            7 static int _hflush(Hio*, int, int);
            8 
            9 int
           10 hinit(Hio *h, int fd, int mode)
           11 {
           12         if(fd == -1 || mode != Hread && mode != Hwrite)
           13                 return -1;
           14         h->hh = nil;
           15         h->fd = fd;
           16         h->seek = 0;
           17         h->state = mode;
           18         h->start = h->buf + 16;                /* leave space for chunk length */
           19         h->stop = h->pos = h->start;
           20         if(mode == Hread){
           21                 h->bodylen = ~0UL;
           22                 *h->pos = '\0';
           23         }else
           24                 h->stop = h->start + Hsize;
           25         return 0;
           26 }
           27 
           28 int
           29 hiserror(Hio *h)
           30 {
           31         return h->state == Herr;
           32 }
           33 
           34 int
           35 hgetc(Hio *h)
           36 {
           37         uchar *p;
           38 
           39         p = h->pos;
           40         if(p < h->stop){
           41                 h->pos = p + 1;
           42                 return *p;
           43         }
           44         p -= UTFmax;
           45         if(p < h->start)
           46                 p = h->start;
           47         if(!hreadbuf(h, p) || h->pos == h->stop)
           48                 return -1;
           49         return *h->pos++;
           50 }
           51 
           52 int
           53 hungetc(Hio *h)
           54 {
           55         if(h->state == Hend)
           56                 h->state = Hread;
           57         else if(h->state == Hread)
           58                 h->pos--;
           59         if(h->pos < h->start || h->state != Hread){
           60                 h->state = Herr;
           61                 h->pos = h->stop;
           62                 return -1;
           63         }
           64         return 0;
           65 }
           66 
           67 /*
           68  * fill the buffer, saving contents from vsave onwards.
           69  * nothing is saved if vsave is nil.
           70  * returns the beginning of the buffer.
           71  *
           72  * understands message body sizes and chunked transfer encoding
           73  */
           74 void *
           75 hreadbuf(Hio *h, void *vsave)
           76 {
           77         Hio *hh;
           78         uchar *save;
           79         int c, in, cpy, dpos;
           80 
           81         save = vsave;
           82         if(save && (save < h->start || save > h->stop)
           83         || h->state != Hread && h->state != Hend){
           84                 h->state = Herr;
           85                 h->pos = h->stop;
           86                 return nil;
           87         }
           88 
           89         dpos = 0;
           90         if(save && h->pos > save)
           91                 dpos = h->pos - save;
           92         cpy = 0;
           93         if(save){
           94                 cpy = h->stop - save;
           95                 memmove(h->start, save, cpy);
           96         }
           97         h->seek += h->stop - h->start - cpy;
           98         h->pos = h->start + dpos;
           99 
          100         in = Hsize - cpy;
          101         if(h->state == Hend)
          102                 in = 0;
          103         else if(in > h->bodylen)
          104                 in = h->bodylen;
          105 
          106         /*
          107          * for chunked encoding, fill buffer,
          108          * then read in new chunk length and wipe out that line
          109          */
          110         hh = h->hh;
          111         if(hh != nil){
          112                 if(!in && h->xferenc && h->state != Hend){
          113                         if(h->xferenc == 2){
          114                                 c = hgetc(hh);
          115                                 if(c == '\r')
          116                                         c = hgetc(hh);
          117                                 if(c != '\n'){
          118                                         h->pos = h->stop;
          119                                         h->state = Herr;
          120                                         return nil;
          121                                 }
          122                         }
          123                         h->xferenc = 2;
          124                         in = 0;
          125                         while((c = hgetc(hh)) != '\n'){
          126                                 if(c >= '0' && c <= '9')
          127                                         c -= '0';
          128                                 else if(c >= 'a' && c <= 'f')
          129                                         c -= 'a' - 10;
          130                                 else if(c >= 'A' && c <= 'F')
          131                                         c -= 'A' - 10;
          132                                 else
          133                                         break;
          134                                 in = in * 16 + c;
          135                         }
          136                         while(c != '\n'){
          137                                 if(c < 0){
          138                                         h->pos = h->stop;
          139                                         h->state = Herr;
          140                                         return nil;
          141                                 }
          142                                 c = hgetc(hh);
          143                         }
          144                         h->bodylen = in;
          145 
          146                         in = Hsize - cpy;
          147                         if(in > h->bodylen)
          148                                 in = h->bodylen;
          149                 }
          150                 if(in){
          151                         while(hh->pos + in > hh->stop){
          152                                 if(hreadbuf(hh, hh->pos) == nil){
          153                                         h->pos = h->stop;
          154                                         h->state = Herr;
          155                                         return nil;
          156                                 }
          157                         }
          158                         memmove(h->start + cpy, hh->pos, in);
          159                         hh->pos += in;
          160                 }
          161         }else if(in){
          162                 if((in = read(h->fd, h->start + cpy, in)) < 0){
          163                         h->state = Herr;
          164                         h->pos = h->stop;
          165                         return nil;
          166                 }
          167         }
          168         if(in == 0)
          169                 h->state = Hend;
          170 
          171         h->bodylen -= in;
          172 
          173         h->stop = h->start + cpy + in;
          174         *h->stop = '\0';
          175         if(h->pos == h->stop)
          176                 return nil;
          177         return h->start;
          178 }
          179 
          180 int
          181 hbuflen(Hio *h, void *p)
          182 {
          183         return h->stop - (uchar*)p;
          184 }
          185 
          186 /*
          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
          191  */
          192 Hio*
          193 hbodypush(Hio *hh, ulong len, HFields *te)
          194 {
          195         Hio *h;
          196         int xe;
          197 
          198         if(hh->state != Hread)
          199                 return nil;
          200         xe = 0;
          201         if(te != nil){
          202                 if(te->params != nil || te->next != nil)
          203                         return nil;
          204                 if(cistrcmp(te->s, "chunked") == 0){
          205                         xe = 1;
          206                         len = 0;
          207                 }else if(cistrcmp(te->s, "identity") == 0){
          208                         ;
          209                 }else
          210                         return nil;
          211         }
          212 
          213         h = malloc(sizeof *h);
          214         if(h == nil)
          215                 return nil;
          216 
          217         h->hh = hh;
          218         h->fd = -1;
          219         h->seek = 0;
          220         h->state = Hread;
          221         h->xferenc = xe;
          222         h->start = h->buf + 16;                /* leave space for chunk length */
          223         h->stop = h->pos = h->start;
          224         *h->pos = '\0';
          225         h->bodylen = len;
          226         return h;
          227 }
          228 
          229 /*
          230  * dump the state of the io buffer into a string
          231  */
          232 char *
          233 hunload(Hio *h)
          234 {
          235         uchar *p, *t, *stop, *buf;
          236         int ne, n, c;
          237 
          238         stop = h->stop;
          239         ne = 0;
          240         for(p = h->pos; p < stop; p++){
          241                 c = *p;
          242                 if(c == 0x80)
          243                         ne++;
          244         }
          245         p = h->pos;
          246 
          247         n = (stop - p) + ne + 3;
          248         buf = mallocz(n, 1);
          249         if(buf == nil)
          250                 return nil;
          251         buf[0] = hstates[h->state];
          252         buf[1] = hxfers[h->xferenc];
          253 
          254         t = &buf[2];
          255         for(; p < stop; p++){
          256                 c = *p;
          257                 if(c == 0 || c == 0x80){
          258                         *t++ = 0x80;
          259                         if(c == 0x80)
          260                                 *t++ = 0x80;
          261                 }else
          262                         *t++ = c;
          263         }
          264         *t++ = '\0';
          265         if(t != buf + n)
          266                 return nil;
          267         return (char*)buf;
          268 }
          269 
          270 /*
          271  * read the io buffer state from a string
          272  */
          273 int
          274 hload(Hio *h, char *buf)
          275 {
          276         uchar *p, *t, *stop;
          277         char *s;
          278         int c;
          279 
          280         s = strchr(hstates, buf[0]);
          281         if(s == nil)
          282                 return -1;
          283         h->state = s - hstates;
          284 
          285         s = strchr(hxfers, buf[1]);
          286         if(s == nil)
          287                 return -1;
          288         h->xferenc = s - hxfers;
          289 
          290         t = h->start;
          291         stop = t + Hsize;
          292         for(p = (uchar*)&buf[2]; c = *p; p++){
          293                 if(c == 0x80){
          294                         if(p[1] != 0x80)
          295                                 c = 0;
          296                         else
          297                                 p++;
          298                 }
          299                 *t++ = c;
          300                 if(t >= stop)
          301                         return -1;
          302         }
          303         *t = '\0';
          304         h->pos = h->start;
          305         h->stop = t;
          306         h->seek = 0;
          307         return 0;
          308 }
          309 
          310 void
          311 hclose(Hio *h)
          312 {
          313         if(h->fd >= 0){
          314                 if(h->state == Hwrite)
          315                         hxferenc(h, 0);
          316                 close(h->fd);
          317         }
          318         h->stop = h->pos = nil;
          319         h->fd = -1;
          320 }
          321 
          322 /*
          323  * flush the buffer and possibly change encoding modes
          324  */
          325 int
          326 hxferenc(Hio *h, int on)
          327 {
          328         if(h->xferenc && !on && h->pos != h->start)
          329                 hflush(h);
          330         if(_hflush(h, 1, 0) < 0)
          331                 return -1;
          332         h->xferenc = !!on;
          333         return 0;
          334 }
          335 
          336 int
          337 hputc(Hio *h, int c)
          338 {
          339         uchar *p;
          340 
          341         p = h->pos;
          342         if(p < h->stop){
          343                 h->pos = p + 1;
          344                 return *p = c;
          345         }
          346         if(hflush(h) < 0)
          347                 return -1;
          348         return *h->pos++ = c;
          349 }
          350 
          351 static int
          352 fmthflush(Fmt *f)
          353 {
          354         Hio *h;
          355 
          356         h = f->farg;
          357         h->pos = f->to;
          358         if(hflush(h) < 0)
          359                 return 0;
          360         f->stop = h->stop;
          361         f->to = h->pos;
          362         f->start = h->pos;
          363         return 1;
          364 }
          365 
          366 int
          367 hvprint(Hio *h, char *fmt, va_list args)
          368 {
          369         int n;
          370         Fmt f;
          371 
          372         f.runes = 0;
          373         f.stop = h->stop;
          374         f.to = h->pos;
          375         f.start = h->pos;
          376         f.flush = fmthflush;
          377         f.farg = h;
          378         f.nfmt = 0;
          379         fmtlocaleinit(&f, nil, nil, nil);
          380         n = fmtvprint(&f, fmt, args);
          381         h->pos = f.to;
          382         return n;
          383 }
          384 
          385 int
          386 hprint(Hio *h, char *fmt, ...)
          387 {
          388         int n;
          389         va_list arg;
          390 
          391         va_start(arg, fmt);
          392         n = hvprint(h, fmt, arg);
          393         va_end(arg);
          394         return n;
          395 }
          396 
          397 static int
          398 _hflush(Hio *h, int force, int dolength)
          399 {
          400         uchar *s;
          401         int w;
          402 
          403         if(h->state != Hwrite){
          404                 h->state = Herr;
          405                 h->stop = h->pos;
          406                 return -1;
          407         }
          408         s = h->start;
          409         w = h->pos - s;
          410         if(w == 0 && !force)
          411                 return 0;
          412         if(h->xferenc){
          413                 *--s = '\n';
          414                 *--s = '\r';
          415                 do{
          416                         *--s = "0123456789abcdef"[w & 0xf];
          417                         w >>= 4;
          418                 }while(w);
          419                 h->pos[0] = '\r';
          420                 h->pos[1] = '\n';
          421                 w = &h->pos[2] - s;
          422         }
          423         if(dolength)
          424                 fprint(h->fd, "Content-Length: %d\r\n\r\n", w);
          425         if(write(h->fd, s, w) != w){
          426                 h->state = Herr;
          427                 h->stop = h->pos;
          428                 return -1;
          429         }
          430         h->seek += w;
          431         h->pos = h->start;
          432         return 0;
          433 }
          434 
          435 int
          436 hflush(Hio *h)
          437 {
          438         return _hflush(h, 0, 0);
          439 }
          440 
          441 int
          442 hlflush(Hio* h)
          443 {
          444         return _hflush(h, 0, 1);
          445 }
          446 
          447 int
          448 hwrite(Hio *h, void *vbuf, int len)
          449 {
          450         uchar *buf;
          451         int n, m;
          452 
          453         buf = vbuf;
          454         n = len;
          455         if(n < 0 || h->state != Hwrite){
          456                 h->state = Herr;
          457                 h->stop = h->pos;
          458                 return -1;
          459         }
          460         if(h->pos + n >= h->stop){
          461                 if(h->start != h->pos)
          462                         if(hflush(h) < 0)
          463                                 return -1;
          464                 while(h->pos + n >= h->stop){
          465                         m = h->stop - h->pos;
          466                         if(h->xferenc){
          467                                 memmove(h->pos, buf, m);
          468                                 h->pos += m;
          469                                 if(hflush(h) < 0)
          470                                         return -1;
          471                         }else{
          472                                 if(write(h->fd, buf, m) != m){
          473                                         h->state = Herr;
          474                                         h->stop = h->pos;
          475                                         return -1;
          476                                 }
          477                                 h->seek += m;
          478                         }
          479                         n -= m;
          480                         buf += m;
          481                 }
          482         }
          483         memmove(h->pos, buf, n);
          484         h->pos += n;
          485         return len;
          486 }