plan9port

[fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port # fast
git clone https://src.adamsgaard.dk/plan9port.git # slow
Log | Files | Refs | README | LICENSE Back to index

http.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 }