4 haveheader(char *buf, int n)
10 if(i+2 < n && buf[i+1] == '\r' && buf[i+2] == '\n')
12 if(i+1 < n && buf[i+1] == '\n')
20 parseheader(char *buf, int n, HTTPHeader *hdr)
23 char *data, *ebuf, *p, *q, *next;
25 memset(hdr, 0, sizeof *hdr);
27 data = haveheader(buf, n);
35 fprint(2, "--HTTP Response Header:\n");
36 fprint(2, "%s\n", buf);
40 for(p=buf; *p; p=next, nline++){
45 if(q > p && q[-1] == '\r')
50 if(memcmp(p, "HTTP/", 5) != 0){
51 werrstr("invalid HTTP version: %.10s", p);
56 werrstr("invalid HTTP version");
60 strncpy(hdr->proto, p, sizeof hdr->proto);
61 hdr->proto[sizeof hdr->proto-1] = 0;
64 if(*q < '0' || '9' < *q){
65 werrstr("invalid HTTP response code");
74 hdr->code = strtol(p, &p, 10);
79 strncpy(hdr->codedesc, q, sizeof hdr->codedesc);
80 hdr->codedesc[sizeof hdr->codedesc-1] = 0;
87 while(*q != 0 && (*q == ' ' || *q == '\t'))
89 if(cistrcmp(p, "Content-Type") == 0){
90 strncpy(hdr->contenttype, q, sizeof hdr->contenttype);
91 hdr->contenttype[sizeof hdr->contenttype-1] = 0;
94 if(cistrcmp(p, "Content-Length") == 0 && '0' <= *q && *q <= '9'){
95 hdr->contentlength = strtoll(q, 0, 10);
100 werrstr("no header");
104 memmove(buf, data, ebuf - data);
109 genhttp(Protocol *proto, char *host, char *req, HTTPHeader *hdr, int wfd, int rfd, vlong rtotal)
111 int n, m, total, want;
112 char buf[8192], *data;
116 fprint(2, "--HTTP Request:\n");
117 fprint(2, "%s", req);
120 fd = proto->connect(host);
123 fprint(2, "connect %s: %r\n", host);
128 if(proto->write(fd, req, n) != n){
130 fprint(2, "write %s: %r\n", host);
140 if((n = read(rfd, buf, m)) <= 0){
141 fprint(2, "read: missing data\n");
145 if(proto->write(fd, buf, n) != n){
146 fprint(2, "write data: %r\n");
155 while(!haveheader(buf, total)){
156 n = proto->read(fd, buf+total, sizeof buf-total);
159 fprint(2, "read missing header\n");
166 n = parseheader(buf, total, hdr);
168 fprint(2, "failed response parse: %r\n");
172 if(hdr->contentlength >= MaxResponse){
173 werrstr("response too long");
177 if(hdr->contentlength >= 0 && n > hdr->contentlength)
178 n = hdr->contentlength;
184 while(want > 0 && (n = proto->read(fd, buf, want)) > 0){
187 if(writen(wfd, buf, n) < 0){
189 werrstr("write error");
193 data = erealloc(data, total+n);
194 memmove(data+total, buf, n);
197 if(total > MaxResponse){
199 werrstr("response too long");
202 if(hdr->contentlength >= 0 && total + want > hdr->contentlength)
203 want = hdr->contentlength - total;
207 if(hdr->contentlength >= 0 && total != hdr->contentlength){
208 werrstr("got wrong content size %d %d", total, hdr->contentlength);
211 hdr->contentlength = total;
215 data = erealloc(data, total+1);
222 httpreq(Protocol *proto, char *host, char *req, HTTPHeader *hdr, int rfd, vlong rlength)
224 return genhttp(proto, host, req, hdr, -1, rfd, rlength);
228 httptofile(Protocol *proto, char *host, char *req, HTTPHeader *hdr, int fd)
234 if(genhttp(proto, host, req, hdr, fd, -1, 0) == nil)