From a9d0e2386f5f494bb9b4e9d56f6b95b40d7579d4 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sun, 24 Apr 2022 19:57:53 -0500 Subject: [PATCH] Add simple static httpd. And move url escape/unescape into lib/net.c. --- lib/lib.h | 2 + lib/net.c | 39 ++++++++++ toys/net/wget.c | 33 +------- toys/pending/httpd.c | 178 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 220 insertions(+), 32 deletions(-) create mode 100644 toys/pending/httpd.c diff --git a/lib/lib.h b/lib/lib.h index e4c3abe0..1bba7b04 100644 --- a/lib/lib.h +++ b/lib/lib.h @@ -351,6 +351,8 @@ int pollinate(int in1, int in2, int out1, int out2, int timeout, int shutdown_ti char *ntop(struct sockaddr *sa); void xsendto(int sockfd, void *buf, size_t len, struct sockaddr *dest); int xrecvwait(int fd, char *buf, int len, union socksaddr *sa, int timeout); +char *escape_url(char *str, char *and); +void unescape_url(char *str); // password.c int get_salt(char *salt, char * algo); diff --git a/lib/net.c b/lib/net.c index 414c82a5..5732b47e 100644 --- a/lib/net.c +++ b/lib/net.c @@ -173,3 +173,42 @@ int xrecvwait(int fd, char *buf, int len, union socksaddr *sa, int timeout) return len; } + +// Convert space/low ascii to %XX escapes, plus any chars in "and" string. +// Returns newly allocated copy of string (even if no changes) +char *escape_url(char *str, char *and) +{ + int i, j , count; + char *ret, *ss; + + for (j = count = 0;;) { + for (i = 0;;) { + if (str[i] && (str[i]<=' ' || (and && strchr(and, str[i])))) { + if (j) ss += sprintf(ss, "%%%02x", str[i]); + else count++; + } else if (j) *ss++ = str[i]; + if (!str[i++]) break; + } + if (j++) break; + ret = ss = xmalloc(i+count*2); + } + + return ret; +} + +// Convert %XX escapes to character (in place) +void unescape_url(char *str) +{ + char *to; + int i; + + for (to = str;;) { + if (*str!='%' || !isxdigit(str[1]) || !isxdigit(str[2])) { + if (!(*to++ = *str++)) break; + } else { + sscanf(++str, "%2x", &i); + *to++ = i; + str += 2; + } + } +} diff --git a/toys/net/wget.c b/toys/net/wget.c index 737605d9..cfdbb7da 100644 --- a/toys/net/wget.c +++ b/toys/net/wget.c @@ -83,37 +83,6 @@ GLOBALS( #endif ) -char *escape_url(char *str) -{ - int i, count; - char *s; - - for (i = count = 0; str[i]; i++) if (isspace(str[i])) count++; - s = xmalloc(i+1+count*2); - for (i = 0;;) { - if (isspace(*str)) i += sprintf(s+i, "%%%02x", *str++); - else if (!(s[i++] = *str++)) break; - } - - return s; -} - -void unescape_url(char *str) -{ - char *to; - int i; - - for (to = str;;) { - if (*str!='%' || !isxdigit(str[1]) || !isxdigit(str[2])) { - if (!(*to++ = *str++)) break; - } else { - sscanf(++str, "%2x", &i); - *to++ = i; - str += 2; - } - } -} - // get http info in URL static void wget_info(char *url, char **host, char **port, char **path) { @@ -266,7 +235,7 @@ void wget_main(void) char *body, *index, *host, *port, *path = 0, *chunked, *ss; char agent[] = "toybox wget/" TOYBOX_VERSION; - TT.url = escape_url(*toys.optargs); + TT.url = escape_url(*toys.optargs, 0); // Ask server for URL, following redirects until success while (status != 200) { diff --git a/toys/pending/httpd.c b/toys/pending/httpd.c new file mode 100644 index 00000000..cf512ac7 --- /dev/null +++ b/toys/pending/httpd.c @@ -0,0 +1,178 @@ +/* httpd.c - Web server. + * + * Copyright 2022 Rob Landley + * + * See https://www.ietf.org/rfc/rfc2616.txt + * + * TODO: multiple domains, cgi, https, actual inetd with ratelimit... + +USE_HTTPD(NEWTOY(httpd, ">1", TOYFLAG_USR|TOYFLAG_BIN)) + +config HTTPD + bool "httpd" + default n + help + usage: httpd [DIR] + + Serve contents of directory as static web pages. +*/ + +#include "toys.h" + +char *rfc1123(char *buf, time_t t) +{ + strftime(buf, 64, "%a, %d %b %Y %T GMT", gmtime(&t)); + + return buf; +} + +// Stop: header time. +void header_time(int stat, char *str, char *more) +{ + char buf[64]; + + xprintf("HTTP/1.0 %d %s\r\nServer: toybox httpd/%s\r\nDate: %s\r\n%s" + "Connection: close\r\n\r\n", stat, str, TOYBOX_VERSION, + rfc1123(buf, time(0)), more ? : ""); +} + +void error_time(int stat, char *str) +{ + header_time(stat, str, 0); + xprintf("%d %s" + "

%d %s

", stat, str, stat, str); +} + +// She never told me... +char *mime(char *file) +{ + char *s = strrchr(file, '.'), *types[] = { + "asc\0text/plain", "bin\0application/octet-stream", "bmp\0image/bmp", + "cpio\0application/x-cpio", "css\0text/css", "doc\0application/msword", + "dtd\0text/xml", "dvi\0application/x-dvi", "gif\0image/gif", + "htm\0text/html", "html\0text/html", "jar\0applicat/x-java-archive", + "jpeg\0image/jpeg", "jpg\0image/jpeg", "js\0application/x-javascript", + "mp3\0audio/mpeg", "mp4\0video/mp4", "mpg\0video/mpeg", + "ogg\0application/ogg", "pbm\0image/x-portable-bitmap", + "pdf\0application/pdf", "png\0image/png", + "ppt\0application/vnd.ms-powerpoint", "ps\0application/postscript", + "rtf\0text/rtf", "sgml\0text/sgml", "svg\0image/svg+xml", + "tar\0application/x-tar", "tex\0application/x-tex", "tiff\0image/tiff", + "txt\0text/plain", "wav\0audio/x-wav", "xls\0application/vnd.ms-excel", + "xml\0tet/xml", "zip\0application/zip" + }; + int i; + + strcpy(toybuf, "text/plain"); + if (s++) for (i = 0; iIndex of %s\n" + "

Index of %s

\n", word[1], word[1]); + for (dd = fdopendir(fd); (dir = readdir(dd));) { + esc = escape_url(dir->d_name, "<>&\""); + dprintf(outfd, "%s
\n", esc, esc); + free(esc); + } + dprintf(outfd, "\n"); + } + } else error_time(501, "Not Implemented"); + free(s); +} + +void httpd_main(void) +{ + if (toys.optc && chdir(*toys.optargs)) + return error_time(500, "Internal Error"); + // inetd only at the moment + handle(0, 1); +} -- 2.39.2