X-Git-Url: http://www.dolda2000.com/gitweb/?p=ashd.git;a=blobdiff_plain;f=lib%2Freq.c;h=da8e3f0d8ffb463082a314762f4e1635bc2bc809;hp=4b16989a9636e66ca4ab1ce73c4c8ac1ce523abe;hb=90b0ba0f9d93e454cc08a566b718abdcbfd0d9f6;hpb=66987955eb1903d6d21d21471f145cbd1f514520 diff --git a/lib/req.c b/lib/req.c index 4b16989..da8e3f0 100644 --- a/lib/req.c +++ b/lib/req.c @@ -18,73 +18,309 @@ #include #include +#include +#include +#include +#include +#include +#include #ifdef HAVE_CONFIG_H #include #endif #include +#include #include +#include -struct htreq *mkreq(char *method, char *url, char *ver) +struct hthead *mkreq(char *method, char *url, char *ver) { - struct htreq *req; + struct hthead *req; omalloc(req); req->method = sstrdup(method); req->url = sstrdup(url); req->ver = sstrdup(ver); - req->restbuf = sstrdup(url); - req->rest = req->restbuf; + req->rest = sstrdup(url); return(req); } -void freereq(struct htreq *req) +struct hthead *mkresp(int code, char *msg, char *ver) +{ + struct hthead *resp; + + omalloc(resp); + resp->code = code; + resp->msg = sstrdup(msg); + resp->ver = sstrdup(ver); + return(resp); +} + +void freehthead(struct hthead *head) { int i; - free(req->method); - free(req->url); - free(req->ver); - free(req->restbuf); - if(req->headers) { - for(i = 0; i < req->noheaders; i++) { - free(req->headers[i][0]); - free(req->headers[i][1]); - free(req->headers[i]); + if(head->method != NULL) + free(head->method); + if(head->url != NULL) + free(head->url); + if(head->msg != NULL) + free(head->msg); + if(head->ver != NULL) + free(head->ver); + if(head->rest != NULL) + free(head->rest); + if(head->headers) { + for(i = 0; i < head->noheaders; i++) { + free(head->headers[i][0]); + free(head->headers[i][1]); + free(head->headers[i]); } - free(req->headers); + free(head->headers); } - free(req); + free(head); } -char *getheader(struct htreq *req, char *name) +char *getheader(struct hthead *head, char *name) { int i; - for(i = 0; i < req->noheaders; i++) { - if(!strcasecmp(req->headers[i][0], name)) - return(req->headers[i][1]); + for(i = 0; i < head->noheaders; i++) { + if(!strcasecmp(head->headers[i][0], name)) + return(head->headers[i][1]); } return(NULL); } -void reqpreheader(struct htreq *req, char *name, char *val) +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); +} + +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)); + memmove(head->headers + 1, head->headers, sizeof(*head->headers) * head->noheaders); + head->noheaders++; + head->headers[0] = smalloc(sizeof(*head->headers[0]) * 2); + head->headers[0][0] = sstrdup(name); + head->headers[0][1] = sstrdup(val); +} + +void headappheader(struct hthead *head, const char *name, const char *val) +{ + int i; + + i = head->noheaders++; + head->headers = srealloc(head->headers, sizeof(*head->headers) * head->noheaders); + head->headers[i] = smalloc(sizeof(*head->headers[i]) * 2); + head->headers[i][0] = sstrdup(name); + head->headers[i][1] = sstrdup(val); +} + +void headrmheader(struct hthead *head, const char *name) { - req->headers = srealloc(req->headers, sizeof(*req->headers) * (req->noheaders + 1)); - memmove(req->headers + 1, req->headers, sizeof(*req->headers) * req->noheaders); - req->noheaders++; - req->headers[0] = smalloc(sizeof(*req->headers[0]) * 2); - req->headers[0][0] = sstrdup(name); - req->headers[0][1] = sstrdup(val); + 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; + } + } } -void reqappheader(struct htreq *req, char *name, char *val) +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 sendreq(int sock, struct hthead *req, int fd) +{ + int ret, i; + struct charbuf buf; + + bufinit(buf); + bufcatstr2(buf, req->method); + bufcatstr2(buf, req->url); + bufcatstr2(buf, req->ver); + bufcatstr2(buf, req->rest); + for(i = 0; i < req->noheaders; i++) { + bufcatstr2(buf, req->headers[i][0]); + bufcatstr2(buf, req->headers[i][1]); + } + bufcatstr2(buf, ""); + ret = sendfd(sock, fd, buf.b, buf.d); + buffree(buf); + if(ret < 0) + return(-1); + else + return(0); +} + +int recvreq(int sock, struct hthead **reqp) +{ + int fd; + struct charbuf buf; + char *p; + size_t l; + char *name, *val; + struct hthead *req; + + 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; + + *reqp = omalloc(req); + if((req->method = sstrdup(decstr(&p, &l))) == NULL) + goto fail; + if((req->url = sstrdup(decstr(&p, &l))) == NULL) + goto fail; + if((req->ver = sstrdup(decstr(&p, &l))) == NULL) + goto fail; + if((req->rest = sstrdup(decstr(&p, &l))) == NULL) + goto fail; + + while(1) { + if(!*(name = decstr(&p, &l))) + break; + val = decstr(&p, &l); + headappheader(req, name, val); + } + + buffree(buf); + return(fd); + +fail: + close(fd); + freehthead(req); + errno = EPROTO; + return(-1); +} - i = req->noheaders++; - req->headers = srealloc(req->headers, sizeof(*req->headers) * req->noheaders); - req->headers[i] = smalloc(sizeof(*req->headers[i]) * 2); - req->headers[i][0] = sstrdup(name); - req->headers[i][1] = sstrdup(val); +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); }