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
This commit is contained in:
parent
fcdb00f735
commit
5d148e2646
@ -44,10 +44,16 @@ static char const *file_type(struct stat const *st)
|
|||||||
|
|
||||||
static char const *human_time(time_t t)
|
static char const *human_time(time_t t)
|
||||||
{
|
{
|
||||||
|
/* Old
|
||||||
static char *str;
|
static char *str;
|
||||||
str = ctime(&t);
|
str = ctime(&t);
|
||||||
str[strlen(str)-1] = '\0';
|
str[strlen(str)-1] = '\0';
|
||||||
return str;
|
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.
|
/* 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 */
|
/* create a working copy of the format string */
|
||||||
char *format = xstrdup(masterformat);
|
char *format = xstrdup(masterformat);
|
||||||
|
|
||||||
/* Add 2 to accommodate our conversion of the stat `%s' format string
|
/* Add 2 to accomodate our conversion of the stat '%s' format string
|
||||||
* to the printf `%llu' one. */
|
* to the printf '%llu' one. */
|
||||||
size_t n_alloc = strlen(format) + 2 + 1;
|
size_t n_alloc = strlen(format) + 2 + 1;
|
||||||
char *dest = xmalloc(n_alloc);
|
char *dest = xmalloc(n_alloc);
|
||||||
|
|
||||||
b = format;
|
b = format;
|
||||||
while (b) {
|
while (b) {
|
||||||
|
size_t len;
|
||||||
char *p = strchr(b, '%');
|
char *p = strchr(b, '%');
|
||||||
if (p != NULL) {
|
if (!p) {
|
||||||
size_t len;
|
/* coreutils 6.3 always print <cr> at the end */
|
||||||
*p++ = '\0';
|
/*fputs(b, stdout);*/
|
||||||
fputs(b, stdout);
|
puts(b);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*p++ = '\0';
|
||||||
|
fputs(b, stdout);
|
||||||
|
|
||||||
len = strspn(p, "#-+.I 0123456789");
|
len = strspn(p, "#-+.I 0123456789");
|
||||||
dest[0] = '%';
|
dest[0] = '%';
|
||||||
memcpy(dest + 1, p, len);
|
memcpy(dest + 1, p, len);
|
||||||
dest[1 + len] = 0;
|
dest[1 + len] = 0;
|
||||||
p += len;
|
p += len;
|
||||||
|
|
||||||
b = p + 1;
|
b = p + 1;
|
||||||
switch (*p) {
|
switch (*p) {
|
||||||
case '\0':
|
case '\0':
|
||||||
b = NULL;
|
|
||||||
/* fall through */
|
|
||||||
case '%':
|
|
||||||
putchar('%');
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
print_func(dest, n_alloc, *p, filename, data);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
fputs(b, stdout);
|
|
||||||
b = NULL;
|
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"
|
" ID: %-8i Namelen: %-7l Type: %T\n"
|
||||||
"Block size: %-10s\n"
|
"Block size: %-10s\n"
|
||||||
"Blocks: Total: %-10b Free: %-10f Available: %a\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);
|
print_it(format, filename, print_statfs, &statfsbuf);
|
||||||
#else
|
#else
|
||||||
|
|
||||||
@ -420,7 +426,7 @@ static int do_stat(char const *filename, char const *format)
|
|||||||
#ifdef CONFIG_FEATURE_STAT_FORMAT
|
#ifdef CONFIG_FEATURE_STAT_FORMAT
|
||||||
if (format == NULL) {
|
if (format == NULL) {
|
||||||
if (flags & OPT_TERSE) {
|
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 {
|
} else {
|
||||||
if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) {
|
if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) {
|
||||||
format =
|
format =
|
||||||
@ -517,7 +523,7 @@ int stat_main(int argc, char **argv)
|
|||||||
int (*statfunc)(char const *, char const *) = do_stat;
|
int (*statfunc)(char const *, char const *) = do_stat;
|
||||||
|
|
||||||
flags = getopt32(argc, argv, "ftL"
|
flags = getopt32(argc, argv, "ftL"
|
||||||
USE_FEATURE_STAT_FORMAT("c:", &format)
|
USE_FEATURE_STAT_FORMAT("c:", &format)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (flags & 1) /* -f */
|
if (flags & 1) /* -f */
|
||||||
|
@ -1103,7 +1103,7 @@ static int sendCgi(const char *url,
|
|||||||
|
|
||||||
post_readed_size = 0;
|
post_readed_size = 0;
|
||||||
post_readed_idx = 0;
|
post_readed_idx = 0;
|
||||||
inFd = fromCgi[0];
|
inFd = fromCgi[0];
|
||||||
outFd = toCgi[1];
|
outFd = toCgi[1];
|
||||||
close(fromCgi[1]);
|
close(fromCgi[1]);
|
||||||
close(toCgi[0]);
|
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) {
|
if (strncmp(rbuf, "HTTP/1.0 200 OK\r\n", 4) != 0) {
|
||||||
full_write(s, "HTTP/1.0 200 OK\r\n", 17);
|
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) {
|
if (strstr(rbuf, "ontent-") == 0) {
|
||||||
full_write(s, "Content-type: text/plain\r\n\r\n", 28);
|
full_write(s, "Content-type: text/plain\r\n\r\n", 28);
|
||||||
}
|
}
|
||||||
@ -1480,6 +1484,7 @@ static void handleIncoming(void)
|
|||||||
strcpy(url, buf);
|
strcpy(url, buf);
|
||||||
/* extract url args if present */
|
/* extract url args if present */
|
||||||
test = strchr(url, '?');
|
test = strchr(url, '?');
|
||||||
|
config->query = NULL;
|
||||||
if (test) {
|
if (test) {
|
||||||
*test++ = '\0';
|
*test++ = '\0';
|
||||||
config->query = test;
|
config->query = test;
|
||||||
@ -1640,20 +1645,26 @@ static void handleIncoming(void)
|
|||||||
sendHeaders(HTTP_NOT_IMPLEMENTED);
|
sendHeaders(HTTP_NOT_IMPLEMENTED);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (purl[-1] == '/') {
|
#endif /* FEATURE_HTTPD_CGI */
|
||||||
if (access("cgi-bin/index.cgi", X_OK) == 0) {
|
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;
|
config->query = url;
|
||||||
sendCgi("/cgi-bin/index.cgi", prequest, length, cookie, content_type);
|
sendCgi("/cgi-bin/index.cgi", prequest, length, cookie, content_type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* FEATURE_HTTPD_CGI */
|
#endif /* FEATURE_HTTPD_CGI */
|
||||||
if (purl[-1] == '/')
|
|
||||||
strcpy(purl, "index.html");
|
|
||||||
if (stat(test, &sb) == 0) {
|
|
||||||
config->ContentLength = sb.st_size;
|
|
||||||
config->last_mod = sb.st_mtime;
|
|
||||||
}
|
|
||||||
sendFile(test);
|
sendFile(test);
|
||||||
config->ContentLength = -1;
|
config->ContentLength = -1;
|
||||||
} while (0);
|
} while (0);
|
||||||
|
55
networking/httpd_index_cgi_example
Normal file
55
networking/httpd_index_cgi_example
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user