Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/libexec/httpd/bozohttpd.c,v rcsdiff: /ftp/cvs/cvsroot/src/libexec/httpd/bozohttpd.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.28.2.3 retrieving revision 1.29 diff -u -p -r1.28.2.3 -r1.29 --- src/libexec/httpd/bozohttpd.c 2014/05/22 11:37:13 1.28.2.3 +++ src/libexec/httpd/bozohttpd.c 2011/11/17 22:09:12 1.29 @@ -1,9 +1,9 @@ -/* $NetBSD: bozohttpd.c,v 1.28.2.3 2014/05/22 11:37:13 yamt Exp $ */ +/* $NetBSD: bozohttpd.c,v 1.29 2011/11/17 22:09:12 mrg Exp $ */ -/* $eterna: bozohttpd.c,v 1.178 2011/11/18 09:21:15 mrg Exp $ */ +/* $eterna: bozohttpd.c,v 1.176 2010/09/20 22:26:28 mrg Exp $ */ /* - * Copyright (c) 1997-2014 Matthew R. Green + * Copyright (c) 1997-2010 Matthew R. Green * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -55,17 +55,17 @@ /* * requirements for minimal http/1.1 (at least, as documented in - * RFC 2616 (HTTP/1.1): + * which expired may 18, 1999): * - * - 14.11: content-encoding handling. [1] + * - 14.15: content-encoding handling. [1] * - * - 14.13: content-length handling. this is only a SHOULD header + * - 14.16: content-length handling. this is only a SHOULD header * thus we could just not send it ever. [1] * * - 14.17: content-type handling. [1] * - * - 14.28: if-unmodified-since handling. if-modified-since is - * done since, shouldn't be too hard for this one. + * - 14.25/28: if-{,un}modified-since handling. maybe do this, but + * i really don't want to have to parse 3 differnet date formats * * [1] need to revisit to ensure proper behaviour * @@ -88,28 +88,28 @@ * * - 10.3.3/10.3.4/10.3.8: just use '302' codes always. * - * - 14.1/14.2/14.3/14.27: we do not support Accept: headers. + * - 14.1/14.2/14.3/14.27: we do not support Accept: headers.. * just ignore them and send the request anyway. they are * only SHOULD. * - * - 14.5/14.16/14.35: only support simple ranges: %d- and %d-%d - * would be nice to support more. + * - 14.5/14.16/14.35: we don't do ranges. from section 14.35.2 + * `A server MAY ignore the Range header'. but it might be nice. + * since 20080301 we support simple range headers. * * - 14.9: we aren't a cache. * - * - 14.15: content-md5 would be nice. + * - 14.15: content-md5 would be nice... + * + * - 14.24/14.26/14.27: be nice to support this... * - * - 14.24/14.26/14.27: if-match, if-none-match, if-range. be - * nice to support this. - * - * - 14.44: Vary: seems unneeded. ignore it for now. + * - 14.44: not sure about this Vary: header. ignore it for now. */ #ifndef INDEX_HTML #define INDEX_HTML "index.html" #endif #ifndef SERVER_SOFTWARE -#define SERVER_SOFTWARE "bozohttpd/20140201" +#define SERVER_SOFTWARE "bozohttpd/20100920" #endif #ifndef DIRECT_ACCESS_FILE #define DIRECT_ACCESS_FILE ".bzdirect" @@ -337,21 +337,21 @@ bozo_clean_request(bozo_httpreq_t *reque MF(hr_remotehost); MF(hr_remoteaddr); MF(hr_serverport); - MF(hr_virthostname); MF(hr_file); MF(hr_oldfile); MF(hr_query); - MF(hr_host); #undef MF bozo_auth_cleanup(request); for (hdr = SIMPLEQ_FIRST(&request->hr_headers); hdr; hdr = SIMPLEQ_NEXT(hdr, h_next)) { free(hdr->h_value); free(hdr->h_header); - free(ohdr); + if (ohdr) + free(ohdr); ohdr = hdr; } - free(ohdr); + if (ohdr) + free(ohdr); free(request); } @@ -539,7 +539,6 @@ bozo_read_request(bozohttpd_t *httpd) request->hr_range = NULL; request->hr_last_byte_pos = -1; request->hr_if_modified_since = NULL; - request->hr_virthostname = NULL; request->hr_file = NULL; request->hr_oldfile = NULL; @@ -682,8 +681,8 @@ bozo_read_request(bozohttpd_t *httpd) else if (strcasecmp(hdr->h_header, "content-length") == 0) request->hr_content_length = hdr->h_value; else if (strcasecmp(hdr->h_header, "host") == 0) - request->hr_host = bozostrdup(httpd, hdr->h_value); - /* RFC 2616 (HTTP/1.1): 14.20 */ + request->hr_host = hdr->h_value; + /* HTTP/1.1 rev06 draft spec: 14.20 */ else if (strcasecmp(hdr->h_header, "expect") == 0) { (void)bozo_http_error(httpd, 417, request, "we don't support Expect:"); @@ -697,9 +696,6 @@ bozo_read_request(bozohttpd_t *httpd) else if (strcasecmp(hdr->h_header, "if-modified-since") == 0) request->hr_if_modified_since = hdr->h_value; - else if (strcasecmp(hdr->h_header, - "accept-encoding") == 0) - request->hr_accept_encoding = hdr->h_value; debug((httpd, DEBUG_FAT, "adding header %s: %s", hdr->h_header, hdr->h_value)); @@ -720,9 +716,8 @@ next_header: goto cleanup; } - /* RFC 2616 (HTTP/1.1), 14.23 & 19.6.1.1 */ + /* HTTP/1.1 draft rev-06, 14.23 & 19.6.1.1 */ if (request->hr_proto == httpd->consts.http_11 && - /*(strncasecmp(request->hr_file, "http://", 7) != 0) &&*/ request->hr_host == NULL) { (void)bozo_http_error(httpd, 400, request, "missing Host header"); @@ -849,70 +844,6 @@ parse_http_date(const char *val, time_t } /* - * given an url, encode it ala rfc 3986. ie, escape ? and friends. - * note that this function returns a static buffer, and thus needs - * to be updated for any sort of parallel processing. - */ -char * -bozo_escape_rfc3986(bozohttpd_t *httpd, const char *url) -{ - static char *buf; - static size_t buflen = 0; - size_t len; - const char *s; - char *d; - - len = strlen(url); - if (buflen < len * 3 + 1) { - buflen = len * 3 + 1; - buf = bozorealloc(httpd, buf, buflen); - } - - if (url == NULL) { - buf[0] = 0; - return buf; - } - - for (len = 0, s = url, d = buf; *s;) { - if (*s & 0x80) - goto encode_it; - switch (*s) { - case ':': - case '/': - case '?': - case '#': - case '[': - case ']': - case '@': - case '!': - case '$': - case '&': - case '\'': - case '(': - case ')': - case '*': - case '+': - case ',': - case ';': - case '=': - case '%': - encode_it: - snprintf(d, 4, "%%%2X", *s++); - d += 3; - len += 3; - break; - default: - *d++ = *s++; - len++; - break; - } - } - buf[len] = 0; - - return buf; -} - -/* * checks to see if this request has a valid .bzdirect file. returns * 0 on failure and 1 on success. */ @@ -924,7 +855,7 @@ check_direct_access(bozo_httpreq_t *requ char dir[MAXPATHLEN], dirfile[MAXPATHLEN], *basename; snprintf(dir, sizeof(dir), "%s", request->hr_file + 1); - debug((request->hr_httpd, DEBUG_FAT, "check_direct_access: dir %s", dir)); + debug((request->hr_httpd, DEBUG_FAT, "check_bzredirect: dir %s", dir)); basename = strrchr(dir, '/'); if ((!basename || basename[1] != '\0') && @@ -956,41 +887,37 @@ handle_redirect(bozo_httpreq_t *request, bozohttpd_t *httpd = request->hr_httpd; char *urlbuf; char portbuf[20]; - const char *hostname = BOZOHOST(httpd, request); int query = 0; - + if (url == NULL) { if (asprintf(&urlbuf, "/%s/", request->hr_file) < 0) bozo_err(httpd, 1, "asprintf"); url = urlbuf; } else urlbuf = NULL; - url = bozo_escape_rfc3986(request->hr_httpd, url); - if (request->hr_query && strlen(request->hr_query)) + if (request->hr_query && strlen(request->hr_query)) { query = 1; + } if (request->hr_serverport && strcmp(request->hr_serverport, "80") != 0) snprintf(portbuf, sizeof(portbuf), ":%s", request->hr_serverport); else portbuf[0] = '\0'; - if (absolute) - bozo_warn(httpd, "redirecting %s", url); - else - bozo_warn(httpd, "redirecting %s%s%s", hostname, portbuf, url); + bozo_warn(httpd, "redirecting %s%s%s", httpd->virthostname, portbuf, url); debug((httpd, DEBUG_FAT, "redirecting %s", url)); bozo_printf(httpd, "%s 301 Document Moved\r\n", request->hr_proto); - if (request->hr_proto != httpd->consts.http_09) + if (request->hr_proto != httpd->consts.http_09) bozo_print_header(request, NULL, "text/html", NULL); if (request->hr_proto != httpd->consts.http_09) { bozo_printf(httpd, "Location: http://"); if (absolute == 0) - bozo_printf(httpd, "%s%s", hostname, portbuf); + bozo_printf(httpd, "%s%s", httpd->virthostname, portbuf); if (query) { - bozo_printf(httpd, "%s?%s\r\n", url, request->hr_query); + bozo_printf(httpd, "%s?%s\r\n", url, request->hr_query); } else { - bozo_printf(httpd, "%s\r\n", url); + bozo_printf(httpd, "%s\r\n", url); } } bozo_printf(httpd, "\r\n"); @@ -1000,23 +927,23 @@ handle_redirect(bozo_httpreq_t *request, bozo_printf(httpd, "

Document Moved

\n"); bozo_printf(httpd, "This document had moved hr_query); - else - bozo_printf(httpd, "%s%s%s?%s", hostname, - portbuf, url, request->hr_query); - } else { - if (absolute) - bozo_printf(httpd, "%s", url); - else - bozo_printf(httpd, "%s%s%s", hostname, - portbuf, url); + if (absolute) + bozo_printf(httpd, "%s?%s", url, request->hr_query); + else + bozo_printf(httpd, "%s%s%s?%s", httpd->virthostname, portbuf, url, + request->hr_query); + } else { + if (absolute) + bozo_printf(httpd, "%s", url); + else + bozo_printf(httpd, "%s%s%s", httpd->virthostname, portbuf, url); } bozo_printf(httpd, "\">here\n"); bozo_printf(httpd, "\n"); head: bozo_flush(httpd, stdout); - free(urlbuf); + if (urlbuf) + free(urlbuf); } /* @@ -1044,13 +971,9 @@ check_virtual(bozo_httpreq_t *request) if (strncasecmp(file, "http://", 7) == 0) { /* we would do virtual hosting here? */ file += 7; - /* RFC 2616 (HTTP/1.1), 5.2: URI takes precedence over Host: */ - free(request->hr_host); - request->hr_host = bozostrdup(request->hr_httpd, file); - if ((s = strchr(request->hr_host, '/')) != NULL) - *s = '\0'; s = strchr(file, '/'); - free(request->hr_file); + /* HTTP/1.1 draft rev-06, 5.2: URI takes precedence over Host: */ + request->hr_host = file; request->hr_file = bozostrdup(request->hr_httpd, s ? s : "/"); debug((httpd, DEBUG_OBESE, "got host ``%s'' file is now ``%s''", request->hr_host, request->hr_file)); @@ -1058,20 +981,12 @@ check_virtual(bozo_httpreq_t *request) goto use_slashdir; /* - * canonicalise hr_host - that is, remove any :80. - */ - len = strlen(request->hr_host); - if (len > 3 && strcmp(request->hr_host + len - 3, ":80") == 0) { - request->hr_host[len - 3] = '\0'; - len = strlen(request->hr_host); - } - - /* - * ok, we have a virtual host, use opendir(3) to find a case + * ok, we have a virtual host, use scandir(3) to find a case * insensitive match for the virtual host we are asked for. * note that if the virtual host is the same as the master, * we don't need to do anything special. */ + len = strlen(request->hr_host); debug((httpd, DEBUG_OBESE, "check_virtual: checking host `%s' under httpd->virtbase `%s' " "for file `%s'", @@ -1093,10 +1008,9 @@ check_virtual(bozo_httpreq_t *request) len) == 0) { /* found it, punch it */ debug((httpd, DEBUG_OBESE, "found it punch it")); - request->hr_virthostname = - bozostrdup(httpd, d->d_name); + httpd->virthostname = d->d_name; if (asprintf(&s, "%s/%s", httpd->virtbase, - request->hr_virthostname) < 0) + httpd->virthostname) < 0) bozo_err(httpd, 1, "asprintf"); break; } @@ -1128,15 +1042,13 @@ use_slashdir: /* * checks to see if this request has a valid .bzredirect file. returns - * 0 when no redirection happend, or 1 when handle_redirect() has been - * called. + * 0 on failure and 1 on success. */ -static int +static void check_bzredirect(bozo_httpreq_t *request) { struct stat sb; - char dir[MAXPATHLEN], redir[MAXPATHLEN], redirpath[MAXPATHLEN + 1], - path[MAXPATHLEN]; + char dir[MAXPATHLEN], redir[MAXPATHLEN], redirpath[MAXPATHLEN + 1]; char *basename, *finalredir; int rv, absolute; @@ -1161,12 +1073,12 @@ check_bzredirect(bozo_httpreq_t *request snprintf(redir, sizeof(redir), "%s/%s", dir, REDIRECT_FILE); if (lstat(redir, &sb) == 0) { if (!S_ISLNK(sb.st_mode)) - return 0; + return; absolute = 0; } else { snprintf(redir, sizeof(redir), "%s/%s", dir, ABSREDIRECT_FILE); if (lstat(redir, &sb) < 0 || !S_ISLNK(sb.st_mode)) - return 0; + return; absolute = 1; } debug((request->hr_httpd, DEBUG_FAT, @@ -1174,17 +1086,12 @@ check_bzredirect(bozo_httpreq_t *request rv = readlink(redir, redirpath, sizeof redirpath - 1); if (rv == -1 || rv == 0) { debug((request->hr_httpd, DEBUG_FAT, "readlink failed")); - return 0; + return; } redirpath[rv] = '\0'; debug((request->hr_httpd, DEBUG_FAT, "readlink returned \"%s\"", redirpath)); - - /* check if we need authentication */ - snprintf(path, sizeof(path), "%s/", dir); - if (bozo_auth_check(request, path)) - return 1; - + /* now we have the link pointer, redirect to the real place */ if (absolute) finalredir = redirpath; @@ -1195,7 +1102,6 @@ check_bzredirect(bozo_httpreq_t *request debug((request->hr_httpd, DEBUG_FAT, "check_bzredirect: new redir %s", finalredir)); handle_redirect(request, finalredir, absolute); - return 1; } /* this fixes the %HH hack that RFC2396 requires. */ @@ -1241,7 +1147,7 @@ fix_url_percent(bozo_httpreq_t *request) "percent hack was %2f (/)"); goto copy_rest; } - + buf[0] = *++s; buf[1] = *++s; buf[2] = '\0'; @@ -1278,7 +1184,7 @@ copy_rest: * - punt if it doesn't start with / * - check httpd->untrustedref / referrer * - look for "http://myname/" and deal with it. - * - maybe call bozo_process_cgi() + * - maybe call bozo_process_cgi() * - check for ~user and call bozo_user_transform() if so * - if the length > 1, check for trailing slash. if so, * add the index.html file @@ -1294,7 +1200,6 @@ transform_request(bozo_httpreq_t *reques bozohttpd_t *httpd = request->hr_httpd; char *file, *newfile = NULL; size_t len; - const char *hostname = BOZOHOST(httpd, request); file = NULL; *isindex = 0; @@ -1310,16 +1215,15 @@ transform_request(bozo_httpreq_t *reques goto bad_done; } - if (check_bzredirect(request)) - return 0; + check_bzredirect(request); if (httpd->untrustedref) { int to_indexhtml = 0; #define TOP_PAGE(x) (strcmp((x), "/") == 0 || \ strcmp((x) + 1, httpd->index_html) == 0 || \ - strcmp((x) + 1, "favicon.ico") == 0) - + strcmp((x) + 1, "favicon.ico") == 0) + debug((httpd, DEBUG_EXPLODING, "checking httpd->untrustedref")); /* * first check that this path isn't allowed via .bzdirect file, @@ -1334,10 +1238,10 @@ transform_request(bozo_httpreq_t *reques debug((httpd, DEBUG_FAT, "checking referrer \"%s\" vs virthostname %s", - r, hostname)); + r, httpd->virthostname)); if (strncmp(r, "http://", 7) != 0 || - (strncasecmp(r + 7, hostname, - strlen(hostname)) != 0 && + (strncasecmp(r + 7, httpd->virthostname, + strlen(httpd->virthostname)) != 0 && !TOP_PAGE(file))) to_indexhtml = 1; } else { @@ -1346,8 +1250,8 @@ transform_request(bozo_httpreq_t *reques debug((httpd, DEBUG_FAT, "url has no referrer at all")); /* if there's no referrer, let / or /index.html past */ if (!TOP_PAGE(file) || - (h && strncasecmp(h, hostname, - strlen(hostname)) != 0)) + (h && strncasecmp(h, httpd->virthostname, + strlen(httpd->virthostname)) != 0)) to_indexhtml = 1; } @@ -1414,7 +1318,7 @@ transform_request(bozo_httpreq_t *reques */ /* - * stop traversing outside our domain + * stop traversing outside our domain * * XXX true security only comes from our parent using chroot(2) * before execve(2)'ing us. or our own built in chroot(2) support. @@ -1436,61 +1340,12 @@ transform_request(bozo_httpreq_t *reques if (bozo_process_cgi(request)) return 0; - if (bozo_process_lua(request)) - return 0; - debug((httpd, DEBUG_FAT, "transform_request set: %s", newfile)); return 1; bad_done: debug((httpd, DEBUG_FAT, "transform_request returning: 0")); - free(newfile); - return 0; -} - -/* - * can_gzip checks if the request supports and prefers gzip encoding. - * - * XXX: we do not consider the associated q with gzip in making our - * decision which is broken. - */ - -static int -can_gzip(bozo_httpreq_t *request) -{ - const char *pos; - const char *tmp; - size_t len; - - /* First we decide if the request can be gzipped at all. */ - - /* not if we already are encoded... */ - tmp = bozo_content_encoding(request, request->hr_file); - if (tmp && *tmp) - return 0; - - /* not if we are not asking for the whole file... */ - if (request->hr_last_byte_pos != -1 || request->hr_have_range) - return 0; - - /* Then we determine if gzip is on the cards. */ - - for (pos = request->hr_accept_encoding; pos && *pos; pos += len) { - while (*pos == ' ') - pos++; - - len = strcspn(pos, ";,"); - - if ((len == 4 && strncasecmp("gzip", pos, 4) == 0) || - (len == 6 && strncasecmp("x-gzip", pos, 6) == 0)) - return 1; - - if (pos[len] == ';') - len += strcspn(&pos[len], ","); - - if (pos[len]) - len++; - } - + if (newfile) + free(newfile); return 0; } @@ -1519,28 +1374,16 @@ bozo_process_request(bozo_httpreq_t *req if (transform_request(request, &isindex) == 0) return; - fd = -1; - encoding = NULL; - if (can_gzip(request)) { - asprintf(&file, "%s.gz", request->hr_file); - fd = open(file, O_RDONLY); - if (fd >= 0) - encoding = "gzip"; - free(file); - } - file = request->hr_file; - if (fd < 0) - fd = open(file, O_RDONLY); - + fd = open(file, O_RDONLY); if (fd < 0) { debug((httpd, DEBUG_FAT, "open failed: %s", strerror(errno))); if (errno == EPERM) (void)bozo_http_error(httpd, 403, request, "no permission to open file"); else if (errno == ENOENT) { - if (!bozo_dir_index(request, file, isindex)) + if (!bozo_dir_index(request, file, isindex)) (void)bozo_http_error(httpd, 404, request, "no file"); } else @@ -1589,8 +1432,7 @@ bozo_process_request(bozo_httpreq_t *req if (request->hr_proto != httpd->consts.http_09) { type = bozo_content_type(request, file); - if (!encoding) - encoding = bozo_content_encoding(request, file); + encoding = bozo_content_encoding(request, file); bozo_print_header(request, &sb, type, encoding); bozo_printf(httpd, "\r\n"); @@ -1703,7 +1545,7 @@ debug__(bozohttpd_t *httpd, int level, c { va_list ap; int savederrno; - + /* only log if the level is low enough */ if (httpd->debug < level) return; @@ -1752,20 +1594,12 @@ bozo_err(bozohttpd_t *httpd, int code, c exit(code); } -/* - * this escapes HTML tags. returns allocated escaped - * string if needed, or NULL on allocation failure or - * lack of escape need. - * call with NULL httpd in error paths, to avoid recursive - * malloc failure. call with valid httpd in normal paths - * to get automatic allocation failure handling. - */ -char * -bozo_escape_html(bozohttpd_t *httpd, const char *url) +/* this escape HTML tags */ +static void +escape_html(bozo_httpreq_t *request) { int i, j; - char *tmp; - size_t len; + char *url = request->hr_file, *tmp; for (i = 0, j = 0; url[i]; i++) { switch (url[i]) { @@ -1780,17 +1614,16 @@ bozo_escape_html(bozohttpd_t *httpd, con } if (j == 0) - return NULL; + return; - /* - * we need to handle being called from different - * pathnames. - */ - len = strlen(url) + j; - if (httpd) - tmp = bozomalloc(httpd, len); - else if ((tmp = malloc(len)) == 0) - return NULL; + if ((tmp = (char *) malloc(strlen(url) + j)) == 0) + /* + * ouch, but we are only called from an error context, and + * most paths here come from malloc(3) failures anyway... + * we could completely punt and just exit, but isn't returning + * an not-quite-correct error better than nothing at all? + */ + return; for (i = 0, j = 0; url[i]; i++) { switch (url[i]) { @@ -1812,7 +1645,8 @@ bozo_escape_html(bozohttpd_t *httpd, con } tmp[j] = 0; - return tmp; + free(request->hr_file); + request->hr_file = tmp; } /* short map between error code, and short/long messages */ @@ -1885,21 +1719,15 @@ bozo_http_error(bozohttpd_t *httpd, int portbuf[0] = '\0'; if (request && request->hr_file) { - char *file = NULL; - const char *hostname = BOZOHOST(httpd, request); - - /* bozo_escape_html() failure here is just too bad. */ - file = bozo_escape_html(NULL, request->hr_file); - if (file == NULL) - file = request->hr_file; + escape_html(request); size = snprintf(httpd->errorbuf, BUFSIZ, "%s\n" "

%s

\n" "%s:
%s
\n" "
%s%s
\n" "\n", - header, header, file, reason, - hostname, portbuf, hostname, portbuf); + header, header, request->hr_file, reason, + httpd->virthostname, portbuf, httpd->virthostname, portbuf); if (size >= (int)BUFSIZ) { bozo_warn(httpd, "bozo_http_error buffer too small, truncated"); @@ -2099,9 +1927,6 @@ bozo_init_httpd(bozohttpd_t *httpd) "bozohttpd: memory_allocation failure\n"); return 0; } -#ifndef NO_LUA_SUPPORT - SIMPLEQ_INIT(&httpd->lua_states); -#endif return 1; }