diff options
author | Denis Vlasenko | 2006-11-21 00:12:09 +0000 |
---|---|---|
committer | Denis Vlasenko | 2006-11-21 00:12:09 +0000 |
commit | 5d148e2646874a6f460402f2dd70ea2fb6be08dd (patch) | |
tree | fae60c2d7ca0d917f73f6a87554657c09a0ddb7b | |
parent | fcdb00f7359488d197ac3361dfbc49ccdead8b87 (diff) | |
download | busybox-5d148e2646874a6f460402f2dd70ea2fb6be08dd.zip busybox-5d148e2646874a6f460402f2dd70ea2fb6be08dd.tar.gz |
httpd: fix cgi-bin/index.cgi support, add example of it,
stat: fix end-of-line if format is specified (wasn't printing it),
fix %z (time) format to match coreutils 6.3
-rw-r--r-- | coreutils/stat.c | 68 | ||||
-rw-r--r-- | networking/httpd.c | 27 | ||||
-rw-r--r-- | networking/httpd_index_cgi_example | 55 |
3 files changed, 111 insertions, 39 deletions
diff --git a/coreutils/stat.c b/coreutils/stat.c index b9fd42f..31dd662 100644 --- a/coreutils/stat.c +++ b/coreutils/stat.c @@ -44,10 +44,16 @@ static char const *file_type(struct stat const *st) static char const *human_time(time_t t) { + /* Old static char *str; str = ctime(&t); str[strlen(str)-1] = '\0'; return str; + */ + /* coreutils 6.3 compat: */ + static char buf[sizeof("YYYY-MM-DD HH:MM:SS.000000000")]; + strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S.000000000", localtime(&t)); + return buf; } /* Return the type of the specified file system. @@ -311,41 +317,41 @@ static void print_it(char const *masterformat, char const *filename, /* create a working copy of the format string */ char *format = xstrdup(masterformat); - /* Add 2 to accommodate our conversion of the stat `%s' format string - * to the printf `%llu' one. */ + /* Add 2 to accomodate our conversion of the stat '%s' format string + * to the printf '%llu' one. */ size_t n_alloc = strlen(format) + 2 + 1; char *dest = xmalloc(n_alloc); b = format; while (b) { + size_t len; char *p = strchr(b, '%'); - if (p != NULL) { - size_t len; - *p++ = '\0'; - fputs(b, stdout); - - len = strspn(p, "#-+.I 0123456789"); - dest[0] = '%'; - memcpy(dest + 1, p, len); - dest[1 + len] = 0; - p += len; - - b = p + 1; - switch (*p) { - case '\0': - b = NULL; - /* fall through */ - case '%': - putchar('%'); - break; - default: - print_func(dest, n_alloc, *p, filename, data); - break; - } - - } else { - fputs(b, stdout); + if (!p) { + /* coreutils 6.3 always print <cr> at the end */ + /*fputs(b, stdout);*/ + puts(b); + break; + } + *p++ = '\0'; + fputs(b, stdout); + + len = strspn(p, "#-+.I 0123456789"); + dest[0] = '%'; + memcpy(dest + 1, p, len); + dest[1 + len] = 0; + p += len; + + b = p + 1; + switch (*p) { + case '\0': b = NULL; + /* fall through */ + case '%': + putchar('%'); + break; + default: + print_func(dest, n_alloc, *p, filename, data); + break; } } @@ -372,7 +378,7 @@ static int do_statfs(char const *filename, char const *format) " ID: %-8i Namelen: %-7l Type: %T\n" "Block size: %-10s\n" "Blocks: Total: %-10b Free: %-10f Available: %a\n" - "Inodes: Total: %-10c Free: %d\n"); + "Inodes: Total: %-10c Free: %d"); print_it(format, filename, print_statfs, &statfsbuf); #else @@ -420,7 +426,7 @@ static int do_stat(char const *filename, char const *format) #ifdef CONFIG_FEATURE_STAT_FORMAT if (format == NULL) { if (flags & OPT_TERSE) { - format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o\n"; + format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o"; } else { if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) { format = @@ -517,7 +523,7 @@ int stat_main(int argc, char **argv) int (*statfunc)(char const *, char const *) = do_stat; flags = getopt32(argc, argv, "ftL" - USE_FEATURE_STAT_FORMAT("c:", &format) + USE_FEATURE_STAT_FORMAT("c:", &format) ); if (flags & 1) /* -f */ diff --git a/networking/httpd.c b/networking/httpd.c index 47d41a1..08b40e0 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -1103,7 +1103,7 @@ static int sendCgi(const char *url, post_readed_size = 0; post_readed_idx = 0; - inFd = fromCgi[0]; + inFd = fromCgi[0]; outFd = toCgi[1]; close(fromCgi[1]); close(toCgi[0]); @@ -1190,6 +1190,10 @@ static int sendCgi(const char *url, if (strncmp(rbuf, "HTTP/1.0 200 OK\r\n", 4) != 0) { full_write(s, "HTTP/1.0 200 OK\r\n", 17); } + /* Sometimes CGI is writing to pipe in small chunks + * and we don't see Content-type (because the read + * is too short) and we emit bogus "text/plain"! + * Is it a bug or CGI *has to* write it in one piece? */ if (strstr(rbuf, "ontent-") == 0) { full_write(s, "Content-type: text/plain\r\n\r\n", 28); } @@ -1480,6 +1484,7 @@ static void handleIncoming(void) strcpy(url, buf); /* extract url args if present */ test = strchr(url, '?'); + config->query = NULL; if (test) { *test++ = '\0'; config->query = test; @@ -1640,20 +1645,26 @@ static void handleIncoming(void) sendHeaders(HTTP_NOT_IMPLEMENTED); break; } - if (purl[-1] == '/') { - if (access("cgi-bin/index.cgi", X_OK) == 0) { - config->query = url; - sendCgi("/cgi-bin/index.cgi", prequest, length, cookie, content_type); - break; - } - } #endif /* FEATURE_HTTPD_CGI */ if (purl[-1] == '/') strcpy(purl, "index.html"); if (stat(test, &sb) == 0) { + /* It's a dir URL and there is index.html */ config->ContentLength = sb.st_size; config->last_mod = sb.st_mtime; } +#if ENABLE_FEATURE_HTTPD_CGI + else if (purl[-1] == '/') { + /* It's a dir URL and there is no index.html + * Try cgi-bin/index.cgi */ + if (access("/cgi-bin/index.cgi"+1, X_OK) == 0) { + purl[0] = '\0'; + config->query = url; + sendCgi("/cgi-bin/index.cgi", prequest, length, cookie, content_type); + break; + } + } +#endif /* FEATURE_HTTPD_CGI */ sendFile(test); config->ContentLength = -1; } while (0); diff --git a/networking/httpd_index_cgi_example b/networking/httpd_index_cgi_example new file mode 100644 index 0000000..31e768c --- /dev/null +++ b/networking/httpd_index_cgi_example @@ -0,0 +1,55 @@ +#!/bin/sh +# This CGI creates directory index. +# Put it into cgi-bin/index.cgi and chmod 0755. +# +# Problems: +# * Unsafe wrt weird filenames with <>"'& etc... +# * Not efficient: calls stat (program, not syscall) for each file +# * Probably requires bash +# +# If you want speed and safety, you need to code it in C + +# Must start with '/' +test "${QUERY_STRING:0:1}" = "/" || exit 1 +# /../ is not allowed +test "${QUERY_STRING%/../*}" = "$QUERY_STRING" || exit 1 +test "${QUERY_STRING%/..}" = "$QUERY_STRING" || exit 1 + +# Outta cgi-bin... +cd .. 2>/dev/null || exit 1 +# Strip leading '/', go to target dir +cd "${QUERY_STRING:1}" 2>/dev/null || exit 1 + +f=`dirname "$QUERY_STRING"` +test "$f" = "/" && f="" + +# Pipe thru dd (need to write header as single write(), +# or else httpd doesn't see "Content-type: text/html" +# in first read() and decides that it is not html) +{ +printf "%s" \ +$'HTTP/1.0 200 OK\r\n'\ +$'Content-type: text/html\r\n\r\n'\ +"<html><head><title>Index of $QUERY_STRING</title></head>"$'\r\n'\ +"<body><h1>Index of $QUERY_STRING</h1><pre>"$'\r\n'\ +$'<table width=100%>\r\n'\ +$'<col><col><col width=0*>\r\n'\ +$'<tr><th>Name<th align=right>Last modified<th align=right>Size\r\n'\ +\ +"<tr><td><a href='$f/'>..</a><td><td>"$'\r\n' + +IFS='#' +for f in *; do + # Guard against empty dirs... + test -e "$f" && \ + stat -c "%F#%s#%z" "$f" | { + read type size cdt junk + dir='' + test "$type" = "directory" && dir='/' + cdt="${cdt//.*}" # no fractional seconds + cdt="${cdt// / }" # prevent wrapping around space + printf "%s" "<tr><td><a href='$f$dir'>$f</a><td align=right>$cdt<td align=right>$size"$'\r\n' + } +done +printf "</table></pre><hr></body></html>"$'\r\n' +} | dd bs=4k |