URI:
       thttp.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
       ---
       thttp.c (4762B)
       ---
            1 #include "a.h"
            2 
            3 static char*
            4 haveheader(char *buf, int n)
            5 {
            6         int i;
            7 
            8         for(i=0; i<n; i++){
            9                 if(buf[i] == '\n'){
           10                         if(i+2 < n && buf[i+1] == '\r' && buf[i+2] == '\n')
           11                                 return buf+i+3;
           12                         if(i+1 < n && buf[i+1] == '\n')
           13                                 return buf+i+2;
           14                 }
           15         }
           16         return 0;
           17 }
           18 
           19 static int
           20 parseheader(char *buf, int n, HTTPHeader *hdr)
           21 {
           22         int nline;
           23         char *data, *ebuf, *p, *q, *next;
           24 
           25         memset(hdr, 0, sizeof *hdr);
           26         ebuf = buf+n;
           27         data = haveheader(buf, n);
           28         if(data == nil)
           29                 return -1;
           30 
           31         data[-1] = 0;
           32         if(data[-2] == '\r')
           33                 data[-2] = 0;
           34         if(chattyhttp > 1){
           35                 fprint(2, "--HTTP Response Header:\n");
           36                 fprint(2, "%s\n", buf);
           37                 fprint(2, "--\n");
           38         }
           39         nline = 0;
           40         for(p=buf; *p; p=next, nline++){
           41                 q = strchr(p, '\n');
           42                 if(q){
           43                         next = q+1;
           44                         *q = 0;
           45                         if(q > p && q[-1] == '\r')
           46                                 q[-1] = 0;
           47                 }else
           48                         next = p+strlen(p);
           49                 if(nline == 0){
           50                         if(memcmp(p, "HTTP/", 5) != 0){
           51                                 werrstr("invalid HTTP version: %.10s", p);
           52                                 return -1;
           53                         }
           54                         q = strchr(p, ' ');
           55                         if(q == nil){
           56                                 werrstr("invalid HTTP version");
           57                                 return -1;
           58                         }
           59                         *q++ = 0;
           60                         strncpy(hdr->proto, p, sizeof hdr->proto);
           61                         hdr->proto[sizeof hdr->proto-1] = 0;
           62                         while(*q == ' ')
           63                                 q++;
           64                         if(*q < '0' || '9' < *q){
           65                                 werrstr("invalid HTTP response code");
           66                                 return -1;
           67                         }
           68                         p = q;
           69                         q = strchr(p, ' ');
           70                         if(q == nil)
           71                                 q = p+strlen(p);
           72                         else
           73                                 *q++ = 0;
           74                         hdr->code = strtol(p, &p, 10);
           75                         if(*p != 0)
           76                                 return -1;
           77                         while(*q == ' ')
           78                                 q++;
           79                         strncpy(hdr->codedesc, q, sizeof hdr->codedesc);
           80                         hdr->codedesc[sizeof hdr->codedesc-1] = 0;
           81                         continue;
           82                 }
           83                 q = strchr(p, ':');
           84                 if(q == nil)
           85                         continue;
           86                 *q++ = 0;
           87                 while(*q != 0 && (*q == ' ' || *q == '\t'))
           88                         q++;
           89                 if(cistrcmp(p, "Content-Type") == 0){
           90                         strncpy(hdr->contenttype, q, sizeof hdr->contenttype);
           91                         hdr->contenttype[sizeof hdr->contenttype-1] = 0;
           92                         continue;
           93                 }
           94                 if(cistrcmp(p, "Content-Length") == 0 && '0' <= *q && *q <= '9'){
           95                         hdr->contentlength = strtoll(q, 0, 10);
           96                         continue;
           97                 }
           98         }
           99         if(nline < 1){
          100                 werrstr("no header");
          101                 return -1;
          102         }
          103 
          104         memmove(buf, data, ebuf - data);
          105         return ebuf - data;
          106 }
          107 
          108 static char*
          109 genhttp(Protocol *proto, char *host, char *req, HTTPHeader *hdr, int wfd, int rfd, vlong rtotal)
          110 {
          111         int n, m, total, want;
          112         char buf[8192], *data;
          113         Pfd *fd;
          114 
          115         if(chattyhttp > 1){
          116                 fprint(2, "--HTTP Request:\n");
          117                 fprint(2, "%s", req);
          118                 fprint(2, "--\n");
          119         }
          120         fd = proto->connect(host);
          121         if(fd == nil){
          122                 if(chattyhttp > 0)
          123                         fprint(2, "connect %s: %r\n", host);
          124                 return nil;
          125         }
          126 
          127         n = strlen(req);
          128         if(proto->write(fd, req, n) != n){
          129                 if(chattyhttp > 0)
          130                         fprint(2, "write %s: %r\n", host);
          131                 proto->close(fd);
          132                 return nil;
          133         }
          134 
          135         if(rfd >= 0){
          136                 while(rtotal > 0){
          137                         m = sizeof buf;
          138                         if(m > rtotal)
          139                                 m = rtotal;
          140                         if((n = read(rfd, buf, m)) <= 0){
          141                                 fprint(2, "read: missing data\n");
          142                                 proto->close(fd);
          143                                 return nil;
          144                         }
          145                         if(proto->write(fd, buf, n) != n){
          146                                 fprint(2, "write data: %r\n");
          147                                 proto->close(fd);
          148                                 return nil;
          149                         }
          150                         rtotal -= n;
          151                 }
          152         }
          153 
          154         total = 0;
          155         while(!haveheader(buf, total)){
          156                 n = proto->read(fd, buf+total, sizeof buf-total);
          157                 if(n <= 0){
          158                         if(chattyhttp > 0)
          159                                 fprint(2, "read missing header\n");
          160                         proto->close(fd);
          161                         return nil;
          162                 }
          163                 total += n;
          164         }
          165 
          166         n = parseheader(buf, total, hdr);
          167         if(n < 0){
          168                 fprint(2, "failed response parse: %r\n");
          169                 proto->close(fd);
          170                 return nil;
          171         }
          172         if(hdr->contentlength >= MaxResponse){
          173                 werrstr("response too long");
          174                 proto->close(fd);
          175                 return nil;
          176         }
          177         if(hdr->contentlength >= 0 && n > hdr->contentlength)
          178                 n = hdr->contentlength;
          179         want = sizeof buf;
          180         data = nil;
          181         total = 0;
          182         goto didread;
          183 
          184         while(want > 0 && (n = proto->read(fd, buf, want)) > 0){
          185         didread:
          186                 if(wfd >= 0){
          187                         if(writen(wfd, buf, n) < 0){
          188                                 proto->close(fd);
          189                                 werrstr("write error");
          190                                 return nil;
          191                         }
          192                 }else{
          193                         data = erealloc(data, total+n);
          194                         memmove(data+total, buf, n);
          195                 }
          196                 total += n;
          197                 if(total > MaxResponse){
          198                         proto->close(fd);
          199                         werrstr("response too long");
          200                         return nil;
          201                 }
          202                 if(hdr->contentlength >= 0 && total + want > hdr->contentlength)
          203                         want = hdr->contentlength - total;
          204         }
          205         proto->close(fd);
          206 
          207         if(hdr->contentlength >= 0 && total != hdr->contentlength){
          208                 werrstr("got wrong content size %d %d", total, hdr->contentlength);
          209                 return nil;
          210         }
          211         hdr->contentlength = total;
          212         if(wfd >= 0)
          213                 return (void*)1;
          214         else{
          215                 data = erealloc(data, total+1);
          216                 data[total] = 0;
          217         }
          218         return data;
          219 }
          220 
          221 char*
          222 httpreq(Protocol *proto, char *host, char *req, HTTPHeader *hdr, int rfd, vlong rlength)
          223 {
          224         return genhttp(proto, host, req, hdr, -1, rfd, rlength);
          225 }
          226 
          227 int
          228 httptofile(Protocol *proto, char *host, char *req, HTTPHeader *hdr, int fd)
          229 {
          230         if(fd < 0){
          231                 werrstr("bad fd");
          232                 return -1;
          233         }
          234         if(genhttp(proto, host, req, hdr, fd, -1, 0) == nil)
          235                 return -1;
          236         return 0;
          237 }