/* TreyfCGI: a non-Kosher (optionally) FastCGI C web framework for when you're * sick of everything else. * * My first slightly interesting C project. It's probably pretty terrible. * * Released into the public domain by Teran McKinney. * If public domain is not an option for you, it's also released under the CC0 * license. * * http://creativecommons.org/publicdomain/zero/1.0/ * * Building: * * Something like this works for me, using GCC 4.4.2: * gcc -O2 -D fastcgi -std=c99 treyfcgi.c -lfcgi -o /usr/local/bin/treyfcgi * * -D options are fastcgi and debug at this time. If you want fastcgi, be sure * to have the appropriate FastCGI headers installed: http://www.fastcgi.com/A * * Usage: * * Typical FastCGI socket setup, or you can argv[1] a file to test it on. * * For example: treyfcgi test.tf * * Version history: * (two bytes representec in hex, for major and minor) * 00.00 - 2011-06-01 * 00.01 - 2011-06-03 - First public release * 00.02 - 2011-06-15 - Fixed a buffer overflow, fixed source view, new tags. * 00.03 - 2011-12-25 - dirlist() did not ASCII sort on newer environment/libc * 00.04 - 2012-02-09 - to set font to monospaced. */ #define _SVID_SOURCE #ifdef fastcgi // FastCGI #include #else // No FastCGI #include #endif // Environment variables #include // open #include // read #include // Sensible int declaration #include // Directory functions #include extern char **environ; typedef uint32_t u32; typedef uint16_t u16; typedef uint8_t u8; // puts without the newline void p (char *text) { fputs(text, stdout); } void e (char *text) { fputs(text, stderr); } void sc (char *dst, char *src) { u8 i=0; // Thanks to Mark L. for finding this obvious bugger overflow. I've // since added range checking on i. for ( ; src[i] != 0 && i != 0xFF; i++ ) { dst[i] = src[i]; } // Null at the end of dst so we don't get contamination. dst[i] = 0; // return i; // Length until null byte. } char endtag[512]; void end(char *t) { sc(endtag, t); } void dirlist() { u16 n; u16 c = 0; extern char envpath[0x100]; struct dirent **listing; n = scandir(envpath, &listing, 0, alphasort); while (c < n) { printf("
  • %s", listing[c]->d_name,listing[c]->d_name); c++; } free(listing); } void parse(char c) { extern u16 pos; switch (c) { // Title case 't': p (""); pos++; // Skip the space or newline end(""); break; // Bold case 'b': p (""); pos++; // Skip the space or newline end(""); break; // Link case 'l': p (""); break; // End link case 'e': p (""); end(""); break; // Image case 'i': p (""); break; // Directory listing case 'd': dirlist(); end(""); break; // p for prettyI really mean li, but l is already in use. case 'p': p ("
  • "); pos++; // Skip the space or newline // No
  • because I'm terrible like that. end(""); break; } } // I believe that technically this is a signed int that can be 32 or 64b // depending on the libc build. Probably won't be happy if I force pass it a // smaller or larger bitwidth. char envpath[0x100]; char scriptpath[0x100]; char buf[0xFFFF]; u16 pos; int main (u8 uberargc, char *uberargv[]) { #ifdef debug char **envp; #endif extern char endtag[512]; #ifdef fastcgi u32 count = 0; while (FCGI_Accept() >= 0) { #endif char *script = getenv("SCRIPT_FILENAME"); extern char scriptpath[0x100]; char *env = getenv("DOCUMENT_ROOT"); extern char envpath[0x100]; char *query = getenv("QUERY_STRING"); char querystring[0x100]; if (env != NULL) { sc(envpath, env); } else { sc(envpath, "."); } if (query != NULL) { sc(querystring, query); } else { sc(querystring, ""); } if (script != NULL) { sc(scriptpath, script); } else if (uberargc == 2) { sc(scriptpath, uberargv[1]); } else { e("You got treyfed!\n"); } if (scriptpath != NULL) { #ifdef debug printf ("\n%s\n", scriptpath); #endif // Probably another int with potentially mixed // definition between libcs. int fd = open(scriptpath, O_RDONLY); if (fd == -1) { e("You got treyfed!\n"); //return 1; } extern char buf[0xFFFF]; extern u16 pos; u16 fdlength = read(fd, buf, 0xFFFF); close(fd); // Prevent buffer corruption. buf[fdlength]=0; #ifdef debug printf ("%d\n", fdlength); #endif #ifdef fastcgi // Source view mode if (querystring[0] == 's') { p("Content-type: text/plain\r\n\r\n"); // Stripped whitespace to fit into 80 colums. for (pos=0;pos!=0xFFFF&&buf[pos]!=0;pos++) printf ("%c", buf[pos]); continue; // Don't do return 0! } printf("Content-type: text/html\r\n" "TreyfCGI-Hits: %d\r\n" "Cache-Control: max-age=120\r\n" // Two minute "\r\n", ++count); // simple cache p(""); #endif for ( pos = 0; pos != 0xFFFF && buf[pos] != 0; pos++) { switch (buf[pos]) { case '[': parse(buf[++pos]); break; // newline. case ']': p(endtag); end(""); break; #ifdef fastcgi case '\n': p("
    "); break; #endif default : printf ("%c", buf[pos]); break; } } } #ifdef debug envp = environ; for ( ; *envp != NULL; envp++) printf("%s\n", *envp); #endif #ifdef fastcgi } #endif return 0; }