httpd: fix cgi-bin/index.cgi support, add example of it,
authorDenis Vlasenko <vda.linux@googlemail.com>
Tue, 21 Nov 2006 00:12:09 +0000 (00:12 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Tue, 21 Nov 2006 00:12:09 +0000 (00:12 -0000)
stat: fix end-of-line if format is specified (wasn't printing it),
      fix %z (time) format to match coreutils 6.3

coreutils/stat.c
networking/httpd.c
networking/httpd_index_cgi_example [new file with mode: 0644]

index b9fd42f4a3707d566ee1fcab13806bcbe0531b80..31dd6624eccdfb4ba9192f00dc691d7602ab7751 100644 (file)
@@ -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 */
index 47d41a1e2adf596e28d7f4a744ed5e7d4d911d1d..08b40e014fdebd83cbfce2329b19204e1aac1783 100644 (file)
@@ -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 (file)
index 0000000..31e768c
--- /dev/null
@@ -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// /&nbsp;}" # 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