diff options
-rw-r--r-- | networking/httpd_ssi.c | 104 |
1 files changed, 83 insertions, 21 deletions
diff --git a/networking/httpd_ssi.c b/networking/httpd_ssi.c index 86f341fbd..03f263397 100644 --- a/networking/httpd_ssi.c +++ b/networking/httpd_ssi.c @@ -31,13 +31,17 @@ httpd_ssi.c -o httpd_ssi */ /* Size (i386, static uclibc, approximate): - text data bss dec hex filename - 8931 164 68552 77647 12f4f httpd_ssi -*/ + * text data bss dec hex filename + * 9487 160 68552 78199 13177 httpd_ssi + * + * Note: it wouldn't be too hard to get rid of stdio and strdup, + * (especially that fgets() mangles NULs...) + */ #include <sys/types.h> #include <sys/stat.h> #include <errno.h> +#include <fcntl.h> #include <stdint.h> #include <stdlib.h> #include <string.h> @@ -46,40 +50,97 @@ httpd_ssi.c -o httpd_ssi #include <dirent.h> #include <time.h> +static char* skip_whitespace(char *s) +{ + while (*s == ' ' || *s == '\t') ++s; + + return s; +} + static char line[64 * 1024]; -/* - * Currently only handles directives which are alone on the line - */ static void process_includes(const char *filename) { + int curdir_fd; + char *end; FILE *fp = fopen(filename, "r"); if (!fp) exit(1); -#define INCLUDE "<!--#include file=\"" + /* Ensure that nested includes are relative: + * if we include a/1.htm and it includes b/2.htm, + * we need to include a/b/2.htm, not b/2.htm + */ + curdir_fd = -1; + end = strrchr(filename, '/'); + if (end) { + curdir_fd = open(".", O_RDONLY); + /* *end = '\0' would mishandle "/file.htm" */ + end[1] = '\0'; + chdir(filename); + } + +#define INCLUDE "<!--#include" while (fgets(line, sizeof(line), fp)) { - char *closing_dq; + unsigned preceding_len; + char *include_directive; - /* FIXME: output text leading to INCLUDE first */ - if (strncmp(line, INCLUDE, sizeof(INCLUDE)-1) != 0 - || (closing_dq = strchr(line + sizeof(INCLUDE)-1, '"')) == NULL - /* or strstr(line + sizeof(INCLUDE)-1, "\" -->")? */ + include_directive = strstr(line, INCLUDE); + if (!include_directive) { + fputs(line, stdout); + continue; + } + preceding_len = include_directive - line; + if (memchr(line, '\"', preceding_len) + || memchr(line, '\'', preceding_len) ) { + /* INCLUDE string may be inside "str" or 'str', + * ignore it */ + fputs(line, stdout); + continue; + } + /* Small bug: we accept #includefile="file" too */ + include_directive = skip_whitespace(include_directive + sizeof(INCLUDE)-1); + if (strncmp(include_directive, "file=\"", 6) != 0) { + /* "<!--#include virtual=..."? - not supported */ + fputs(line, stdout); + continue; + } + include_directive += 6; /* now it points to file name */ + end = strchr(include_directive, '\"'); + if (!end) { fputs(line, stdout); continue; } - *closing_dq = '\0'; + /* We checked that this is a valid include directive */ + + /* Print everything before directive */ + if (preceding_len) { + line[preceding_len] = '\0'; + fputs(line, stdout); + } + /* Save everything after directive */ + *end++ = '\0'; + end = strchr(end, '>'); + if (end) + end = strdup(end + 1); + /* FIXME: * (1) are relative paths with /../ etc ok? - * (2) if we include a/1.htm and it includes b/2.htm, - * do we need to include a/b/2.htm or b/2.htm? - * IOW, do we need to "cd $dirname"? + * (2) what to do with absolute paths? + * are they relative to doc root or to real root? */ - process_includes(line + sizeof(INCLUDE)-1); - /* FIXME: this should be the tail of line after --> */ - putchar('\n'); + process_includes(include_directive); + + /* Print everything after directive */ + if (end) { + fputs(end, stdout); + free(end); + } } + if (curdir_fd >= 0) + fchdir(curdir_fd); + fclose(fp); } int main(int argc, char *argv[]) @@ -95,13 +156,14 @@ int main(int argc, char *argv[]) * Connection: close * Content-Type: text/html */ - printf( + fputs( /* "Date: Thu, 10 Sep 2009 18:23:28 GMT\r\n" */ /* "Server: Apache\r\n" */ /* "Accept-Ranges: bytes\r\n" - do we really accept bytes?! */ "Connection: close\r\n" "Content-Type: text/html\r\n" - "\r\n" + "\r\n", + stdout ); process_includes(argv[1]); return 0; |