X-Git-Url: http://dolda2000.com/gitweb/?a=blobdiff_plain;f=lib%2Fresp.c;h=be2f7bd7c586f3046d6884c08c6276543ccf4d42;hb=b04429ebd08b1a5cbb05938e935e48ab7223a382;hp=da354f99e40f3dcb98d91863a406550d60bf0504;hpb=f812ea037b5c693977e83ace9ed7ac2515a4a6d0;p=ashd.git diff --git a/lib/resp.c b/lib/resp.c index da354f9..be2f7bd 100644 --- a/lib/resp.c +++ b/lib/resp.c @@ -17,6 +17,7 @@ */ #include +#include #include #include #include @@ -29,10 +30,45 @@ #include #include +static char safechars[128] = { + /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, +}; + +char *urlquote(char *text) +{ + static char *ret = NULL; + struct charbuf buf; + unsigned char c; + + if(ret != NULL) + free(ret); + bufinit(buf); + for(; *text; text++) { + c = *text; + if((c < 128) && safechars[(int)c]) + bufadd(buf, *text); + else + bprintf(&buf, "%%%02X", (int)c); + } + bufadd(buf, 0); + return(ret = buf.b); +} + char *htmlquote(char *text) { + static char *ret = NULL; struct charbuf buf; + if(ret != NULL) + free(ret); bufinit(buf); for(; *text; text++) { if(*text == '<') @@ -41,25 +77,21 @@ char *htmlquote(char *text) bufcatstr(buf, ">"); else if(*text == '&') bufcatstr(buf, "&"); + else if(*text == '\"') + bufcatstr(buf, """); else bufadd(buf, *text); } bufadd(buf, 0); - return(buf.b); + return(ret = buf.b); } -void simpleerror(int fd, int code, char *msg, char *fmt, ...) +static void simpleerror2v(FILE *out, int code, char *msg, char *fmt, va_list args) { struct charbuf buf; - char *tmp1, *tmp2; - va_list args; - FILE *out; + char *tmp; - va_start(args, fmt); - tmp1 = vsprintf2(fmt, args); - va_end(args); - tmp2 = htmlquote(tmp1); - free(tmp1); + tmp = vsprintf2(fmt, args); bufinit(buf); bufcatstr(buf, "\r\n"); bufcatstr(buf, "\r\n"); @@ -69,18 +101,81 @@ void simpleerror(int fd, int code, char *msg, char *fmt, ...) bufcatstr(buf, "\r\n"); bufcatstr(buf, "\r\n"); bprintf(&buf, "

%s

\r\n", msg); - bprintf(&buf, "

%s

\r\n", tmp2); + bprintf(&buf, "

%s

\r\n", htmlquote(tmp)); bufcatstr(buf, "\r\n"); bufcatstr(buf, "\r\n"); - free(tmp2); - out = fdopen(fd, "w"); - fprintf(out, "HTTP/1.1 %i %s\r\n", code, msg); - fprintf(out, "Content-Type: text/html\r\n"); - fprintf(out, "Content-Length: %zi\r\n", buf.d); - fprintf(out, "\r\n"); + fprintf(out, "HTTP/1.1 %i %s\n", code, msg); + fprintf(out, "Content-Type: text/html\n"); + fprintf(out, "Content-Length: %zi\n", buf.d); + fprintf(out, "\n"); fwrite(buf.b, 1, buf.d, out); - fclose(out); buffree(buf); + free(tmp); +} + +void simpleerror2(FILE *out, int code, char *msg, char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + simpleerror2v(out, code, msg, fmt, args); + va_end(args); +} + +void simpleerror(int fd, int code, char *msg, char *fmt, ...) +{ + va_list args; + FILE *out; + + va_start(args, fmt); + out = fdopen(dup(fd), "w"); + simpleerror2v(out, code, msg, fmt, args); + fclose(out); + va_end(args); +} + +void stdredir(struct hthead *req, int fd, int code, char *dst) +{ + FILE *out; + char *sp, *cp, *ep, *qs, *path, *url, *adst, *proto, *host; + + sp = strchr(dst, '/'); + cp = strchr(dst, ':'); + if(cp && (!sp || (cp < sp))) { + adst = sstrdup(dst); + } else { + proto = getheader(req, "X-Ash-Protocol"); + host = getheader(req, "Host"); + if((proto == NULL) || (host == NULL)) { + /* Not compliant, but there isn't a whole lot to be done + * about it. */ + adst = sstrdup(dst); + } else { + if(*dst == '/') { + path = sstrdup(dst + 1); + } else { + if((*(url = req->url)) == '/') + url++; + if((ep = strchr(url, '?')) == NULL) { + ep = url + strlen(url); + qs = ""; + } else { + qs = ep; + } + for(; (ep > url) && (ep[-1] != '/'); ep--); + path = sprintf2("%.*s%s%s", ep - url, url, dst, qs); + } + adst = sprintf2("%s://%s/%s", proto, host, path); + free(path); + } + } + out = fdopen(dup(fd), "w"); + fprintf(out, "HTTP/1.1 %i Redirection\n", code); + fprintf(out, "Content-Length: 0\n"); + fprintf(out, "Location: %s\n", adst); + fprintf(out, "\n"); + fclose(out); + free(adst); } char *fmthttpdate(time_t time) @@ -95,6 +190,22 @@ char *fmthttpdate(time_t time) return(sprintf3("%s, %i %s %i %02i:%02i:%02i GMT", days[(tm->tm_wday + 6) % 7], tm->tm_mday, months[tm->tm_mon], tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec)); } +static int gtoi(char *bstr, regmatch_t g) +{ + int i, n; + + for(i = g.rm_so, n = 0; i < g.rm_eo; i++) + n = (n * 10) + (bstr[i] - '0'); + return(n); +} + +static int gstrcmp(char *bstr, regmatch_t g, char *str) +{ + if(g.rm_eo - g.rm_so != strlen(str)) + return(1); + return(strncasecmp(bstr + g.rm_so, str, g.rm_eo - g.rm_so)); +} + time_t parsehttpdate(char *date) { static regex_t *spec = NULL; @@ -105,21 +216,6 @@ time_t parsehttpdate(char *date) struct tm tm; int tz; - int gtoi(regmatch_t g) - { - int i, n; - - for(i = g.rm_so, n = 0; i < g.rm_eo; i++) - n = (n * 10) + (date[i] - '0'); - return(n); - } - - int gstrcmp(regmatch_t g, char *str) { - if(g.rm_eo - g.rm_so != strlen(str)) - return(1); - return(strncasecmp(date + g.rm_so, str, g.rm_eo - g.rm_so)); - } - if(spec == NULL) { omalloc(spec); if(regcomp(spec, "^[A-Z]{3}, +([0-9]+) +([A-Z]{3}) +([0-9]+) +([0-9]{2}):([0-9]{2}):([0-9]{2}) +(([A-Z]+)|[+-]([0-9]{2})([0-9]{2}))$", REG_EXTENDED | REG_ICASE)) { @@ -130,15 +226,15 @@ time_t parsehttpdate(char *date) } if(regexec(spec, date, 11, g, 0)) return(0); - tm.tm_mday = gtoi(g[1]); - tm.tm_year = gtoi(g[3]) - 1900; - tm.tm_hour = gtoi(g[4]); - tm.tm_min = gtoi(g[5]); - tm.tm_sec = gtoi(g[6]); + tm.tm_mday = gtoi(date, g[1]); + tm.tm_year = gtoi(date, g[3]) - 1900; + tm.tm_hour = gtoi(date, g[4]); + tm.tm_min = gtoi(date, g[5]); + tm.tm_sec = gtoi(date, g[6]); tm.tm_mon = -1; for(i = 0; i < 12; i++) { - if(!gstrcmp(g[2], months[i])) { + if(!gstrcmp(date, g[2], months[i])) { tm.tm_mon = i; break; } @@ -147,12 +243,12 @@ time_t parsehttpdate(char *date) return(0); if(g[8].rm_so > 0) { - if(!gstrcmp(g[8], "GMT")) + if(!gstrcmp(date, g[8], "GMT")) tz = 0; else return(0); } else if((g[9].rm_so > 0) && (g[10].rm_so > 0)) { - tz = gtoi(g[9]) * 3600 + gtoi(g[10]) * 60; + tz = gtoi(date, g[9]) * 3600 + gtoi(date, g[10]) * 60; if(date[g[7].rm_so] == '-') tz = -tz; } else { @@ -161,3 +257,45 @@ time_t parsehttpdate(char *date) return(timegm(&tm) - tz); } + +char *httpdefstatus(int code) +{ + switch(code) { + case 200: + return("OK"); + case 201: + return("Created"); + case 202: + return("Accepted"); + case 204: + return("No Content"); + case 300: + return("Multiple Choices"); + case 301: + return("Moved Permanently"); + case 302: + return("Found"); + case 303: + return("See Other"); + case 304: + return("Not Modified"); + case 307: + return("Moved Temporarily"); + case 400: + return("Bad Request"); + case 401: + return("Unauthorized"); + case 403: + return("Forbidden"); + case 404: + return("Not Found"); + case 500: + return("Internal Server Error"); + case 501: + return("Not Implemented"); + case 503: + return("Service Unavailable"); + default: + return("Unknown status"); + } +}