+static struct hthead *parserawresp(char *buf)
+{
+ char *p, *p2, *nl;
+ char *msg, *ver;
+ int code;
+ struct hthead *resp;
+
+ if((nl = strchr(buf, '\n')) == NULL)
+ return(NULL);
+ p = strchr(buf, '\r');
+ if((p != NULL) && (p < nl))
+ nl = p;
+ if(strncmp(buf, "HTTP/", 5))
+ return(NULL);
+ ver = p = buf + 5;
+ for(; ((*p >= '0') && (*p <= '9')) || (*p == '.'); p++);
+ if(*p != ' ')
+ return(NULL);
+ *(p++) = 0;
+ if(((p2 = strchr(p, ' ')) == NULL) || (p2 > nl))
+ return(NULL);
+ *(p2++) = 0;
+ code = atoi(p);
+ if((code < 100) || (code >= 600))
+ return(NULL);
+ if(p2 >= nl)
+ return(NULL);
+ msg = p2;
+ p = nl;
+ if(!SKIPNL(p))
+ return(NULL);
+
+ resp = mkresp(code, msg, ver);
+ while(1) {
+ if(SKIPNL(p)) {
+ if(*p)
+ goto fail;
+ break;
+ }
+ if((nl = strchr(p, '\n')) == NULL)
+ goto fail;
+ if(((p2 = strchr(p, ':')) == NULL) || (p2 > nl))
+ goto fail;
+ *(p2++) = 0;
+ for(; (*p2 == ' ') || (*p2 == '\t'); p2++);
+ for(nl = p2; (*nl != '\r') && (*nl != '\n'); nl++);
+ if(!SKIPNL(nl))
+ goto fail;
+ headappheader(resp, p, p2);
+ p = nl;
+ }
+ return(resp);
+
+fail:
+ freehthead(resp);
+ return(NULL);
+}
+
+static off_t passdata(int src, int dst, struct charbuf *buf, off_t max)
+{
+ size_t dataoff, smax;
+ off_t sent;
+ int eof, ret;
+
+ sent = 0;
+ eof = 0;
+ while(!eof || (buf->d > 0)) {
+ if(!eof && (buf->d < buf->s) && ((max < 0) || (sent + buf->d < max))) {
+ while(1) {
+ ret = recv(src, buf->b + buf->d, buf->s - buf->d, MSG_DONTWAIT);
+ if((ret < 0) && (errno == EAGAIN)) {
+ } else if(ret < 0) {
+ return(-1);
+ } else if(ret == 0) {
+ eof = 1;
+ break;
+ } else {
+ buf->d += ret;
+ break;
+ }
+ if(buf->d > 0)
+ break;
+ if(block(src, EV_READ, 0) <= 0)
+ return(-1);
+ }
+ }
+ for(dataoff = 0; (dataoff < buf->d) && ((max < 0) || (sent < max));) {
+ if(block(dst, EV_WRITE, 120) <= 0)
+ return(-1);
+ smax = buf->d - dataoff;
+ if(sent + smax > max)
+ smax = max - sent;
+ ret = send(dst, buf->b + dataoff, smax, MSG_NOSIGNAL | MSG_DONTWAIT);
+ if(ret < 0)
+ return(-1);
+ dataoff += ret;
+ sent += ret;
+ }
+ bufeat(*buf, dataoff);
+ }
+ return(sent);
+}
+