X-Git-Url: http://www.dolda2000.com/gitweb/?a=blobdiff_plain;f=lib%2Freq.c;h=8ff26e06b6b8aedcae50f61068d3f1c4efa00d9f;hb=d9f67feaea01146d7ea10abfff2dc59ff8946ced;hp=26711599a3879eec1697fbba7582b78522ee4a69;hpb=8f55ddd74fadb637a400e0ec4d0f2714dfb41804;p=ashd.git diff --git a/lib/req.c b/lib/req.c index 2671159..8ff26e0 100644 --- a/lib/req.c +++ b/lib/req.c @@ -21,6 +21,9 @@ #include #include #include +#include +#include +#include #ifdef HAVE_CONFIG_H #include @@ -89,6 +92,155 @@ char *getheader(struct hthead *head, char *name) return(NULL); } +static void trim(struct charbuf *buf) +{ + char *p; + + for(p = buf->b; (p - buf->b < buf->d) && isspace(*p); p++); + memmove(buf->b, p, buf->d -= (p - buf->b)); + if(buf->d > 0) + for(p = buf->b + buf->d - 1; (p > buf->b) && isspace(*p); p--, buf->d--); +} + +int parseheaders(struct hthead *head, FILE *in) +{ + int c, state; + struct charbuf name, val; + size_t tsz; + + bufinit(name); + bufinit(val); + state = 0; + tsz = 0; + while(1) { + c = fgetc(in); + if(++tsz >= 65536) + goto fail; + again: + if(state == 0) { + if(c == '\r') { + } else if(c == '\n') { + break; + } else if(c == EOF) { + goto fail; + } else { + state = 1; + goto again; + } + } else if(state == 1) { + if(c == ':') { + trim(&name); + bufadd(name, 0); + state = 2; + } else if(c == '\r') { + } else if(c == '\n') { + goto fail; + } else if(c == EOF) { + goto fail; + } else { + bufadd(name, c); + } + } else if(state == 2) { + if(c == '\r') { + } else if(c == '\n') { + trim(&val); + bufadd(val, 0); + headappheader(head, name.b, val.b); + buffree(name); + buffree(val); + state = 0; + } else if(c == EOF) { + goto fail; + } else { + bufadd(val, c); + } + } + } + return(0); + +fail: + buffree(name); + buffree(val); + return(-1); +} + +struct hthead *parseresponse(FILE *in) +{ + struct hthead *req; + int code; + struct charbuf ver, msg; + int c; + + req = NULL; + bufinit(ver); + bufinit(msg); + code = 0; + while(1) { + c = getc(in); + if(c == ' ') { + break; + } else if((c == EOF) || (c < 32) || (c >= 128)) { + goto fail; + } else { + bufadd(ver, c); + if(ver.d >= 128) + goto fail; + } + } + while(1) { + c = getc(in); + if(c == ' ') { + break; + } else if((c == EOF) || (c < '0') || (c > '9')) { + goto fail; + } else { + code = (code * 10) + (c - '0'); + if(code >= 10000) + goto fail; + } + } + while(1) { + c = getc(in); + if(c == 10) { + break; + } else if(c == 13) { + } else if((c == EOF) || (c < 32)) { + goto fail; + } else { + bufadd(msg, c); + if(msg.d >= 512) + goto fail; + } + } + bufadd(msg, 0); + bufadd(ver, 0); + req = mkresp(code, msg.b, ver.b); + if(parseheaders(req, in)) + goto fail; + goto out; + +fail: + if(req != NULL) { + freehthead(req); + req = NULL; + } +out: + buffree(msg); + buffree(ver); + return(req); +} + +void replrest(struct hthead *head, char *rest) +{ + char *tmp; + + /* Do not free the current rest string yet, so that the new one + * can be taken from a subpart of the old one. */ + tmp = head->rest; + head->rest = sstrdup(rest); + free(tmp); +} + void headpreheader(struct hthead *head, const char *name, const char *val) { head->headers = srealloc(head->headers, sizeof(*head->headers) * (head->noheaders + 1)); @@ -110,14 +262,39 @@ void headappheader(struct hthead *head, const char *name, const char *val) head->headers[i][1] = sstrdup(val); } -int sendreq(int sock, struct hthead *req) +void headrmheader(struct hthead *head, const char *name) +{ + int i; + + for(i = 0; i < head->noheaders; i++) { + if(!strcasecmp(head->headers[i][0], name)) { + free(head->headers[i][0]); + free(head->headers[i][1]); + free(head->headers[i]); + memmove(head->headers + i, head->headers + i + 1, sizeof(head->headers) * (--head->noheaders - i)); + return; + } + } +} + +int writeresp(FILE *out, struct hthead *resp) +{ + int i; + + if(fprintf(out, "%s %i %s\r\n", resp->ver, resp->code, resp->msg) < 0) + return(-1); + for(i = 0; i < resp->noheaders; i++) { + if(fprintf(out, "%s: %s\r\n", resp->headers[i][0], resp->headers[i][1]) < 0) + return(-1); + } + return(0); +} + +int sendreq2(int sock, struct hthead *req, int fd, int flags) { int ret, i; - int pfds[2]; struct charbuf buf; - if(socketpair(PF_UNIX, SOCK_STREAM, 0, pfds)) - return(-1); bufinit(buf); bufcatstr2(buf, req->method); bufcatstr2(buf, req->url); @@ -128,15 +305,17 @@ int sendreq(int sock, struct hthead *req) bufcatstr2(buf, req->headers[i][1]); } bufcatstr2(buf, ""); - ret = sendfd(sock, pfds[0], buf.b, buf.d); + ret = sendfd2(sock, fd, buf.b, buf.d, flags); buffree(buf); - close(pfds[0]); - if(ret < 0) { - close(pfds[1]); + if(ret < 0) return(-1); - } else { - return(pfds[1]); - } + else + return(0); +} + +int sendreq(int sock, struct hthead *req, int fd) +{ + return(sendreq2(sock, req, fd, MSG_NOSIGNAL | MSG_DONTWAIT)); } int recvreq(int sock, struct hthead **reqp) @@ -151,6 +330,7 @@ int recvreq(int sock, struct hthead **reqp) if((fd = recvfd(sock, &buf.b, &buf.d)) < 0) { return(-1); } + fcntl(fd, F_SETFD, FD_CLOEXEC); buf.s = buf.d; p = buf.b; l = buf.d; @@ -181,3 +361,37 @@ fail: errno = EPROTO; return(-1); } + +char *unquoteurl(char *in) +{ + struct charbuf buf; + char *p; + int c; + + bufinit(buf); + p = in; + while(*p) { + if(*p == '%') { + if(!p[1] || !p[2]) + goto fail; + c = 0; + if((p[1] >= '0') && (p[1] <= '9')) c |= (p[1] - '0') << 4; + else if((p[1] >= 'a') && (p[1] <= 'f')) c |= (p[1] - 'a' + 10) << 4; + else if((p[1] >= 'A') && (p[1] <= 'F')) c |= (p[1] - 'A' + 10) << 4; + else goto fail; + if((p[2] >= '0') && (p[2] <= '9')) c |= (p[2] - '0'); + else if((p[2] >= 'a') && (p[2] <= 'f')) c |= (p[2] - 'a' + 10); + else if((p[2] >= 'A') && (p[2] <= 'F')) c |= (p[2] - 'A' + 10); + else goto fail; + bufadd(buf, c); + p += 3; + } else { + bufadd(buf, *(p++)); + } + } + bufadd(buf, 0); + return(buf.b); +fail: + buffree(buf); + return(NULL); +}