diff options
author | Ralf Corsepius <ralf.corsepius@rtems.org> | 2010-06-09 08:06:08 +0000 |
---|---|---|
committer | Ralf Corsepius <ralf.corsepius@rtems.org> | 2010-06-09 08:06:08 +0000 |
commit | dc35201765459ae69c0becccdc4cace5ce246da2 (patch) | |
tree | 5b01dff6a33fd36a3b2215611b8f61faffadeeec | |
parent | Remove. (diff) | |
download | rtems-dc35201765459ae69c0becccdc4cace5ce246da2.tar.bz2 |
Remove.
36 files changed, 0 insertions, 8068 deletions
diff --git a/cpukit/aclocal/enable-shttpd.m4 b/cpukit/aclocal/enable-shttpd.m4 deleted file mode 100644 index 5398c5308a..0000000000 --- a/cpukit/aclocal/enable-shttpd.m4 +++ /dev/null @@ -1,12 +0,0 @@ -dnl $Id$ - -AC_DEFUN([RTEMS_ENABLE_SHTTPD], -[ -AC_ARG_ENABLE([shttpd], -AS_HELP_STRING([--enable-shttpd],[enable (small httpd) shttpd (DEPRECATED)]), -[case "${enableval}" in - yes) enable_shttpd=yes ;; - no) enable_shttpd=no ;; - *) AC_MSG_ERROR(bad value ${enableval} for enable-shttpd option) ;; -esac],[enable_shttpd=no]) -]) diff --git a/cpukit/shttpd/.cvsignore b/cpukit/shttpd/.cvsignore deleted file mode 100644 index 3dda72986f..0000000000 --- a/cpukit/shttpd/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -Makefile.in -Makefile diff --git a/cpukit/shttpd/Makefile.am b/cpukit/shttpd/Makefile.am deleted file mode 100644 index 8496e7b132..0000000000 --- a/cpukit/shttpd/Makefile.am +++ /dev/null @@ -1,70 +0,0 @@ -# DEPRECATED, don't use. - -include $(top_srcdir)/automake/compile.am - -if LIBSHTTPD -include_shttpddir = $(includedir)/shttpd - -project_lib_LIBRARIES = libshttpd.a -libshttpd_a_CPPFLAGS = $(AM_CPPFLAGS) -DHAVE_MD5 - -# HACK ALERT: -# prefix all non-public symbols with _shttp_ -# FIXME: There must be something better than this -libshttpd_a_CPPFLAGS += -Dcheck_authorization=_shttpd_check_authorization -libshttpd_a_CPPFLAGS += -Ddecode_url_encoded_string=_shttpd_decode_url_encoded_string -libshttpd_a_CPPFLAGS += -Dedit_passwords=_shttpd_edit_passwords -libshttpd_a_CPPFLAGS += -Delog=_shttpd_elog -libshttpd_a_CPPFLAGS += -Dget_dir=_shttpd_get_dir -libshttpd_a_CPPFLAGS += -Dget_file=_shttpd_get_file -libshttpd_a_CPPFLAGS += -Dget_headers_len=_shttpd_get_headers_len -libshttpd_a_CPPFLAGS += -Dget_mime_type=_shttpd_get_mime_type -libshttpd_a_CPPFLAGS += -Dinit_from_argc_argv=_shttpd_init_from_argc_argv -libshttpd_a_CPPFLAGS += -Dis_authorized_for_put=_shttpd_is_authorized_for_put -libshttpd_a_CPPFLAGS += -Dis_registered_uri=_shttpd_is_registered_uri -libshttpd_a_CPPFLAGS += -Dlog_access=_shttpd_log_access -libshttpd_a_CPPFLAGS += -Dparse_headers=_shttpd_parse_headers -libshttpd_a_CPPFLAGS += -Dput_dir=_shttpd_put_dir -libshttpd_a_CPPFLAGS += -Dsend_authorization_request=_shttpd_send_authorization_request -libshttpd_a_CPPFLAGS += -Dsend_server_error=_shttpd_send_server_error -libshttpd_a_CPPFLAGS += -Dset_close_on_exec=_shttpd_set_close_on_exec -libshttpd_a_CPPFLAGS += -Dset_mime_types=_shttpd_set_mime_types -libshttpd_a_CPPFLAGS += -Dset_non_blocking_mode=_shttpd_set_non_blocking_mode -libshttpd_a_CPPFLAGS += -Dsetup_embedded_stream=_shttpd_setup_embedded_stream -libshttpd_a_CPPFLAGS += -Dstop_stream=_shttpd_stop_stream -libshttpd_a_CPPFLAGS += -Dusage=_shttpd_usage - -libshttpd_a_CPPFLAGS += -Dknown_http_methods=_shttpd_known_http_methods -libshttpd_a_CPPFLAGS += -Doptions=_shttpd_options -libshttpd_a_CPPFLAGS += -Dio_file=_shttpd_io_file -libshttpd_a_CPPFLAGS += -Dio_socket=_shttpd_io_socket -libshttpd_a_CPPFLAGS += -Dio_embedded=_shttpd_io_embedded -libshttpd_a_CPPFLAGS += -Dio_dir=_shttpd_io_dir -libshttpd_a_CPPFLAGS += -Dio_cgi=_shttpd_io_cgi - -libshttpd_a_CPPFLAGS += -Dcurrent_time=_shttpd_current_time -libshttpd_a_CPPFLAGS += -Dtz_offset=_shttpd_tz_offset - -SRCS= string.c shttpd.c log.c auth.c md5.c \ - cgi.c mime_type.c config.c \ - io_file.c io_socket.c io_ssl.c io_emb.c io_dir.c io_cgi.c -HDRS= defs.h llist.h shttpd.h std_includes.h io.h md5.h ssl.h \ - compat_unix.h compat_win32.h compat_rtems.h - -libshttpd_a_SOURCES = $(SRCS) $(HDRS) -libshttpd_a_SOURCES += compat_rtems.c -include_shttpd_HEADERS = shttpd.h - -# Possible flags: (in brackets are rough numbers for 'gcc -O2' on i386) -# -DHAVE_MD5 - use system md5 library (-2kb) -# -DNDEBUG - strip off all debug code (-5kb) -# -D_DEBUG - build debug version (very noisy) (+6kb) -# -DNO_CGI - disable CGI support (-5kb) -# -DNO_SSL - disable SSL functionality (-2kb) -# -DNO_AUTH - disable authorization support (-4kb) -# -DNO_GUI - Win32 only. Build console version, no GUI -# -DCONFIG=\"file\" - use `file' as the default config file -endif - -include $(srcdir)/preinstall.am -include $(top_srcdir)/automake/local.am diff --git a/cpukit/shttpd/Makefile.shttpd b/cpukit/shttpd/Makefile.shttpd deleted file mode 100644 index 31e8da228e..0000000000 --- a/cpukit/shttpd/Makefile.shttpd +++ /dev/null @@ -1,50 +0,0 @@ -SRCS= string.c shttpd.c log.c auth.c md5.c \ - cgi.c mime_type.c config.c \ - io_file.c io_socket.c io_ssl.c io_emb.c io_dir.c io_cgi.c -HDRS= defs.h llist.h shttpd.h std_includes.h io.h md5.h ssl.h \ - compat_unix.h compat_win32.h compat_rtems.h -PROG= shttpd - -# Possible flags: (in brackets are rough numbers for 'gcc -O2' on i386) -# -DHAVE_MD5 - use system md5 library (-2kb) -# -DNDEBUG - strip off all debug code (-5kb) -# -D_DEBUG - build debug version (very noisy) (+6kb) -# -DNO_CGI - disable CGI support (-5kb) -# -DNO_SSL - disable SSL functionality (-2kb) -# -DNO_AUTH - disable authorization support (-4kb) -# -DNO_GUI - Win32 only. Build console version, no GUI -# -DCONFIG=\"file\" - use `file' as the default config file - -CL_FLAGS= /O1 /MD /TC /nologo /DNDEBUG - -all: - @echo "make (unix|msvc|mingw|rtems)" - -unix: - $(CC) -c $(CFLAGS) -DEMBEDDED $(SRCS) compat_unix.c - $(AR) -r lib$(PROG).a *.o && ranlib lib$(PROG).a - $(CC) $(CFLAGS) $(SRCS) compat_unix.c standalone.c -o $(PROG) $(LIBS) - -rtems: - $(CC) -c $(CFLAGS) -DEMBEDDED $(SRCS) compat_rtems.c - $(AR) -r lib$(PROG).a *.o && ranlib lib$(PROG).a - -msvc: - cl $(SRCS) /c $(CL_FLAGS) /DEMBEDDED - lib *.obj /out:shttpd.lib - rc resources.rc - cl $(SRCS) compat_win32.c standalone.c $(CL_FLAGS) \ - /link resources.res /out:$(PROG).exe /machine:ix86 - -mingw: - $(CC) -c $(CFLAGS) -DEMBEDDED $(SRCS) compat_win32.c - $(AR) -r lib$(PROG).a *.o && ranlib lib$(PROG).a - windres resources.rc resources.o - $(CC) $(CFLAGS) $(SRCS) compat_win32.c standalone.c resources.o -o $(PROG) $(LIBS) -lws2_32 -lcomdlg32 -lcomctl32 - -man: - cat shttpd.1 | tbl | groff -man -Tascii | col -b > shttpd.1.txt - cat shttpd.1 | tbl | groff -man -Tascii | less - -clean: - rm -rf *.o *.core $(PROG) lib$(PROG).a diff --git a/cpukit/shttpd/auth.c b/cpukit/shttpd/auth.c deleted file mode 100644 index 745f8ed709..0000000000 --- a/cpukit/shttpd/auth.c +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> - * All rights reserved - * - * "THE BEER-WARE LICENSE" (Revision 42): - * Sergey Lyubka wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. - */ - -#include "defs.h" - -#include <unistd.h> -#ifdef HAVE_STRINGS_H -#include <strings.h> -#endif - -#if !defined(NO_AUTH) -/* - * Stringify binary data. Output buffer must be twice as big as input, - * because each byte takes 2 bytes in string representation - */ -static void -bin2str(char *to, const unsigned char *p, size_t len) -{ - const char *hex = "0123456789abcdef"; - - for (;len--; p++) { - *to++ = hex[p[0] >> 4]; - *to++ = hex[p[0] & 0x0f]; - } -} - -/* - * Return stringified MD5 hash for list of vectors. - * buf must point to at least 32-bytes long buffer - */ -static void -md5(char *buf, ...) -{ - unsigned char hash[16]; - const struct vec *v; - va_list ap; - MD5_CTX ctx; - int i; - - MD5Init(&ctx); - - va_start(ap, buf); - for (i = 0; (v = va_arg(ap, const struct vec *)) != NULL; i++) { - assert(v->len >= 0); - if (v->len == 0) - continue; - if (i > 0) - MD5Update(&ctx, (unsigned char *) ":", 1); - MD5Update(&ctx,(unsigned char *)v->ptr,(unsigned int)v->len); - } - va_end(ap); - - MD5Final(hash, &ctx); - bin2str(buf, hash, sizeof(hash)); -} - -/* - * Compare to vectors. Return 1 if they are equal - */ -static int -vcmp(const struct vec *v1, const struct vec *v2) -{ - return (v1->len == v2->len && !memcmp(v1->ptr, v2->ptr, v1->len)); -} - -struct digest { - struct vec user; - struct vec uri; - struct vec nonce; - struct vec cnonce; - struct vec resp; - struct vec qop; - struct vec nc; -}; - -static const struct auth_keyword { - size_t offset; - struct vec vec; -} known_auth_keywords[] = { - {offsetof(struct digest, user), {"username=", 9}}, - {offsetof(struct digest, cnonce), {"cnonce=", 7}}, - {offsetof(struct digest, resp), {"response=", 9}}, - {offsetof(struct digest, uri), {"uri=", 4}}, - {offsetof(struct digest, qop), {"qop=", 4}}, - {offsetof(struct digest, nc), {"nc=", 3}}, - {offsetof(struct digest, nonce), {"nonce=", 6}}, - {0, {NULL, 0}} -}; - -static void -parse_authorization_header(const struct vec *h, struct digest *dig) -{ - const unsigned char *p, *e, *s; - struct vec *v, vec; - const struct auth_keyword *kw; - - (void) memset(dig, 0, sizeof(*dig)); - p = (unsigned char *) h->ptr + 7; - e = (unsigned char *) h->ptr + h->len; - - while (p < e) { - - /* Skip spaces */ - while (p < e && (*p == ' ' || *p == ',')) - p++; - - /* Skip to "=" */ - for (s = p; s < e && *s != '='; ) - s++; - s++; - - /* Is it known keyword ? */ - for (kw = known_auth_keywords; kw->vec.len > 0; kw++) - if (kw->vec.len <= s - p && - !memcmp(p, kw->vec.ptr, kw->vec.len)) - break; - - if (kw->vec.len == 0) - v = &vec; /* Dummy placeholder */ - else - v = (struct vec *) ((char *) dig + kw->offset); - - if (*s == '"') { - p = ++s; - while (p < e && *p != '"') - p++; - } else { - p = s; - while (p < e && *p != ' ' && *p != ',') - p++; - } - - v->ptr = (char *) s; - v->len = p - s; - - if (*p == '"') - p++; - - DBG(("auth field [%.*s]", v->len, v->ptr)); - } -} - -/* - * Check the user's password, return 1 if OK - */ -static int -check_password(int method, const struct vec *ha1, const struct digest *digest) -{ - char a2[32], resp[32]; - struct vec vec_a2; - - /* XXX Due to a bug in MSIE, we do not compare the URI */ - /* Also, we do not check for authentication timeout */ - if (/*strcmp(dig->uri, c->ouri) != 0 || */ - digest->resp.len != 32 /*|| - now - strtoul(dig->nonce, NULL, 10) > 3600 */) - return (0); - - md5(a2, &known_http_methods[method], &digest->uri, NULL); - vec_a2.ptr = a2; - vec_a2.len = sizeof(a2); - md5(resp, ha1, &digest->nonce, &digest->nc, - &digest->cnonce, &digest->qop, &vec_a2, NULL); - - return (!memcmp(resp, digest->resp.ptr, 32)); -} - -static FILE * -open_auth_file(struct shttpd_ctx *ctx, const char *path) -{ - char name[FILENAME_MAX]; - const char *p, *e; - FILE *fp = NULL; - int fd; - - if (ctx->global_passwd_file) { - /* Use global passwords file */ - my_snprintf(name, sizeof(name), "%s", ctx->global_passwd_file); - } else { - /* Try to find .htpasswd in requested directory */ - for (p = path, e = p + strlen(p) - 1; e > p; e--) - if (IS_DIRSEP_CHAR(*e)) - break; - - assert(IS_DIRSEP_CHAR(*e)); - (void) my_snprintf(name, sizeof(name), "%.*s/%s", - (int) (e - p), p, HTPASSWD); - } - - if ((fd = my_open(name, O_RDONLY, 0)) == -1) { - DBG(("open_auth_file: open(%s)", name)); - } else if ((fp = fdopen(fd, "r")) == NULL) { - DBG(("open_auth_file: fdopen(%s)", name)); - (void) close(fd); - } - - return (fp); -} - -/* - * Parse the line from htpasswd file. Line should be in form of - * "user:domain:ha1". Fill in the vector values. Return 1 if successful. - */ -static int -parse_htpasswd_line(const char *s, struct vec *user, - struct vec *domain, struct vec *ha1) -{ - user->len = domain->len = ha1->len = 0; - - for (user->ptr = s; *s != '\0' && *s != ':'; s++, user->len++); - if (*s++ != ':') - return (0); - - for (domain->ptr = s; *s != '\0' && *s != ':'; s++, domain->len++); - if (*s++ != ':') - return (0); - - for (ha1->ptr = s; *s != '\0' && !isspace(* (unsigned char *) s); - s++, ha1->len++); - - DBG(("parse_htpasswd_line: [%.*s] [%.*s] [%.*s]", user->len, user->ptr, - domain->len, domain->ptr, ha1->len, ha1->ptr)); - - return (user->len > 0 && domain->len > 0 && ha1->len > 0); -} - -/* - * Authorize against the opened passwords file. Return 1 if authorized. - */ -static int -authorize(struct conn *c, FILE *fp) -{ - struct vec *auth_vec = &c->ch.auth.v_vec; - struct vec *user_vec = &c->ch.user.v_vec; - struct vec user, domain, ha1; - struct digest digest; - int ok = 0; - char line[256]; - - if (auth_vec->len > 20 && - !my_strncasecmp(auth_vec->ptr, "Digest ", 7)) { - - parse_authorization_header(auth_vec, &digest); - *user_vec = digest.user; - - while (fgets(line, sizeof(line), fp) != NULL) { - - if (!parse_htpasswd_line(line, &user, &domain, &ha1)) - continue; - - DBG(("[%.*s] [%.*s] [%.*s]", user.len, user.ptr, - domain.len, domain.ptr, ha1.len, ha1.ptr)); - - if (vcmp(user_vec, &user) && !memcmp(c->ctx->auth_realm, - domain.ptr, domain.len)) { - ok = check_password(c->method, &ha1, &digest); - break; - } - } - } - - return (ok); -} - -int -check_authorization(struct conn *c, const char *path) -{ - FILE *fp = NULL; - int authorized = 1; - -#ifdef EMBEDDED - struct llhead *lp; - struct uri_auth *auth; - - /* Check, is this URL protected by shttpd_protect_url() */ - LL_FOREACH(&c->ctx->uri_auths, lp) { - auth = LL_ENTRY(lp, struct uri_auth, link); - if (!strncmp(c->uri, auth->uri, auth->uri_len)) { - fp = fopen(auth->file_name, "r"); - break; - } - } -#endif /* EMBEDDED */ - - if (fp == NULL) - fp = open_auth_file(c->ctx, path); - - if (fp != NULL) { - authorized = authorize(c, fp); - (void) fclose(fp); - } - - return (authorized); -} - -int -is_authorized_for_put(struct conn *c) -{ - FILE *fp; - int ret = 0; - - if ((fp = fopen(c->ctx->put_auth_file, "r")) != NULL) { - ret = authorize(c, fp); - (void) fclose(fp); - } - - return (ret); -} - -void -send_authorization_request(struct conn *c) -{ - char buf[512]; - - (void) my_snprintf(buf, sizeof(buf), "Unauthorized\r\n" - "WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", " - "nonce=\"%lu\"", c->ctx->auth_realm, (unsigned long) current_time); - - send_server_error(c, 401, buf); -} - -/* - * Edit the passwords file. - */ -int -edit_passwords(const char *fname, const char *domain, - const char *user, const char *pass) -{ - int ret = EXIT_SUCCESS, found = 0; - struct vec u, d, p; - char line[512], tmp[FILENAME_MAX], ha1[32]; - FILE *fp = NULL, *fp2 = NULL; - - (void) my_snprintf(tmp, sizeof(tmp), "%s.tmp", fname); - - /* Create the file if does not exist */ - if ((fp = fopen(fname, "a+"))) - (void) fclose(fp); - - /* Open the given file and temporary file */ - if ((fp = fopen(fname, "r")) == NULL) - elog(E_FATAL, 0, "Cannot open %s: %s", fname, strerror(errno)); - else if ((fp2 = fopen(tmp, "w+")) == NULL) - elog(E_FATAL, 0, "Cannot open %s: %s", tmp, strerror(errno)); - - p.ptr = pass; - p.len = strlen(pass); - - /* Copy the stuff to temporary file */ - while (fgets(line, sizeof(line), fp) != NULL) { - u.ptr = line; - if ((d.ptr = strchr(line, ':')) == NULL) - continue; - u.len = d.ptr - u.ptr; - d.ptr++; - if (strchr(d.ptr, ':') == NULL) - continue; - d.len = strchr(d.ptr, ':') - d.ptr; - - if ((int) strlen(user) == u.len && - !memcmp(user, u.ptr, u.len) && - (int) strlen(domain) == d.len && - !memcmp(domain, d.ptr, d.len)) { - found++; - md5(ha1, &u, &d, &p, NULL); - (void) fprintf(fp2, "%s:%s:%.32s\n", user, domain, ha1); - } else { - (void) fprintf(fp2, "%s", line); - } - } - - /* If new user, just add it */ - if (found == 0) { - u.ptr = user; u.len = strlen(user); - d.ptr = domain; d.len = strlen(domain); - md5(ha1, &u, &d, &p, NULL); - (void) fprintf(fp2, "%s:%s:%.32s\n", user, domain, ha1); - } - - /* Close files */ - (void) fclose(fp); - (void) fclose(fp2); - - /* Put the temp file in place of real file */ - (void) my_remove(fname); - (void) my_rename(tmp, fname); - - return (ret); -} -#endif /* NO_AUTH */ diff --git a/cpukit/shttpd/cgi.c b/cpukit/shttpd/cgi.c deleted file mode 100644 index 98d83db241..0000000000 --- a/cpukit/shttpd/cgi.c +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> - * All rights reserved - * - * "THE BEER-WARE LICENSE" (Revision 42): - * Sergey Lyubka wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. - */ - -#include "defs.h" - -#if !defined(NO_CGI) -struct env_block { - char buf[ENV_MAX]; /* Environment buffer */ - int len; /* Space taken */ - char *vars[CGI_ENV_VARS]; /* Point into the buffer */ - int nvars; /* Number of variables */ -}; - -/* - * Verify that given file has CGI extension - */ -int -is_cgi(struct shttpd_ctx *ctx, const char *path) -{ - size_t len, path_len; - const char *s = ctx->cgi_extensions; - - path_len = strlen(path); - - FOR_EACH_WORD_IN_LIST(s, len) - if (len < path_len && - !my_strncasecmp(path + path_len - len, s, len)) - return (1); - - return (0); -} - -/* - * UNIX socketpair() implementation. Why? Because Windows does not have it. - * Return 0 on success, -1 on error. - */ -static int -my_socketpair(struct conn *c, int sp[2]) -{ - struct sockaddr_in sa; - int sock, ret = -1; - socklen_t len = sizeof(sa); - - (void) memset(&sa, 0, sizeof(sa)); - sa.sin_family = AF_INET; - sa.sin_port = htons(0); - sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - - if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { - elog(E_LOG, c, "mysocketpair: socket(): %d", ERRNO); - } else if (bind(sock, (struct sockaddr *) &sa, len) != 0) { - elog(E_LOG, c, "mysocketpair: bind(): %d", ERRNO); - (void) closesocket(sock); - } else if (listen(sock, 1) != 0) { - elog(E_LOG, c, "mysocketpair: listen(): %d", ERRNO); - (void) closesocket(sock); - } else if (getsockname(sock, (struct sockaddr *) &sa, &len) != 0) { - elog(E_LOG, c, "mysocketpair: getsockname(): %d", ERRNO); - (void) closesocket(sock); - } else if ((sp[0] = socket(AF_INET, SOCK_STREAM, 6)) == -1) { - elog(E_LOG, c, "mysocketpair: socket(): %d", ERRNO); - (void) closesocket(sock); - } else if (connect(sp[0], (struct sockaddr *) &sa, len) != 0) { - elog(E_LOG, c, "mysocketpair: connect(): %d", ERRNO); - (void) closesocket(sock); - (void) closesocket(sp[0]); - } else if ((sp[1] = accept(sock,(struct sockaddr *) &sa, &len)) == -1) { - elog(E_LOG, c, "mysocketpair: accept(): %d", ERRNO); - (void) closesocket(sock); - (void) closesocket(sp[0]); - } else { - /* Success */ - ret = 0; - (void) closesocket(sock); - } - -#ifndef _WIN32 - (void) fcntl(sp[0], F_SETFD, FD_CLOEXEC); - (void) fcntl(sp[1], F_SETFD, FD_CLOEXEC); -#endif /* _WIN32*/ - - return (ret); -} - -static void -addenv(struct env_block *block, const char *fmt, ...) -{ - int n, space; - va_list ap; - - space = sizeof(block->buf) - block->len - 2; - assert(space >= 0); - - va_start(ap, fmt); - n = vsnprintf(block->buf + block->len, space, fmt, ap); - va_end(ap); - - if (n > 0 && n < space && block->nvars < CGI_ENV_VARS - 2) { - block->vars[block->nvars++] = block->buf + block->len; - block->len += n + 1; /* Include \0 terminator */ - } -} - -static void -add_http_headers_to_env(struct env_block *b, const char *s, int len) -{ - const char *p, *v, *e = s + len; - int space, n, i, ch; - - /* Loop through all headers in the request */ - while (s < e) { - - /* Find where this header ends. Remember where value starts */ - for (p = s, v = NULL; p < e && *p != '\n'; p++) - if (v == NULL && *p == ':') - v = p; - - /* 2 null terminators and "HTTP_" */ - space = (sizeof(b->buf) - b->len) - (2 + 5); - assert(space >= 0); - - /* Copy header if enough space in the environment block */ - if (v > s && p > v + 2 && space > p - s) { - - /* Store var */ - if (b->nvars < (int) NELEMS(b->vars) - 1) - b->vars[b->nvars++] = b->buf + b->len; - - (void) memcpy(b->buf + b->len, "HTTP_", 5); - b->len += 5; - - /* Copy header name. Substitute '-' to '_' */ - n = v - s; - for (i = 0; i < n; i++) { - ch = s[i] == '-' ? '_' : s[i]; - b->buf[b->len++] = toupper(ch); - } - - b->buf[b->len++] = '='; - - /* Copy header value */ - v += 2; - n = p[-1] == '\r' ? (p - v) - 1 : p - v; - for (i = 0; i < n; i++) - b->buf[b->len++] = v[i]; - - /* Null-terminate */ - b->buf[b->len++] = '\0'; - } - - s = p + 1; /* Shift to the next header */ - } -} - -static void -prepare_environment(const struct conn *c, const char *prog, - struct env_block *blk) -{ - const struct headers *h = &c->ch; - const char *s; - size_t len; - - blk->len = blk->nvars = 0; - - /* Prepare the environment block */ - addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1"); - addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1"); - addenv(blk, "%s", "REDIRECT_STATUS=200"); /* PHP */ - addenv(blk, "SERVER_PORT=%d", c->ctx->port); - addenv(blk, "SERVER_NAME=%s", c->ctx->auth_realm); - addenv(blk, "SERVER_ROOT=%s", c->ctx->document_root); - addenv(blk, "DOCUMENT_ROOT=%s", c->ctx->document_root); - addenv(blk, "REQUEST_METHOD=%s", known_http_methods[c->method].ptr); - addenv(blk, "REMOTE_ADDR=%s", inet_ntoa(c->sa.u.sin.sin_addr)); - addenv(blk, "REMOTE_PORT=%hu", ntohs(c->sa.u.sin.sin_port)); - addenv(blk, "REQUEST_URI=%s", c->uri); - addenv(blk, "SCRIPT_NAME=%s", prog + strlen(c->ctx->document_root)); - addenv(blk, "SCRIPT_FILENAME=%s", prog); /* PHP */ - addenv(blk, "PATH_TRANSLATED=%s", prog); - - if (h->ct.v_vec.len > 0) - addenv(blk, "CONTENT_TYPE=%.*s", - h->ct.v_vec.len, h->ct.v_vec.ptr); - - if (c->query != NULL) - addenv(blk, "QUERY_STRING=%s", c->query); - - if (c->path_info != NULL) - addenv(blk, "PATH_INFO=/%s", c->path_info); - - if (h->cl.v_big_int > 0) - addenv(blk, "CONTENT_LENGTH=%lu", h->cl.v_big_int); - - if ((s = getenv("PATH")) != NULL) - addenv(blk, "PATH=%s", s); - -#ifdef _WIN32 - if ((s = getenv("COMSPEC")) != NULL) - addenv(blk, "COMSPEC=%s", s); - if ((s = getenv("SYSTEMROOT")) != NULL) - addenv(blk, "SYSTEMROOT=%s", s); -#else - if ((s = getenv("LD_LIBRARY_PATH")) != NULL) - addenv(blk, "LD_LIBRARY_PATH=%s", s); -#endif /* _WIN32 */ - - if ((s = getenv("PERLLIB")) != NULL) - addenv(blk, "PERLLIB=%s", s); - - if (h->user.v_vec.len > 0) { - addenv(blk, "REMOTE_USER=%.*s", - h->user.v_vec.len, h->user.v_vec.ptr); - addenv(blk, "%s", "AUTH_TYPE=Digest"); - } - - /* Add user-specified variables */ - s = c->ctx->cgi_vars; - FOR_EACH_WORD_IN_LIST(s, len) - addenv(blk, "%.*s", len, s); - - /* Add all headers as HTTP_* variables */ - add_http_headers_to_env(blk, c->headers, - c->rem.headers_len - (c->headers - c->request)); - - blk->vars[blk->nvars++] = NULL; - blk->buf[blk->len++] = '\0'; - - assert(blk->nvars < CGI_ENV_VARS); - assert(blk->len > 0); - assert(blk->len < (int) sizeof(blk->buf)); - - /* Debug stuff to view passed environment */ - DBG(("%s: %d vars, %d env size", prog, blk->nvars, blk->len)); - { - int i; - for (i = 0 ; i < blk->nvars; i++) - DBG(("[%s]", blk->vars[i] ? blk->vars[i] : "null")); - } -} - -int -run_cgi(struct conn *c, const char *prog) -{ - struct env_block blk; - char dir[FILENAME_MAX], *p; - int ret, pair[2]; - - prepare_environment(c, prog, &blk); - - /* CGI must be executed in its own directory */ - (void) my_snprintf(dir, sizeof(dir), "%s", prog); - for (p = dir + strlen(dir) - 1; p > dir; p--) - if (*p == '/') { - *p++ = '\0'; - break; - } - - if (my_socketpair(c, pair) != 0) { - ret = -1; - } else if (spawn_process(c, prog, blk.buf, blk.vars, pair[1], dir)) { - ret = -1; - (void) closesocket(pair[0]); - (void) closesocket(pair[1]); - } else { - ret = 0; - c->loc.chan.sock = pair[0]; - } - - return (ret); -} - -void -do_cgi(struct conn *c) -{ - DBG(("running CGI: [%s]", c->uri)); - assert(c->loc.io.size > CGI_REPLY_LEN); - memcpy(c->loc.io.buf, CGI_REPLY, CGI_REPLY_LEN); - c->loc.io.head = c->loc.io.tail = c->loc.io.total = CGI_REPLY_LEN; - c->loc.io_class = &io_cgi; - c->loc.flags = FLAG_R; - if (c->method == METHOD_POST) - c->loc.flags |= FLAG_W; -} - -#endif /* !NO_CGI */ diff --git a/cpukit/shttpd/compat_rtems.c b/cpukit/shttpd/compat_rtems.c deleted file mode 100644 index 19f28d045c..0000000000 --- a/cpukit/shttpd/compat_rtems.c +++ /dev/null @@ -1,200 +0,0 @@ -/********************************************************************** - * - * rtems shttpd management - * - * FILE NAME : rtems_shttpd.c - * - * AUTHOR : Steven Johnson - * - * DESCRIPTION : Defines the interface functions to the shttp daemon - * - * REVISION : $Id$ - * - * COMMENTS : - * - **********************************************************************/ - - /********************************************************************** - * INCLUDED MODULES - **********************************************************************/ -#include <rtems.h> -#include "defs.h" - -#define MAX_WEB_BASE_PATH_LENGTH 256 -#define MIN_SHTTPD_STACK (8*1024) - -typedef struct RTEMS_HTTPD_ARGS { - rtems_shttpd_init init_callback; - rtems_shttpd_addpages addpages_callback; - unsigned int port; - char webroot[MAX_WEB_BASE_PATH_LENGTH]; -} RTEMS_HTTPD_ARGS; - -static int rtems_webserver_running = FALSE; /* not running. */ - -static rtems_task rtems_httpd_daemon(rtems_task_argument args) -{ - RTEMS_HTTPD_ARGS *httpd_args = (RTEMS_HTTPD_ARGS*)args; - - struct shttpd_ctx *ctx; - - if (httpd_args != NULL) - if (httpd_args->init_callback != NULL) - httpd_args->init_callback(); - -/************************************** - * Initialize the web server - */ - /* - * Initialize SHTTPD context. - * Set WWW root to current WEB_ROOT_PATH. - */ - ctx = shttpd_init(NULL, "document_root", httpd_args->webroot, NULL); - - if (httpd_args != NULL) - if (httpd_args->addpages_callback != NULL) - httpd_args->addpages_callback(ctx); - - /* Finished with args, so free them */ - if (httpd_args != NULL) - free(httpd_args); - - /* Open listening socket */ - shttpd_listen(ctx, httpd_args->port); - - rtems_webserver_running = TRUE; - - /* Serve connections infinitely until someone kills us */ - while (rtems_webserver_running) - shttpd_poll(ctx, 1000); - - /* Unreached, because we will be killed by a signal */ - shttpd_fini(ctx); - - rtems_task_delete( RTEMS_SELF ); -} - -rtems_status_code rtems_initialize_webserver( - rtems_task_priority initial_priority, - size_t stack_size, - rtems_mode initial_modes, - rtems_attribute attribute_set, - rtems_shttpd_init init_callback, - rtems_shttpd_addpages addpages_callback, - char *webroot, - unsigned int port -) -{ - rtems_status_code sc; - rtems_id tid; - RTEMS_HTTPD_ARGS *args; - - if (stack_size < MIN_SHTTPD_STACK) - stack_size = MIN_SHTTPD_STACK; - - args = malloc(sizeof(RTEMS_HTTPD_ARGS)); - - if (args != NULL) { - args->init_callback = init_callback; - args->addpages_callback = addpages_callback; - args->port = port; - strncpy(args->webroot,webroot,MAX_WEB_BASE_PATH_LENGTH); - - sc = rtems_task_create(rtems_build_name('H', 'T', 'P', 'D'), - initial_priority, - stack_size, - initial_modes, - attribute_set, - &tid); - - if (sc == RTEMS_SUCCESSFUL) { - sc = rtems_task_start(tid, rtems_httpd_daemon, (rtems_task_argument)args); - } - } else { - sc = RTEMS_NO_MEMORY; - } - - return sc; -} - -void rtems_terminate_webserver(void) -{ - rtems_webserver_running = FALSE; /* not running, so terminate */ -} - -int rtems_webserver_ok(void) -{ - return rtems_webserver_running; -} - -void -set_close_on_exec(int fd) -{ - /* - * RTEMS Does not have a functional "execve" - * so technically this call does not do anything, - * but it doesnt hurt either. - */ - (void) fcntl(fd, F_SETFD, FD_CLOEXEC); -} -#ifndef __rtems__ -int -my_stat(const char *path, struct stat *stp) -{ - return (stat(path, stp)); -} - -int -my_open(const char *path, int flags, int mode) -{ - return (open(path, flags, mode)); -} - -int -my_remove(const char *path) -{ - return (remove(path)); -} - -int -my_rename(const char *path1, const char *path2) -{ - return (rename(path1, path2)); -} - -int -my_mkdir(const char *path, int mode) -{ - return (mkdir(path, mode)); -} - -char * -my_getcwd(char *buffer, int maxlen) -{ - return (getcwd(buffer, maxlen)); -} -#endif -int -set_non_blocking_mode(int fd) -{ - int ret = -1; - int flags; - - if ((flags = fcntl(fd, F_GETFL, 0)) == -1) { - DBG(("nonblock: fcntl(F_GETFL): %d", ERRNO)); - } else if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) { - DBG(("nonblock: fcntl(F_SETFL): %d", ERRNO)); - } else { - ret = 0; /* Success */ - } - - return (ret); -} - -#if !defined(NO_CGI) -int -spawn_process(struct conn *c, const char *prog, char *envblk, char **envp) -{ - return (-1); // RTEMS does not have subprocess support as standard. -} -#endif diff --git a/cpukit/shttpd/compat_rtems.h b/cpukit/shttpd/compat_rtems.h deleted file mode 100644 index aae550ca4b..0000000000 --- a/cpukit/shttpd/compat_rtems.h +++ /dev/null @@ -1,69 +0,0 @@ -/** - * @file rtems/rtems-shttpd.h - */ - -#ifndef _rtems_rtems_webserver_h -#define _rtems_rtems_webserver_h - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "shttpd.h" - -#include <rtems.h> -#include <sys/socket.h> -#include <sys/select.h> -#include <netinet/in.h> -#include <dirent.h> -#include <arpa/inet.h> - -/* RTEMS is an Real Time Embedded operating system, for operation in hardware. - It does not have SSL or CGI support, as it does not have dynamic library - loading or sub-processes. */ -#define EMBEDDED -#define NO_SSL -#define NO_CGI - -#define DIRSEP '/' -#define IS_DIRSEP_CHAR(c) ((c) == '/') -#define O_BINARY 0 -#define closesocket(a) close(a) -#define ERRNO errno - -/* RTEMS version is Thread Safe */ -#define InitializeCriticalSection(x) rtems_semaphore_create( \ - rtems_build_name('H','T','P','X'), \ - 1, /* Not Held Yet.*/ \ - RTEMS_FIFO | \ - RTEMS_BINARY_SEMAPHORE, \ - 0, \ - x); -#define EnterCriticalSection(x) rtems_semaphore_obtain(*(x),RTEMS_WAIT,RTEMS_NO_TIMEOUT) -#define LeaveCriticalSection(x) rtems_semaphore_release(*(x)) - - - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*rtems_shttpd_addpages)(struct shttpd_ctx *ctx); -typedef void (*rtems_shttpd_init)(void); - -rtems_status_code rtems_initialize_webserver(rtems_task_priority initial_priority, - size_t stack_size, - rtems_mode initial_modes, - rtems_attribute attribute_set, - rtems_shttpd_init init_callback, - rtems_shttpd_addpages addpages_callback, - char *webroot, - unsigned int port - ); -void rtems_terminate_webserver(void); -int rtems_webserver_ok(void); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/cpukit/shttpd/compat_unix.c b/cpukit/shttpd/compat_unix.c deleted file mode 100644 index 819361fd8c..0000000000 --- a/cpukit/shttpd/compat_unix.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> - * All rights reserved - * - * "THE BEER-WARE LICENSE" (Revision 42): - * Sergey Lyubka wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. - */ - -#include "defs.h" - -void -set_close_on_exec(int fd) -{ - (void) fcntl(fd, F_SETFD, FD_CLOEXEC); -} - -int -my_stat(const char *path, struct stat *stp) -{ - return (stat(path, stp)); -} - -int -my_open(const char *path, int flags, int mode) -{ - return (open(path, flags, mode)); -} - -int -my_remove(const char *path) -{ - return (remove(path)); -} - -int -my_rename(const char *path1, const char *path2) -{ - return (rename(path1, path2)); -} - -int -my_mkdir(const char *path, int mode) -{ - return (mkdir(path, mode)); -} - -char * -my_getcwd(char *buffer, int maxlen) -{ - return (getcwd(buffer, maxlen)); -} - -int -set_non_blocking_mode(int fd) -{ - int ret = -1; - int flags; - - if ((flags = fcntl(fd, F_GETFL, 0)) == -1) { - DBG(("nonblock: fcntl(F_GETFL): %d", ERRNO)); - } else if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) { - DBG(("nonblock: fcntl(F_SETFL): %d", ERRNO)); - } else { - ret = 0; /* Success */ - } - - return (ret); -} - -#ifndef NO_CGI -int -spawn_process(struct conn *c, const char *prog, char *envblk, - char *envp[], int sock, const char *dir) -{ - int ret; - pid_t pid; - - envblk = NULL; /* unused */ - - if ((pid = vfork()) == -1) { - - ret = -1; - elog(E_LOG, c, "redirect: fork: %s", strerror(errno)); - - } else if (pid == 0) { - - /* Child */ - (void) chdir(dir); - (void) dup2(sock, 0); - (void) dup2(sock, 1); - (void) closesocket(sock); - - /* If error file is specified, send errors there */ - if (c->ctx->error_log) - (void) dup2(fileno(c->ctx->error_log), 2); - - /* Execute CGI program */ - if (c->ctx->cgi_interpreter == NULL) { - (void) execle(prog, prog, NULL, envp); - elog(E_FATAL, c, "redirect: exec(%s)", prog); - } else { - (void) execle(c->ctx->cgi_interpreter, - c->ctx->cgi_interpreter, prog, NULL, envp); - elog(E_FATAL, c, "redirect: exec(%s %s)", - c->ctx->cgi_interpreter, prog); - } - - /* UNREACHED */ - ret = -1; - exit(EXIT_FAILURE); - - } else { - - /* Parent */ - ret = 0; - (void) closesocket(sock); - } - - return (ret); -} -#endif /* !NO_CGI */ diff --git a/cpukit/shttpd/compat_unix.h b/cpukit/shttpd/compat_unix.h deleted file mode 100644 index 67c935faaf..0000000000 --- a/cpukit/shttpd/compat_unix.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2004-2007 Sergey Lyubka <valenok@gmail.com> - * All rights reserved - * - * "THE BEER-WARE LICENSE" (Revision 42): - * Sergey Lyubka wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. - */ - -#include <sys/wait.h> -#include <sys/socket.h> -#include <sys/select.h> -#include <sys/mman.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <sys/time.h> - -#include <pwd.h> -#include <unistd.h> -#include <dirent.h> -#include <dlfcn.h> -#define SSL_LIB "libssl.so" -#define DIRSEP '/' -#define IS_DIRSEP_CHAR(c) ((c) == '/') -#define O_BINARY 0 -#define closesocket(a) close(a) -#define ERRNO errno -#define NO_GUI - -#define InitializeCriticalSection(x) /* FIXME UNIX version is not MT safe */ -#define EnterCriticalSection(x) -#define LeaveCriticalSection(x) diff --git a/cpukit/shttpd/compat_win32.c b/cpukit/shttpd/compat_win32.c deleted file mode 100644 index ee1221e7a2..0000000000 --- a/cpukit/shttpd/compat_win32.c +++ /dev/null @@ -1,923 +0,0 @@ -/* - * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> - * All rights reserved - * - * "THE BEER-WARE LICENSE" (Revision 42): - * Sergey Lyubka wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. - */ - -#include "defs.h" - -static const char *config_file = CONFIG; - -#if !defined(NO_GUI) - -static HICON hIcon; /* SHTTPD icon handle */ -HWND hLog; /* Log window */ - -/* - * Dialog box control IDs - */ -#define ID_GROUP 100 -#define ID_SAVE 101 -#define ID_STATUS 102 -#define ID_STATIC 103 -#define ID_SETTINGS 104 -#define ID_QUIT 105 -#define ID_TRAYICON 106 -#define ID_TIMER 107 -#define ID_ICON 108 -#define ID_ADVANCED 109 -#define ID_SHOWLOG 110 -#define ID_LOG 111 - -#define ID_USER 200 -#define ID_DELTA 1000 - -static void -run_server(void *param) -{ - struct shttpd_ctx *ctx = param; - - if (shttpd_listen(ctx, ctx->port) == -1) - elog(E_FATAL, NULL, "Cannot open socket on port %d", ctx->port); - - while (WaitForSingleObject(ctx->ev[0], 0) != WAIT_OBJECT_0) - shttpd_poll(ctx, 1000); - - SetEvent(ctx->ev[1]); - shttpd_fini(ctx); -} - -/* - * Save the configuration back into config file - */ -static void -save_config(HWND hDlg, FILE *fp) -{ - const struct opt *opt; - char text[FILENAME_MAX]; - int id; - - if (fp == NULL) - elog(E_FATAL, NULL, "save_config: cannot open %s", config_file); - - for (opt = options; opt->name != NULL; opt++) { - id = ID_USER + (opt - options); /* Control ID */ - - /* Do not save if the text is the same as default */ - - if (opt->flags & OPT_BOOL) - (void) fprintf(fp, "%s\t%d\n", - opt->name, IsDlgButtonChecked(hDlg, id)); - else if (GetDlgItemText(hDlg, id, text, sizeof(text)) != 0 && - (opt->def == NULL || strcmp(text, opt->def) != 0)) - (void) fprintf(fp, "%s\t%s\n", opt->name, text); - } - - (void) fclose(fp); -} - -static void -set_control_values(HWND hDlg, const struct shttpd_ctx *ctx) -{ - const struct opt *opt; - const union variant *v; - char buf[FILENAME_MAX]; - int id; - - for (opt = options; opt->name != NULL; opt++) { - id = ID_USER + (opt - options); - v = (union variant *) ((char *) ctx + opt->ofs); - if (opt->flags & OPT_BOOL) { - CheckDlgButton(hDlg, id, - v->v_int ? BST_CHECKED : BST_UNCHECKED); - } else if (opt->flags & OPT_INT) { - my_snprintf(buf, sizeof(buf), "%d", v->v_int); - SetDlgItemText(hDlg, id, buf); - } else { - SetDlgItemText(hDlg, id, v->v_str); - } - } - -} - -static BOOL CALLBACK -DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - static struct shttpd_ctx *ctx, **pctx; - HANDLE ev; - const struct opt *opt; - DWORD tid; - int id, up; - char text[256]; - - switch (msg) { - - case WM_CLOSE: - KillTimer(hDlg, ID_TIMER); - DestroyWindow(hDlg); - break; - - case WM_COMMAND: - switch (LOWORD(wParam)) { - case ID_SAVE: - EnableWindow(GetDlgItem(hDlg, ID_SAVE), FALSE); - save_config(hDlg, fopen(config_file, "w+")); - ev = ctx->ev[1]; - SetEvent(ctx->ev[0]); - WaitForSingleObject(ev, INFINITE); - *pctx = ctx = init_from_argc_argv(config_file, 0, NULL); - shttpd_listen(ctx, ctx->port); - _beginthread(run_server, 0, ctx); - EnableWindow(GetDlgItem(hDlg, ID_SAVE), TRUE); - - break; - } - - id = ID_USER + ID_DELTA; - for (opt = options; opt->name != NULL; opt++, id++) - if (LOWORD(wParam) == id) { - OPENFILENAME of; - BROWSEINFO bi; - char path[FILENAME_MAX] = ""; - - memset(&of, 0, sizeof(of)); - of.lStructSize = sizeof(of); - of.hwndOwner = (HWND) hDlg; - of.lpstrFile = path; - of.nMaxFile = sizeof(path); - of.lpstrInitialDir = ctx->document_root; - of.Flags = OFN_CREATEPROMPT | OFN_NOCHANGEDIR; - - memset(&bi, 0, sizeof(bi)); - bi.hwndOwner = (HWND) hDlg; - bi.lpszTitle = "Choose WWW root directory:"; - bi.ulFlags = BIF_RETURNONLYFSDIRS; - - if (opt->flags & OPT_DIR) - SHGetPathFromIDList( - SHBrowseForFolder(&bi), path); - else - GetOpenFileName(&of); - - if (path[0] != '\0') - SetWindowText(GetDlgItem(hDlg, - id - ID_DELTA), path); - } - - break; - - case WM_INITDIALOG: - pctx = (struct shttpd_ctx **) lParam; - ctx = *pctx; - SendMessage(hDlg,WM_SETICON,(WPARAM)ICON_SMALL,(LPARAM)hIcon); - SendMessage(hDlg,WM_SETICON,(WPARAM)ICON_BIG,(LPARAM)hIcon); - SetWindowText(hDlg, "SHTTPD settings"); - SetFocus(GetDlgItem(hDlg, ID_SAVE)); - set_control_values(hDlg, ctx); - break; - default: - break; - } - - return FALSE; -} - -static void * -align(void *ptr, DWORD alig) -{ - ULONG ul = (ULONG) ptr; - - ul += alig; - ul &= ~alig; - - return ((void *) ul); -} - - -static void -add_control(unsigned char **mem, DLGTEMPLATE *dia, WORD type, DWORD id, - DWORD style, WORD x, WORD y, WORD cx, WORD cy, const char *caption) -{ - DLGITEMTEMPLATE *tp; - LPWORD p; - - dia->cdit++; - - *mem = align(*mem, 3); - tp = (DLGITEMTEMPLATE *) *mem; - - tp->id = (WORD)id; - tp->style = style; - tp->dwExtendedStyle = 0; - tp->x = x; - tp->y = y; - tp->cx = cx; - tp->cy = cy; - - p = align(*mem + sizeof(*tp), 1); - *p++ = 0xffff; - *p++ = type; - - while (*caption != '\0') - *p++ = (WCHAR) *caption++; - *p++ = 0; - p = align(p, 1); - - *p++ = 0; - *mem = (unsigned char *) p; -} - -static void -show_settings_dialog(struct shttpd_ctx **ctxp) -{ -#define HEIGHT 15 -#define WIDTH 400 -#define LABEL_WIDTH 70 - - unsigned char mem[4096], *p; - DWORD style; - DLGTEMPLATE *dia = (DLGTEMPLATE *) mem; - WORD cl, x, y, width, nelems = 0; - const struct opt *opt; - static int guard; - - static struct { - DLGTEMPLATE template; /* 18 bytes */ - WORD menu, class; - wchar_t caption[1]; - WORD fontsiz; - wchar_t fontface[7]; - } dialog_header = {{WS_CAPTION | WS_POPUP | WS_SYSMENU | WS_VISIBLE | - DS_SETFONT | WS_DLGFRAME, WS_EX_TOOLWINDOW, - 0, 200, 200, WIDTH, 0}, 0, 0, L"", 8, L"Tahoma"}; - - if (guard == 0) - guard++; - else - return; - - (void) memset(mem, 0, sizeof(mem)); - (void) memcpy(mem, &dialog_header, sizeof(dialog_header)); - p = mem + sizeof(dialog_header); - - for (opt = options; opt->name != NULL; opt++) { - - style = WS_CHILD | WS_VISIBLE | WS_TABSTOP; - x = 10 + (WIDTH / 2) * (nelems % 2); - y = (nelems/2 + 1) * HEIGHT + 5; - width = WIDTH / 2 - 20 - LABEL_WIDTH; - if (opt->flags & OPT_INT) { - style |= ES_NUMBER; - cl = 0x81; - style |= WS_BORDER | ES_AUTOHSCROLL; - } else if (opt->flags & OPT_BOOL) { - cl = 0x80; - style |= BS_AUTOCHECKBOX; - } else if (opt->flags & (OPT_DIR | OPT_FILE)) { - style |= WS_BORDER | ES_AUTOHSCROLL; - width -= 20; - cl = 0x81; - add_control(&p, dia, 0x80, - ID_USER + ID_DELTA + (opt - options), - WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, - (WORD) (x + width + LABEL_WIDTH + 5), - y, 15, 12, "..."); - } else { - cl = 0x81; - style |= WS_BORDER | ES_AUTOHSCROLL; - } - add_control(&p, dia, 0x82, ID_STATIC, WS_VISIBLE | WS_CHILD, - x, y, LABEL_WIDTH, HEIGHT, opt->desc); - add_control(&p, dia, cl, ID_USER + (opt - options), style, - (WORD) (x + LABEL_WIDTH), y, width, 12, ""); - nelems++; - } - - y = (WORD) (((nelems + 1)/2 + 1) * HEIGHT + 5); - add_control(&p, dia, 0x80, ID_GROUP, WS_CHILD | WS_VISIBLE | - BS_GROUPBOX, 5, 5, WIDTH - 10, y, "Settings"); - y += 10; - add_control(&p, dia, 0x80, ID_SAVE, - WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP, - WIDTH - 70, y, 65, 12, "Save Settings"); -#if 0 - add_control(&p, dia, 0x80, ID_ADVANCED, - WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP, - WIDTH - 190, y, 110, 12, "Show Advanced Settings >>"); -#endif - add_control(&p, dia, 0x82, ID_STATIC, - WS_CHILD | WS_VISIBLE | WS_DISABLED, - 5, y, 180, 12,"SHTTPD v." VERSION - " (http://shttpd.sourceforge.net)"); - - dia->cy = ((nelems + 1)/2 + 1) * HEIGHT + 30; - DialogBoxIndirectParam(NULL, dia, NULL, DlgProc, (LPARAM) ctxp); - guard--; -} - -static BOOL CALLBACK -LogProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - static struct shttpd_ctx *ctx; - static HWND hStatus; - HWND hEdit; - RECT rect, rect2, rect3, rect4; - int len, up, widths[] = {120, 220, 330, 460, -1}; - char text[256], buf[1024 * 64]; - - switch (msg) { - - case WM_CLOSE: - KillTimer(hDlg, ID_TIMER); - DestroyWindow(hDlg); - break; - - case WM_APP: - hEdit = GetDlgItem(hDlg, ID_LOG); - len = GetWindowText(hEdit, buf, sizeof(buf)); - if (len > sizeof(buf) * 4 / 5) - len = sizeof(buf) * 4 / 5; - my_snprintf(buf + len, sizeof(buf) - len, - "%s\r\n", (char *) lParam); - SetWindowText(hEdit, buf); - SendMessage(hEdit, WM_VSCROLL, SB_BOTTOM, 0); - break; - - case WM_TIMER: - /* Print statistics on a status bar */ - up = current_time - ctx->start_time; - (void) my_snprintf(text, sizeof(text), - " Up: %3d h %2d min %2d sec", - up / 3600, up / 60 % 60, up % 60); - SendMessage(hStatus, SB_SETTEXT, 0, (LPARAM) text); - (void) my_snprintf(text, sizeof(text), - " Requests: %u", ctx->nrequests); - SendMessage(hStatus, SB_SETTEXT, 1, (LPARAM) text); - (void) my_snprintf(text, sizeof(text), - " Sent: %4.2f Mb", (double) ctx->out / 1048576); - SendMessage(hStatus, SB_SETTEXT, 2, (LPARAM) text); - (void) my_snprintf(text, sizeof(text), - " Received: %4.2f Mb", (double) ctx->in / 1048576); - SendMessage(hStatus, SB_SETTEXT, 3, (LPARAM) text); - break; - - case WM_INITDIALOG: - ctx = (struct shttpd_ctx *) lParam; - SendMessage(hDlg,WM_SETICON,(WPARAM)ICON_SMALL,(LPARAM)hIcon); - SendMessage(hDlg,WM_SETICON,(WPARAM)ICON_BIG,(LPARAM)hIcon); - hStatus = CreateStatusWindow(WS_CHILD | WS_VISIBLE, - "", hDlg, ID_STATUS); - SendMessage(hStatus, SB_SETPARTS, 5, (LPARAM) widths); - SendMessage(hStatus, SB_SETTEXT, 4, (LPARAM) " Running"); - SetWindowText(hDlg, "SHTTPD web server log"); - SetTimer(hDlg, ID_TIMER, 1000, NULL); - GetWindowRect(GetDesktopWindow(), &rect3); - GetWindowRect(hDlg, &rect4); - GetClientRect(hDlg, &rect); - GetClientRect(hStatus, &rect2); - SetWindowPos(GetDlgItem(hDlg, ID_LOG), 0, - 0, 0, rect.right, rect.bottom - rect2.bottom, 0); - SetWindowPos(hDlg, HWND_TOPMOST, - rect3.right - (rect4.right - rect4.left), - rect3.bottom - (rect4.bottom - rect4.top) - 30, - 0, 0, SWP_NOSIZE); - SetFocus(hStatus); - SendMessage(hDlg, WM_TIMER, 0, 0); - hLog = hDlg; - break; - default: - break; - } - - - return (FALSE); -} - -static void -show_log_window(struct shttpd_ctx *ctx) -{ - unsigned char mem[4096], *p; - DWORD style; - DLGTEMPLATE *dia = (DLGTEMPLATE *) mem; - WORD cl, x, y, width, nelems = 0; - - static struct { - DLGTEMPLATE template; /* 18 bytes */ - WORD menu, class; - wchar_t caption[1]; - WORD fontsiz; - wchar_t fontface[7]; - } dialog_header = {{WS_CAPTION | WS_POPUP | WS_VISIBLE | WS_SYSMENU | - DS_SETFONT | WS_DLGFRAME, WS_EX_TOOLWINDOW, - 0, 200, 200, 400, 100}, 0, 0, L"", 8, L"Tahoma"}; - - if (hLog != NULL) - return; - - (void) memset(mem, 0, sizeof(mem)); - (void) memcpy(mem, &dialog_header, sizeof(dialog_header)); - p = mem + sizeof(dialog_header); - - add_control(&p, dia, 0x81, ID_LOG, WS_CHILD | WS_VISIBLE | - WS_BORDER | WS_VSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | - ES_READONLY, 5, 5, WIDTH - 10, 60, ""); - - DialogBoxIndirectParam(NULL, dia, NULL, LogProc, (LPARAM) ctx); - - hLog = NULL; -} - -static LRESULT CALLBACK -WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - static NOTIFYICONDATA ni; - static struct shttpd_ctx *ctx; - DWORD tid; /* Thread ID */ - HMENU hMenu; - POINT pt; - - switch (msg) { - case WM_CREATE: - ctx = ((CREATESTRUCT *) lParam)->lpCreateParams; - memset(&ni, 0, sizeof(ni)); - ni.cbSize = sizeof(ni); - ni.uID = ID_TRAYICON; - ni.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; - ni.hIcon = hIcon; - ni.hWnd = hWnd; - my_snprintf(ni.szTip, sizeof(ni.szTip), "SHTTPD web server"); - ni.uCallbackMessage = WM_USER; - Shell_NotifyIcon(NIM_ADD, &ni); - ctx->ev[0] = CreateEvent(0, TRUE, FALSE, 0); - ctx->ev[1] = CreateEvent(0, TRUE, FALSE, 0); - _beginthread(run_server, 0, ctx); - break; - case WM_CLOSE: - Shell_NotifyIcon(NIM_DELETE, &ni); - PostQuitMessage(0); - break; - case WM_COMMAND: - switch (LOWORD(wParam)) { - case ID_SETTINGS: - show_settings_dialog(&ctx); - break; - case ID_QUIT: - SendMessage(hWnd, WM_CLOSE, wParam, lParam); - PostQuitMessage(0); - break; - case ID_SHOWLOG: - show_log_window(ctx); - break; - } - break; - case WM_USER: - switch (lParam) { - case WM_RBUTTONUP: - case WM_LBUTTONUP: - case WM_LBUTTONDBLCLK: - hMenu = CreatePopupMenu(); - AppendMenu(hMenu, 0, ID_SETTINGS, "Settings"); - AppendMenu(hMenu, 0, ID_SHOWLOG, "Show Log"); - AppendMenu(hMenu, 0, ID_QUIT, "Exit SHTTPD"); - GetCursorPos(&pt); - TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, hWnd, NULL); - DestroyMenu(hMenu); - break; - } - break; - } - - return (DefWindowProc(hWnd, msg, wParam, lParam)); -} - -int WINAPI -WinMain(HINSTANCE h, HINSTANCE prev, char *cmdline, int show) -{ - struct shttpd_ctx *ctx; - WNDCLASS cls; - HWND hWnd; - MSG msg; - - ctx = init_from_argc_argv(config_file, 0, NULL); - (void) memset(&cls, 0, sizeof(cls)); - - hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(ID_ICON)); - if (hIcon == NULL) - hIcon = LoadIcon(NULL, IDI_APPLICATION); - cls.lpfnWndProc = (WNDPROC) WindowProc; - cls.hIcon = hIcon; - cls.lpszClassName = "shttpd v." VERSION; - - if (!RegisterClass(&cls)) - elog(E_FATAL, NULL, "RegisterClass: %d", ERRNO); - else if ((hWnd = CreateWindow(cls.lpszClassName, "",WS_OVERLAPPEDWINDOW, - 0, 0, 0, 0, NULL, NULL, NULL, ctx)) == NULL) - elog(E_FATAL, NULL, "CreateWindow: %d", ERRNO); - - while (GetMessage(&msg, (HWND) NULL, 0, 0)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - return (0); -} -#endif /* NO_GUI */ - -static void -fix_directory_separators(char *path) -{ - for (; *path != '\0'; path++) { - if (*path == '/') - *path = '\\'; - if (*path == '\\') - while (path[1] == '\\' || path[1] == '/') - (void) memmove(path + 1, - path + 2, strlen(path + 2) + 1); - } -} - -int -my_open(const char *path, int flags, int mode) -{ - char buf[FILENAME_MAX]; - wchar_t wbuf[FILENAME_MAX]; - - my_strlcpy(buf, path, sizeof(buf)); - fix_directory_separators(buf); - MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf)); - - return (_wopen(wbuf, flags)); -} - -int -my_stat(const char *path, struct stat *stp) -{ - char buf[FILENAME_MAX], *p; - wchar_t wbuf[FILENAME_MAX]; - - my_strlcpy(buf, path, sizeof(buf)); - fix_directory_separators(buf); - - p = buf + strlen(buf) - 1; - while (p > buf && *p == '\\' && p[-1] != ':') - *p-- = '\0'; - - MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf)); - - return (_wstat(wbuf, (struct _stat *) stp)); -} - -int -my_remove(const char *path) -{ - char buf[FILENAME_MAX]; - wchar_t wbuf[FILENAME_MAX]; - - my_strlcpy(buf, path, sizeof(buf)); - fix_directory_separators(buf); - - MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf)); - - return (_wremove(wbuf)); -} - -int -my_rename(const char *path1, const char *path2) -{ - char buf1[FILENAME_MAX]; - char buf2[FILENAME_MAX]; - wchar_t wbuf1[FILENAME_MAX]; - wchar_t wbuf2[FILENAME_MAX]; - - my_strlcpy(buf1, path1, sizeof(buf1)); - my_strlcpy(buf2, path2, sizeof(buf2)); - fix_directory_separators(buf1); - fix_directory_separators(buf2); - - MultiByteToWideChar(CP_UTF8, 0, buf1, -1, wbuf1, sizeof(wbuf1)); - MultiByteToWideChar(CP_UTF8, 0, buf2, -1, wbuf2, sizeof(wbuf2)); - - return (_wrename(wbuf1, wbuf2)); -} - -int -my_mkdir(const char *path, int mode) -{ - char buf[FILENAME_MAX]; - wchar_t wbuf[FILENAME_MAX]; - - my_strlcpy(buf, path, sizeof(buf)); - fix_directory_separators(buf); - - MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf)); - - return (_wmkdir(wbuf)); -} - -static char * -wide_to_utf8(const wchar_t *str) -{ - char *buf = NULL; - if (str) { - int nchar = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL); - if (nchar > 0) { - buf = malloc(nchar); - if (!buf) - errno = ENOMEM; - else if (!WideCharToMultiByte(CP_UTF8, 0, str, -1, buf, nchar, NULL, NULL)) { - free(buf); - buf = NULL; - errno = EINVAL; - } - } else - errno = EINVAL; - } else - errno = EINVAL; - return buf; -} - -char * -my_getcwd(char *buffer, int maxlen) -{ - char *result = NULL; - wchar_t *wbuffer, *wresult; - - if (buffer) { - /* User-supplied buffer */ - wbuffer = malloc(maxlen * sizeof(wchar_t)); - if (wbuffer == NULL) - return NULL; - } else - /* Dynamically allocated buffer */ - wbuffer = NULL; - wresult = _wgetcwd(wbuffer, maxlen); - if (wresult) { - int err = errno; - if (buffer) { - /* User-supplied buffer */ - int n = WideCharToMultiByte(CP_UTF8, 0, wresult, -1, buffer, maxlen, NULL, NULL); - if (n == 0) - err = ERANGE; - free(wbuffer); - result = buffer; - } else { - /* Buffer allocated by _wgetcwd() */ - result = wide_to_utf8(wresult); - err = errno; - free(wresult); - } - errno = err; - } - return result; -} - -DIR * -opendir(const char *name) -{ - DIR *dir = NULL; - char path[FILENAME_MAX]; - wchar_t wpath[FILENAME_MAX]; - - if (name == NULL || name[0] == '\0') { - errno = EINVAL; - } else if ((dir = malloc(sizeof(*dir))) == NULL) { - errno = ENOMEM; - } else { - my_snprintf(path, sizeof(path), "%s/*", name); - fix_directory_separators(path); - MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, sizeof(wpath)); - dir->handle = FindFirstFileW(wpath, &dir->info); - - if (dir->handle != INVALID_HANDLE_VALUE) { - dir->result.d_name[0] = '\0'; - } else { - free(dir); - dir = NULL; - } - } - - return (dir); -} - -int -closedir(DIR *dir) -{ - int result = -1; - - if (dir != NULL) { - if (dir->handle != INVALID_HANDLE_VALUE) - result = FindClose(dir->handle) ? 0 : -1; - - free(dir); - } - - if (result == -1) - errno = EBADF; - - return (result); -} - -struct dirent * -readdir(DIR *dir) -{ - struct dirent *result = 0; - - if (dir && dir->handle != INVALID_HANDLE_VALUE) { - if(!dir->result.d_name || - FindNextFileW(dir->handle, &dir->info)) { - result = &dir->result; - - WideCharToMultiByte(CP_UTF8, 0, dir->info.cFileName, - -1, result->d_name, - sizeof(result->d_name), NULL, NULL); - } - } else { - errno = EBADF; - } - - return (result); -} - -int -set_non_blocking_mode(int fd) -{ - unsigned long on = 1; - - return (ioctlsocket(fd, FIONBIO, &on)); -} - -void -set_close_on_exec(int fd) -{ - fd = 0; /* Do nothing. There is no FD_CLOEXEC on Windows */ -} - -#if !defined(NO_CGI) - -struct threadparam { - SOCKET s; - HANDLE hPipe; - big_int_t content_len; -}; - -/* - * Thread function that reads POST data from the socket pair - * and writes it to the CGI process. - */ -static void//DWORD WINAPI -stdoutput(void *arg) -{ - struct threadparam *tp = arg; - int n, sent, stop = 0; - big_int_t total = 0; - DWORD k; - char buf[BUFSIZ]; - size_t max_recv; - - max_recv = min(sizeof(buf), tp->content_len - total); - while (!stop && max_recv > 0 && (n = recv(tp->s, buf, max_recv, 0)) > 0) { - for (sent = 0; !stop && sent < n; sent += k) - if (!WriteFile(tp->hPipe, buf + sent, n - sent, &k, 0)) - stop++; - total += n; - max_recv = min(sizeof(buf), tp->content_len - total); - } - - CloseHandle(tp->hPipe); /* Suppose we have POSTed everything */ - free(tp); -} - -/* - * Thread function that reads CGI output and pushes it to the socket pair. - */ -static void -stdinput(void *arg) -{ - struct threadparam *tp = arg; - static int ntotal; - int k, stop = 0; - DWORD n, sent; - char buf[BUFSIZ]; - - while (!stop && ReadFile(tp->hPipe, buf, sizeof(buf), &n, NULL)) { - ntotal += n; - for (sent = 0; !stop && sent < n; sent += k) - if ((k = send(tp->s, buf + sent, n - sent, 0)) <= 0) - stop++; - } - CloseHandle(tp->hPipe); - - /* - * Windows is a piece of crap. When this thread closes its end - * of the socket pair, the other end (get_cgi() function) may loose - * some data. I presume, this happens if get_cgi() is not fast enough, - * and the data written by this end does not "push-ed" to the other - * end socket buffer. So after closesocket() the remaining data is - * gone. If I put shutdown() before closesocket(), that seems to - * fix the problem, but I am not sure this is the right fix. - * XXX (submitted by James Marshall) we do not do shutdown() on UNIX. - * If fork() is called from user callback, shutdown() messes up things. - */ - shutdown(tp->s, 2); - - closesocket(tp->s); - free(tp); - - _endthread(); -} - -static void -spawn_stdio_thread(int sock, HANDLE hPipe, void (*func)(void *), - big_int_t content_len) -{ - struct threadparam *tp; - DWORD tid; - - tp = malloc(sizeof(*tp)); - assert(tp != NULL); - - tp->s = sock; - tp->hPipe = hPipe; - tp->content_len = content_len; - _beginthread(func, 0, tp); -} - -int -spawn_process(struct conn *c, const char *prog, char *envblk, - char *envp[], int sock, const char *dir) -{ - HANDLE a[2], b[2], h[2], me; - DWORD flags; - char *p, cmdline[FILENAME_MAX], line[FILENAME_MAX]; - FILE *fp; - STARTUPINFOA si; - PROCESS_INFORMATION pi; - - me = GetCurrentProcess(); - flags = DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS; - - /* FIXME add error checking code here */ - CreatePipe(&a[0], &a[1], NULL, 0); - CreatePipe(&b[0], &b[1], NULL, 0); - DuplicateHandle(me, a[0], me, &h[0], 0, TRUE, flags); - DuplicateHandle(me, b[1], me, &h[1], 0, TRUE, flags); - - (void) memset(&si, 0, sizeof(si)); - (void) memset(&pi, 0, sizeof(pi)); - - /* XXX redirect CGI errors to the error log file */ - si.cb = sizeof(si); - si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; - si.wShowWindow = SW_HIDE; - si.hStdOutput = si.hStdError = h[1]; - si.hStdInput = h[0]; - - /* If CGI file is a script, try to read the interpreter line */ - if (c->ctx->cgi_interpreter == NULL) { - if ((fp = fopen(prog, "r")) != NULL) { - (void) fgets(line, sizeof(line), fp); - if (memcmp(line, "#!", 2) != 0) - line[2] = '\0'; - /* Trim whitespaces from interpreter name */ - for (p = &line[strlen(line) - 1]; p > line && - isspace(*p); p--) - *p = '\0'; - (void) fclose(fp); - } - (void) my_snprintf(cmdline, sizeof(cmdline), "%s%s%s", - line + 2, line[2] == '\0' ? "" : " ", prog); - } else { - (void) my_snprintf(cmdline, sizeof(cmdline), "%s %s", - c->ctx->cgi_interpreter, prog); - } - - (void) my_snprintf(line, sizeof(line), "%s", dir); - fix_directory_separators(line); - fix_directory_separators(cmdline); - - /* - * Spawn reader & writer threads before we create CGI process. - * Otherwise CGI process may die too quickly, loosing the data - */ - spawn_stdio_thread(sock, b[0], stdinput, 0); - spawn_stdio_thread(sock, a[1], stdoutput, c->rem.content_len); - - if (CreateProcessA(NULL, cmdline, NULL, NULL, TRUE, - CREATE_NEW_PROCESS_GROUP, envblk, line, &si, &pi) == 0) { - elog(E_LOG, c,"redirect: CreateProcess(%s): %d",cmdline,ERRNO); - return (-1); - } else { - CloseHandle(h[0]); - CloseHandle(h[1]); - CloseHandle(pi.hThread); - CloseHandle(pi.hProcess); - } - - return (0); -} - -#endif /* !NO_CGI */ diff --git a/cpukit/shttpd/compat_win32.h b/cpukit/shttpd/compat_win32.h deleted file mode 100644 index b45b713048..0000000000 --- a/cpukit/shttpd/compat_win32.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2004-2007 Sergey Lyubka <valenok@gmail.com> - * All rights reserved - * - * "THE BEER-WARE LICENSE" (Revision 42): - * Sergey Lyubka wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. - */ - -/* Tip from Justin Maximilian, suppress errors from winsock2.h */ -#define _WINSOCKAPI_ - -#include <windows.h> -#include <winsock2.h> -#include <commctrl.h> -#include <winnls.h> -#include <shlobj.h> -#include <shellapi.h> - -#ifndef _WIN32_WCE - -#ifdef _MSC_VER /* pragmas not valid on MinGW */ -#pragma comment(lib,"ws2_32") -#pragma comment(lib,"user32") -#pragma comment(lib,"comctl32") -#pragma comment(lib,"comdlg32") -#pragma comment(lib,"shell32") -#ifdef NO_GUI -#pragma comment(linker,"/subsystem:console") -#else -#pragma comment(linker,"/subsystem:windows") -#endif /* NO_GUI */ -#endif /* _MSC_VER */ -#include <process.h> -#include <direct.h> -#include <io.h> - -#else /* _WIN32_WCE */ - -/* Windows CE-specific definitions */ -#define NO_CGI /* WinCE has no pipes */ -#define NO_GUI /* temporarily until it is fixed */ -#pragma comment(lib,"ws2") -/* WinCE has both Unicode and ANSI versions of GetProcAddress */ -#undef GetProcAddress -#define GetProcAddress GetProcAddressA -#include "compat_wince.h" - -#endif /* _WIN32_WCE */ - -#define ERRNO GetLastError() -#define NO_SOCKLEN_T -#define SSL_LIB L"libssl32.dll" -#define DIRSEP '\\' -#define IS_DIRSEP_CHAR(c) ((c) == '/' || (c) == '\\') -#define O_NONBLOCK 0 -#define EWOULDBLOCK WSAEWOULDBLOCK -#define snprintf _snprintf -#define vsnprintf _vsnprintf -#define mkdir(x,y) _mkdir(x) -#define dlopen(x,y) LoadLibraryW(x) -#define dlsym(x,y) (void *) GetProcAddress(x,y) -#define _POSIX_ - -#ifdef __LCC__ -#include <stdint.h> -#endif /* __LCC__ */ - -#ifdef _MSC_VER /* MinGW already has these */ -typedef unsigned int uint32_t; -typedef unsigned short uint16_t; -typedef __int64 uint64_t; -#define S_ISDIR(x) ((x) & _S_IFDIR) -#endif /* _MSC_VER */ - -/* - * POSIX dirent interface - */ -struct dirent { - char d_name[FILENAME_MAX]; -}; - -typedef struct DIR { - HANDLE handle; - WIN32_FIND_DATAW info; - struct dirent result; - char *name; -} DIR; - -extern DIR *opendir(const char *name); -extern int closedir(DIR *dir); -extern struct dirent *readdir(DIR *dir); diff --git a/cpukit/shttpd/compat_wince.c b/cpukit/shttpd/compat_wince.c deleted file mode 100644 index edf8da21fa..0000000000 --- a/cpukit/shttpd/compat_wince.c +++ /dev/null @@ -1,1593 +0,0 @@ -/* - vi:ts=8:sw=8:noet - * Copyright (c) 2006 Luke Dunstan <infidel@users.sourceforge.net> - * Partly based on code by David Kashtan, Validus Medical Systems - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -/* - * This file provides various functions that are available on desktop Windows - * but not on Windows CE - */ - -#ifdef _MSC_VER -/* Level 4 warnings caused by windows.h */ -#pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int -#pragma warning(disable : 4115) // named type definition in parentheses -#pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union -#pragma warning(disable : 4514) // unreferenced inline function has been removed -#pragma warning(disable : 4244) // conversion from 'int ' to 'unsigned short ', possible loss of data -#pragma warning(disable : 4100) // unreferenced formal parameter -#endif - -#include <windows.h> -#include <stdlib.h> - -#include "compat_wince.h" - - -static WCHAR *to_wide_string(LPCSTR pStr) -{ - int nwide; - WCHAR *buf; - - if(pStr == NULL) - return NULL; - nwide = MultiByteToWideChar(CP_ACP, 0, pStr, -1, NULL, 0); - if(nwide == 0) - return NULL; - buf = malloc(nwide * sizeof(WCHAR)); - if(buf == NULL) { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return NULL; - } - if(MultiByteToWideChar(CP_ACP, 0, pStr, -1, buf, nwide) == 0) { - free(buf); - return NULL; - } - return buf; -} - -FILE *fdopen(int handle, const char *mode) -{ - WCHAR *wmode = to_wide_string(mode); - FILE *result; - - if(wmode != NULL) - result = _wfdopen((void *)handle, wmode); - else - result = NULL; - free(wmode); - return result; -} - -/* - * Time conversion constants - */ -#define FT_EPOCH (116444736000000000i64) -#define FT_TICKS (10000000i64) - - /* - * Convert a FILETIME to a time_t - */ -static time_t convert_FILETIME_to_time_t(FILETIME *File_Time) -{ - __int64 Temp; - - /* - * Convert the FILETIME structure to 100nSecs since 1601 (as a 64-bit value) - */ - Temp = (((__int64)File_Time->dwHighDateTime) << 32) + (__int64)File_Time->dwLowDateTime; - /* - * Convert to seconds from 1970 - */ - return((time_t)((Temp - FT_EPOCH) / FT_TICKS)); -} - -/* - * Convert a FILETIME to a tm structure - */ -static struct tm *Convert_FILETIME_To_tm(FILETIME *File_Time) -{ - SYSTEMTIME System_Time; - static struct tm tm = {0}; - static const short Day_Of_Year_By_Month[12] = {(short)(0), - (short)(31), - (short)(31 + 28), - (short)(31 + 28 + 31), - (short)(31 + 28 + 31 + 30), - (short)(31 + 28 + 31 + 30 + 31), - (short)(31 + 28 + 31 + 30 + 31 + 30), - (short)(31 + 28 + 31 + 30 + 31 + 30 + 31), - (short)(31 + 28 + 31 + 30 + 31 + 30 + 31 + 31), - (short)(31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30), - (short)(31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31), - (short)(31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30)}; - - - /* - * Turn the FILETIME into a SYSTEMTIME - */ - FileTimeToSystemTime(File_Time, &System_Time); - /* - * Use SYSTEMTIME to fill in the tm structure - */ - tm.tm_sec = System_Time.wSecond; - tm.tm_min = System_Time.wMinute; - tm.tm_hour = System_Time.wHour; - tm.tm_mday = System_Time.wDay; - tm.tm_mon = System_Time.wMonth - 1; - tm.tm_year = System_Time.wYear - 1900; - tm.tm_wday = System_Time.wDayOfWeek; - tm.tm_yday = Day_Of_Year_By_Month[tm.tm_mon] + tm.tm_mday - 1; - if (tm.tm_mon >= 2) { - /* - * Check for leap year (every 4 years but not every 100 years but every 400 years) - */ - if ((System_Time.wYear % 4) == 0) { - /* - * It Is a 4th year - */ - if ((System_Time.wYear % 100) == 0) { - /* - * It is a 100th year - */ - if ((System_Time.wYear % 400) == 0) { - /* - * It is a 400th year: It is a leap year - */ - tm.tm_yday++; - } - } else { - /* - * It is not a 100th year: It is a leap year - */ - tm.tm_yday++; - } - } - } - return(&tm); -} - -/* - * Convert a time_t to a FILETIME - */ -static void Convert_time_t_To_FILETIME(time_t Time, FILETIME *File_Time) -{ - __int64 Temp; - - /* - * Use 64-bit calculation to convert seconds since 1970 to - * 100nSecs since 1601 - */ - Temp = ((__int64)Time * FT_TICKS) + FT_EPOCH; - /* - * Put it into the FILETIME structure - */ - File_Time->dwLowDateTime = (DWORD)Temp; - File_Time->dwHighDateTime = (DWORD)(Temp >> 32); -} - -/* - * Convert a tm structure to a FILETIME - */ -static FILETIME *Convert_tm_To_FILETIME(struct tm *tm) -{ - SYSTEMTIME System_Time; - static FILETIME File_Time = {0}; - - /* - * Use the tm structure to fill in a SYSTEM - */ - System_Time.wYear = tm->tm_year + 1900; - System_Time.wMonth = tm->tm_mon + 1; - System_Time.wDayOfWeek = tm->tm_wday; - System_Time.wDay = tm->tm_mday; - System_Time.wHour = tm->tm_hour; - System_Time.wMinute = tm->tm_min; - System_Time.wSecond = tm->tm_sec; - System_Time.wMilliseconds = 0; - /* - * Convert it to a FILETIME and return it - */ - SystemTimeToFileTime(&System_Time, &File_Time); - return(&File_Time); -} - - -/************************************************************************/ -/* */ -/* Errno emulation: There is no errno on Windows/CE and we need */ -/* to make it per-thread. So we have a function */ -/* that returns a pointer to the errno for the */ -/* current thread. */ -/* */ -/* If there is ONLY the main thread then we can */ -/* quickly return some static storage. */ -/* */ -/* If we have multiple threads running, we use */ -/* Thread-Local Storage to hold the pointer */ -/* */ -/************************************************************************/ - -/* - * Function pointer for returning errno pointer - */ -static int *Initialize_Errno(void); -int *(*__WinCE_Errno_Pointer_Function)(void) = Initialize_Errno; - -/* - * Static errno storage for the main thread - */ -static int Errno_Storage = 0; - -/* - * Thread-Local storage slot for errno - */ -static int TLS_Errno_Slot = 0xffffffff; - -/* - * Number of threads we have running and critical section protection - * for manipulating it - */ -static int Number_Of_Threads = 0; -static CRITICAL_SECTION Number_Of_Threads_Critical_Section; - -/* - * For the main thread only -- return the errno pointer - */ -static int *Get_Main_Thread_Errno(void) -{ - return &Errno_Storage; -} - -/* - * When there is more than one thread -- return the errno pointer - */ -static int *Get_Thread_Errno(void) -{ - return (int *)TlsGetValue(TLS_Errno_Slot); -} - -/* - * Initialize a thread's errno - */ -static void Initialize_Thread_Errno(int *Errno_Pointer) -{ - /* - * Make sure we have a slot - */ - if (TLS_Errno_Slot == 0xffffffff) { - /* - * No: Get one - */ - TLS_Errno_Slot = (int)TlsAlloc(); - if (TLS_Errno_Slot == 0xffffffff) ExitProcess(3); - } - /* - * We can safely check for 0 threads, because - * only the main thread will be initializing - * at this point. Make sure the critical - * section that protects the number of threads - * is initialized - */ - if (Number_Of_Threads == 0) - InitializeCriticalSection(&Number_Of_Threads_Critical_Section); - /* - * Store the errno pointer - */ - if (TlsSetValue(TLS_Errno_Slot, (LPVOID)Errno_Pointer) == 0) ExitProcess(3); - /* - * Bump the number of threads - */ - EnterCriticalSection(&Number_Of_Threads_Critical_Section); - Number_Of_Threads++; - if (Number_Of_Threads > 1) { - /* - * We have threads other than the main thread: - * Use thread-local storage - */ - __WinCE_Errno_Pointer_Function = Get_Thread_Errno; - } - LeaveCriticalSection(&Number_Of_Threads_Critical_Section); -} - -/* - * Initialize errno emulation on Windows/CE (Main thread) - */ -static int *Initialize_Errno(void) -{ - /* - * Initialize the main thread's errno in thread-local storage - */ - Initialize_Thread_Errno(&Errno_Storage); - /* - * Set the errno function to be the one that returns the - * main thread's errno - */ - __WinCE_Errno_Pointer_Function = Get_Main_Thread_Errno; - /* - * Return the main thread's errno - */ - return &Errno_Storage; -} - -/* - * Initialize errno emulation on Windows/CE (New thread) - */ -void __WinCE_Errno_New_Thread(int *Errno_Pointer) -{ - Initialize_Thread_Errno(Errno_Pointer); -} - -/* - * Note that a thread has exited - */ -void __WinCE_Errno_Thread_Exit(void) -{ - /* - * Decrease the number of threads - */ - EnterCriticalSection(&Number_Of_Threads_Critical_Section); - Number_Of_Threads--; - if (Number_Of_Threads <= 1) { - /* - * We only have the main thread - */ - __WinCE_Errno_Pointer_Function = Get_Main_Thread_Errno; - } - LeaveCriticalSection(&Number_Of_Threads_Critical_Section); -} - - -char * -strerror(int errnum) -{ - return "(strerror not implemented)"; -} - -#define FT_EPOCH (116444736000000000i64) -#define FT_TICKS (10000000i64) - -int -_wstat(const WCHAR *path, struct _stat *buffer) -{ - WIN32_FIND_DATA data; - HANDLE handle; - WCHAR *p; - - /* Fail if wildcard characters are specified */ - if (wcscspn(path, L"?*") != wcslen(path)) - return -1; - - handle = FindFirstFile(path, &data); - if (handle == INVALID_HANDLE_VALUE) { - errno = GetLastError(); - return -1; - } - FindClose(handle); - - /* Found: Convert the file times */ - buffer->st_mtime = convert_FILETIME_to_time_t(&data.ftLastWriteTime); - if (data.ftLastAccessTime.dwLowDateTime || data.ftLastAccessTime.dwHighDateTime) - buffer->st_atime = convert_FILETIME_to_time_t(&data.ftLastAccessTime); - else - buffer->st_atime = buffer->st_mtime; - if (data.ftCreationTime.dwLowDateTime || data.ftCreationTime.dwHighDateTime) - buffer->st_ctime = convert_FILETIME_to_time_t(&data.ftCreationTime); - else - buffer->st_ctime = buffer->st_mtime; - - /* Convert the file modes */ - buffer->st_mode = (unsigned short)((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? (S_IFDIR | S_IEXEC) : S_IFREG); - buffer->st_mode |= (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? S_IREAD : (S_IREAD | S_IWRITE); - if((p = wcsrchr(path, L'.')) != NULL) { - p++; - if (_wcsicmp(p, L".exe") == 0) - buffer->st_mode |= S_IEXEC; - } - buffer->st_mode |= (buffer->st_mode & 0700) >> 3; - buffer->st_mode |= (buffer->st_mode & 0700) >> 6; - /* Set the other information */ - buffer->st_nlink = 1; - buffer->st_size = (unsigned long int)data.nFileSizeLow; - buffer->st_uid = 0; - buffer->st_gid = 0; - buffer->st_ino = 0 /*data.dwOID ?*/; - buffer->st_dev = 0; - - return 0; /* success */ -} - -/* - * Helper function for cemodule -- do an fstat() operation on a Win32 File Handle - */ -int -_fstat(int handle, struct _stat *st) -{ - BY_HANDLE_FILE_INFORMATION Data; - - /* - * Get the file information - */ - if (!GetFileInformationByHandle((HANDLE)handle, &Data)) { - /* - * Return error - */ - errno = GetLastError(); - return(-1); - } - /* - * Found: Convert the file times - */ - st->st_mtime=(time_t)((*(__int64*)&Data.ftLastWriteTime-FT_EPOCH)/FT_TICKS); - if(Data.ftLastAccessTime.dwLowDateTime || Data.ftLastAccessTime.dwHighDateTime) - st->st_atime=(time_t)((*(__int64*)&Data.ftLastAccessTime-FT_EPOCH)/FT_TICKS); - else - st->st_atime=st->st_mtime ; - if(Data.ftCreationTime.dwLowDateTime || Data.ftCreationTime.dwHighDateTime ) - st->st_ctime=(time_t)((*(__int64*)&Data.ftCreationTime-FT_EPOCH)/FT_TICKS); - else - st->st_ctime=st->st_mtime ; - /* - * Convert the file modes - */ - st->st_mode = (unsigned short)((Data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? (S_IFDIR | S_IEXEC) : S_IFREG); - st->st_mode |= (Data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? S_IREAD : (S_IREAD | S_IWRITE); - st->st_mode |= (st->st_mode & 0700) >> 3; - st->st_mode |= (st->st_mode & 0700) >> 6; - /* - * Set the other information - */ - st->st_nlink=1; - st->st_size=(unsigned long int)Data.nFileSizeLow; - st->st_uid=0; - st->st_gid=0; - st->st_ino=0; - st->st_dev=0; - /* - * Return success - */ - return(0); -} - -int _wopen(const wchar_t *filename, int oflag, ...) -{ - DWORD Access, ShareMode, CreationDisposition; - HANDLE Handle; - static int Modes[4] = {0, (GENERIC_READ | GENERIC_WRITE), GENERIC_READ, GENERIC_WRITE}; - - /* - * Calculate the CreateFile arguments - */ - Access = Modes[oflag & O_MODE_MASK]; - ShareMode = (oflag & O_EXCL) ? 0 : (FILE_SHARE_READ | FILE_SHARE_WRITE); - if (oflag & O_TRUNC) - CreationDisposition = (oflag & O_CREAT) ? CREATE_ALWAYS : TRUNCATE_EXISTING; - else - CreationDisposition = (oflag & O_CREAT) ? CREATE_NEW : OPEN_EXISTING; - - Handle = CreateFileW(filename, Access, ShareMode, NULL, CreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); - - /* - * Deal with errors - */ - if (Handle == INVALID_HANDLE_VALUE) { - errno = GetLastError(); - if ((errno == ERROR_ALREADY_EXISTS) || (errno == ERROR_FILE_EXISTS)) - errno = ERROR_ALREADY_EXISTS; - return -1; - } - /* - * Return the handle - */ - return (int)Handle; -} - -int -_close(int handle) -{ - if(CloseHandle((HANDLE)handle)) - return 0; - errno = GetLastError(); - return -1; -} - -int -_write(int handle, const void *buffer, unsigned int count) -{ - DWORD numwritten = 0; - if(!WriteFile((HANDLE)handle, buffer, count, &numwritten, NULL)) { - errno = GetLastError(); - return -1; - } - return numwritten; -} - -int -_read(int handle, void *buffer, unsigned int count) -{ - DWORD numread = 0; - if(!ReadFile((HANDLE)handle, buffer, count, &numread, NULL)) { - errno = GetLastError(); - return -1; - } - return numread; -} - -long -_lseek(int handle, long offset, int origin) -{ - DWORD dwMoveMethod; - DWORD result; - - switch(origin) { - default: - errno = EINVAL; - return -1L; - case SEEK_SET: - dwMoveMethod = FILE_BEGIN; - break; - case SEEK_CUR: - dwMoveMethod = FILE_CURRENT; - break; - case SEEK_END: - dwMoveMethod = FILE_END; - break; - } - result = SetFilePointer((HANDLE)handle, offset, NULL, dwMoveMethod); - if(result == 0xFFFFFFFF) { - errno = GetLastError(); - return -1; - } - return (long)result; -} - -int -_wmkdir(const wchar_t *dirname) -{ - if(!CreateDirectoryW(dirname, NULL)) { - errno = GetLastError(); - return -1; - } - return 0; -} - -int -_wremove(const wchar_t *filename) -{ - if(!DeleteFileW(filename)) { - errno = GetLastError(); - return -1; - } - return 0; -} - -int -_wrename(const wchar_t *oldname, const wchar_t *newname) -{ - if(!MoveFileW(oldname, newname)) { - errno = GetLastError(); - return -1; - } - return 0; -} - -wchar_t * -_wgetcwd(wchar_t *buffer, int maxlen) -{ - wchar_t *result; - WCHAR wszPath[MAX_PATH + 1]; - WCHAR *p; - - if(!GetModuleFileNameW(NULL, wszPath, MAX_PATH + 1)) { - errno = GetLastError(); - return NULL; - } - /* Remove the filename part of the path to leave the directory */ - p = wcsrchr(wszPath, L'\\'); - if(p) - *p = L'\0'; - - if(buffer == NULL) - result = _wcsdup(wszPath); - else if(wcslen(wszPath) + 1 > (size_t)maxlen) { - result = NULL; - errno = ERROR_INSUFFICIENT_BUFFER; - } else { - wcsncpy(buffer, wszPath, maxlen); - buffer[maxlen - 1] = L'\0'; - result = buffer; - } - return result; -} - -/* - * The missing "C" runtime gmtime() function - */ -struct tm *gmtime(const time_t *TimeP) -{ - FILETIME File_Time; - - /* - * Deal with null time pointer - */ - if (!TimeP) return(NULL); - /* - * time_t -> FILETIME -> tm - */ - Convert_time_t_To_FILETIME(*TimeP, &File_Time); - return(Convert_FILETIME_To_tm(&File_Time)); -} - -/* - * The missing "C" runtime localtime() function - */ -struct tm *localtime(const time_t *TimeP) -{ - FILETIME File_Time, Local_File_Time; - - /* - * Deal with null time pointer - */ - if (!TimeP) return(NULL); - /* - * time_t -> FILETIME -> Local FILETIME -> tm - */ - Convert_time_t_To_FILETIME(*TimeP, &File_Time); - FileTimeToLocalFileTime(&File_Time, &Local_File_Time); - return(Convert_FILETIME_To_tm(&Local_File_Time)); -} - -/* - * The missing "C" runtime mktime() function - */ -time_t mktime(struct tm *tm) -{ - FILETIME *Local_File_Time; - FILETIME File_Time; - - /* - * tm -> Local FILETIME -> FILETIME -> time_t - */ - Local_File_Time = Convert_tm_To_FILETIME(tm); - LocalFileTimeToFileTime(Local_File_Time, &File_Time); - return(convert_FILETIME_to_time_t(&File_Time)); -} - -/* - * Missing "C" runtime time() function - */ -time_t time(time_t *TimeP) -{ - SYSTEMTIME System_Time; - FILETIME File_Time; - time_t Result; - - /* - * Get the current system time - */ - GetSystemTime(&System_Time); - /* - * SYSTEMTIME -> FILETIME -> time_t - */ - SystemTimeToFileTime(&System_Time, &File_Time); - Result = convert_FILETIME_to_time_t(&File_Time); - /* - * Return the time_t - */ - if (TimeP) *TimeP = Result; - return(Result); -} - -static char Standard_Name[32] = "GMT"; -static char Daylight_Name[32] = "GMT"; -char *tzname[2] = {Standard_Name, Daylight_Name}; -long timezone = 0; -int daylight = 0; - -void tzset(void) -{ - TIME_ZONE_INFORMATION Info; - int Result; - - /* - * Get our current timezone information - */ - Result = GetTimeZoneInformation(&Info); - switch(Result) { - /* - * We are on standard time - */ - case TIME_ZONE_ID_STANDARD: - daylight = 0; - break; - /* - * We are on daylight savings time - */ - case TIME_ZONE_ID_DAYLIGHT: - daylight = 1; - break; - /* - * We don't know the timezone information (leave it GMT) - */ - default: return; - } - /* - * Extract the timezone information - */ - timezone = Info.Bias * 60; - if (Info.StandardName[0]) - WideCharToMultiByte(CP_ACP, 0, Info.StandardName, -1, Standard_Name, sizeof(Standard_Name) - 1, NULL, NULL); - if (Info.DaylightName[0]) - WideCharToMultiByte(CP_ACP, 0, Info.DaylightName, -1, Daylight_Name, sizeof(Daylight_Name) - 1, NULL, NULL); -} - -/*** strftime() from newlib libc/time/strftime.c ***/ - -/* - * Sane snprintf(). Acts like snprintf(), but never return -1 or the - * value bigger than supplied buffer. - */ -static int -Snprintf(char *buf, size_t buflen, const char *fmt, ...) -{ - va_list ap; - int n; - - if (buflen == 0) - return (0); - - va_start(ap, fmt); - n = _vsnprintf(buf, buflen, fmt, ap); - va_end(ap); - - if (n < 0 || n > (int) buflen - 1) { - n = buflen - 1; - } - buf[n] = '\0'; - - return (n); -} - -#define snprintf Snprintf - -/* from libc/include/_ansi.h */ -#define _CONST const -#define _DEFUN(name, arglist, args) name(args) -#define _AND , -/* from libc/time/local.h */ -#define TZ_LOCK -#define TZ_UNLOCK -#define _tzname tzname -#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) -#define YEAR_BASE 1900 -#define SECSPERMIN 60L -#define MINSPERHOUR 60L -#define HOURSPERDAY 24L -#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) - -/* - * strftime.c - * Original Author: G. Haley - * Additions from: Eric Blake - * - * Places characters into the array pointed to by s as controlled by the string - * pointed to by format. If the total number of resulting characters including - * the terminating null character is not more than maxsize, returns the number - * of characters placed into the array pointed to by s (not including the - * terminating null character); otherwise zero is returned and the contents of - * the array indeterminate. - */ - -/* -FUNCTION -<<strftime>>---flexible calendar time formatter - -INDEX - strftime - -ANSI_SYNOPSIS - #include <time.h> - size_t strftime(char *<[s]>, size_t <[maxsize]>, - const char *<[format]>, const struct tm *<[timp]>); - -TRAD_SYNOPSIS - #include <time.h> - size_t strftime(<[s]>, <[maxsize]>, <[format]>, <[timp]>) - char *<[s]>; - size_t <[maxsize]>; - char *<[format]>; - struct tm *<[timp]>; - -DESCRIPTION -<<strftime>> converts a <<struct tm>> representation of the time (at -<[timp]>) into a null-terminated string, starting at <[s]> and occupying -no more than <[maxsize]> characters. - -You control the format of the output using the string at <[format]>. -<<*<[format]>>> can contain two kinds of specifications: text to be -copied literally into the formatted string, and time conversion -specifications. Time conversion specifications are two- and -three-character sequences beginning with `<<%>>' (use `<<%%>>' to -include a percent sign in the output). Each defined conversion -specification selects only the specified field(s) of calendar time -data from <<*<[timp]>>>, and converts it to a string in one of the -following ways: - -o+ -o %a -A three-letter abbreviation for the day of the week. [tm_wday] - -o %A -The full name for the day of the week, one of `<<Sunday>>', -`<<Monday>>', `<<Tuesday>>', `<<Wednesday>>', `<<Thursday>>', -`<<Friday>>', or `<<Saturday>>'. [tm_wday] - -o %b -A three-letter abbreviation for the month name. [tm_mon] - -o %B -The full name of the month, one of `<<January>>', `<<February>>', -`<<March>>', `<<April>>', `<<May>>', `<<June>>', `<<July>>', -`<<August>>', `<<September>>', `<<October>>', `<<November>>', -`<<December>>'. [tm_mon] - -o %c -A string representing the complete date and time, in the form -`<<"%a %b %e %H:%M:%S %Y">>' (example "Mon Apr 01 13:13:13 -1992"). [tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday] - -o %C -The century, that is, the year divided by 100 then truncated. For -4-digit years, the result is zero-padded and exactly two characters; -but for other years, there may a negative sign or more digits. In -this way, `<<%C%y>>' is equivalent to `<<%Y>>'. [tm_year] - -o %d -The day of the month, formatted with two digits (from `<<01>>' to -`<<31>>'). [tm_mday] - -o %D -A string representing the date, in the form `<<"%m/%d/%y">>'. -[tm_mday, tm_mon, tm_year] - -o %e -The day of the month, formatted with leading space if single digit -(from `<<1>>' to `<<31>>'). [tm_mday] - -o %E<<x>> -In some locales, the E modifier selects alternative representations of -certain modifiers <<x>>. But in the "C" locale supported by newlib, -it is ignored, and treated as %<<x>>. - -o %F -A string representing the ISO 8601:2000 date format, in the form -`<<"%Y-%m-%d">>'. [tm_mday, tm_mon, tm_year] - -o %g -The last two digits of the week-based year, see specifier %G (from -`<<00>>' to `<<99>>'). [tm_year, tm_wday, tm_yday] - -o %G -The week-based year. In the ISO 8601:2000 calendar, week 1 of the year -includes January 4th, and begin on Mondays. Therefore, if January 1st, -2nd, or 3rd falls on a Sunday, that day and earlier belong to the last -week of the previous year; and if December 29th, 30th, or 31st falls -on Monday, that day and later belong to week 1 of the next year. For -consistency with %Y, it always has at least four characters. -Example: "%G" for Saturday 2nd January 1999 gives "1998", and for -Tuesday 30th December 1997 gives "1998". [tm_year, tm_wday, tm_yday] - -o %h -A three-letter abbreviation for the month name (synonym for -"%b"). [tm_mon] - -o %H -The hour (on a 24-hour clock), formatted with two digits (from -`<<00>>' to `<<23>>'). [tm_hour] - -o %I -The hour (on a 12-hour clock), formatted with two digits (from -`<<01>>' to `<<12>>'). [tm_hour] - -o %j -The count of days in the year, formatted with three digits -(from `<<001>>' to `<<366>>'). [tm_yday] - -o %k -The hour (on a 24-hour clock), formatted with leading space if single -digit (from `<<0>>' to `<<23>>'). Non-POSIX extension. [tm_hour] - -o %l -The hour (on a 12-hour clock), formatted with leading space if single -digit (from `<<1>>' to `<<12>>'). Non-POSIX extension. [tm_hour] - -o %m -The month number, formatted with two digits (from `<<01>>' to `<<12>>'). -[tm_mon] - -o %M -The minute, formatted with two digits (from `<<00>>' to `<<59>>'). [tm_min] - -o %n -A newline character (`<<\n>>'). - -o %O<<x>> -In some locales, the O modifier selects alternative digit characters -for certain modifiers <<x>>. But in the "C" locale supported by newlib, it -is ignored, and treated as %<<x>>. - -o %p -Either `<<AM>>' or `<<PM>>' as appropriate. [tm_hour] - -o %r -The 12-hour time, to the second. Equivalent to "%I:%M:%S %p". [tm_sec, -tm_min, tm_hour] - -o %R -The 24-hour time, to the minute. Equivalent to "%H:%M". [tm_min, tm_hour] - -o %S -The second, formatted with two digits (from `<<00>>' to `<<60>>'). The -value 60 accounts for the occasional leap second. [tm_sec] - -o %t -A tab character (`<<\t>>'). - -o %T -The 24-hour time, to the second. Equivalent to "%H:%M:%S". [tm_sec, -tm_min, tm_hour] - -o %u -The weekday as a number, 1-based from Monday (from `<<1>>' to -`<<7>>'). [tm_wday] - -o %U -The week number, where weeks start on Sunday, week 1 contains the first -Sunday in a year, and earlier days are in week 0. Formatted with two -digits (from `<<00>>' to `<<53>>'). See also <<%W>>. [tm_wday, tm_yday] - -o %V -The week number, where weeks start on Monday, week 1 contains January 4th, -and earlier days are in the previous year. Formatted with two digits -(from `<<01>>' to `<<53>>'). See also <<%G>>. [tm_year, tm_wday, tm_yday] - -o %w -The weekday as a number, 0-based from Sunday (from `<<0>>' to `<<6>>'). -[tm_wday] - -o %W -The week number, where weeks start on Monday, week 1 contains the first -Monday in a year, and earlier days are in week 0. Formatted with two -digits (from `<<00>>' to `<<53>>'). [tm_wday, tm_yday] - -o %x -A string representing the complete date, equivalent to "%m/%d/%y". -[tm_mon, tm_mday, tm_year] - -o %X -A string representing the full time of day (hours, minutes, and -seconds), equivalent to "%H:%M:%S". [tm_sec, tm_min, tm_hour] - -o %y -The last two digits of the year (from `<<00>>' to `<<99>>'). [tm_year] - -o %Y -The full year, equivalent to <<%C%y>>. It will always have at least four -characters, but may have more. The year is accurate even when tm_year -added to the offset of 1900 overflows an int. [tm_year] - -o %z -The offset from UTC. The format consists of a sign (negative is west of -Greewich), two characters for hour, then two characters for minutes -(-hhmm or +hhmm). If tm_isdst is negative, the offset is unknown and no -output is generated; if it is zero, the offset is the standard offset for -the current time zone; and if it is positive, the offset is the daylight -savings offset for the current timezone. The offset is determined from -the TZ environment variable, as if by calling tzset(). [tm_isdst] - -o %Z -The time zone name. If tm_isdst is negative, no output is generated. -Otherwise, the time zone name is based on the TZ environment variable, -as if by calling tzset(). [tm_isdst] - -o %% -A single character, `<<%>>'. -o- - -RETURNS -When the formatted time takes up no more than <[maxsize]> characters, -the result is the length of the formatted string. Otherwise, if the -formatting operation was abandoned due to lack of room, the result is -<<0>>, and the string starting at <[s]> corresponds to just those -parts of <<*<[format]>>> that could be completely filled in within the -<[maxsize]> limit. - -PORTABILITY -ANSI C requires <<strftime>>, but does not specify the contents of -<<*<[s]>>> when the formatted string would require more than -<[maxsize]> characters. Unrecognized specifiers and fields of -<<timp>> that are out of range cause undefined results. Since some -formats expand to 0 bytes, it is wise to set <<*<[s]>>> to a nonzero -value beforehand to distinguish between failure and an empty string. -This implementation does not support <<s>> being NULL, nor overlapping -<<s>> and <<format>>. - -<<strftime>> requires no supporting OS subroutines. -*/ - -static _CONST int dname_len[7] = -{6, 6, 7, 9, 8, 6, 8}; - -static _CONST char *_CONST dname[7] = -{"Sunday", "Monday", "Tuesday", "Wednesday", - "Thursday", "Friday", "Saturday"}; - -static _CONST int mname_len[12] = -{7, 8, 5, 5, 3, 4, 4, 6, 9, 7, 8, 8}; - -static _CONST char *_CONST mname[12] = -{"January", "February", "March", "April", - "May", "June", "July", "August", "September", "October", "November", - "December"}; - -/* Using the tm_year, tm_wday, and tm_yday components of TIM_P, return - -1, 0, or 1 as the adjustment to add to the year for the ISO week - numbering used in "%g%G%V", avoiding overflow. */ -static int -_DEFUN (iso_year_adjust, (tim_p), - _CONST struct tm *tim_p) -{ - /* Account for fact that tm_year==0 is year 1900. */ - int leap = isleap (tim_p->tm_year + (YEAR_BASE - - (tim_p->tm_year < 0 ? 0 : 2000))); - - /* Pack the yday, wday, and leap year into a single int since there are so - many disparate cases. */ -#define PACK(yd, wd, lp) (((yd) << 4) + (wd << 1) + (lp)) - switch (PACK (tim_p->tm_yday, tim_p->tm_wday, leap)) - { - case PACK (0, 5, 0): /* Jan 1 is Fri, not leap. */ - case PACK (0, 6, 0): /* Jan 1 is Sat, not leap. */ - case PACK (0, 0, 0): /* Jan 1 is Sun, not leap. */ - case PACK (0, 5, 1): /* Jan 1 is Fri, leap year. */ - case PACK (0, 6, 1): /* Jan 1 is Sat, leap year. */ - case PACK (0, 0, 1): /* Jan 1 is Sun, leap year. */ - case PACK (1, 6, 0): /* Jan 2 is Sat, not leap. */ - case PACK (1, 0, 0): /* Jan 2 is Sun, not leap. */ - case PACK (1, 6, 1): /* Jan 2 is Sat, leap year. */ - case PACK (1, 0, 1): /* Jan 2 is Sun, leap year. */ - case PACK (2, 0, 0): /* Jan 3 is Sun, not leap. */ - case PACK (2, 0, 1): /* Jan 3 is Sun, leap year. */ - return -1; /* Belongs to last week of previous year. */ - case PACK (362, 1, 0): /* Dec 29 is Mon, not leap. */ - case PACK (363, 1, 1): /* Dec 29 is Mon, leap year. */ - case PACK (363, 1, 0): /* Dec 30 is Mon, not leap. */ - case PACK (363, 2, 0): /* Dec 30 is Tue, not leap. */ - case PACK (364, 1, 1): /* Dec 30 is Mon, leap year. */ - case PACK (364, 2, 1): /* Dec 30 is Tue, leap year. */ - case PACK (364, 1, 0): /* Dec 31 is Mon, not leap. */ - case PACK (364, 2, 0): /* Dec 31 is Tue, not leap. */ - case PACK (364, 3, 0): /* Dec 31 is Wed, not leap. */ - case PACK (365, 1, 1): /* Dec 31 is Mon, leap year. */ - case PACK (365, 2, 1): /* Dec 31 is Tue, leap year. */ - case PACK (365, 3, 1): /* Dec 31 is Wed, leap year. */ - return 1; /* Belongs to first week of next year. */ - } - return 0; /* Belongs to specified year. */ -#undef PACK -} - -size_t -_DEFUN (strftime, (s, maxsize, format, tim_p), - char *s _AND - size_t maxsize _AND - _CONST char *format _AND - _CONST struct tm *tim_p) -{ - size_t count = 0; - int i; - - for (;;) - { - while (*format && *format != '%') - { - if (count < maxsize - 1) - s[count++] = *format++; - else - return 0; - } - - if (*format == '\0') - break; - - format++; - if (*format == 'E' || *format == 'O') - format++; - - switch (*format) - { - case 'a': - for (i = 0; i < 3; i++) - { - if (count < maxsize - 1) - s[count++] = - dname[tim_p->tm_wday][i]; - else - return 0; - } - break; - case 'A': - for (i = 0; i < dname_len[tim_p->tm_wday]; i++) - { - if (count < maxsize - 1) - s[count++] = - dname[tim_p->tm_wday][i]; - else - return 0; - } - break; - case 'b': - case 'h': - for (i = 0; i < 3; i++) - { - if (count < maxsize - 1) - s[count++] = - mname[tim_p->tm_mon][i]; - else - return 0; - } - break; - case 'B': - for (i = 0; i < mname_len[tim_p->tm_mon]; i++) - { - if (count < maxsize - 1) - s[count++] = - mname[tim_p->tm_mon][i]; - else - return 0; - } - break; - case 'c': - { - /* Length is not known because of %C%y, so recurse. */ - size_t adjust = strftime (&s[count], maxsize - count, - "%a %b %e %H:%M:%S %C%y", tim_p); - if (adjust > 0) - count += adjust; - else - return 0; - } - break; - case 'C': - { - /* Examples of (tm_year + YEAR_BASE) that show how %Y == %C%y - with 32-bit int. - %Y %C %y - 2147485547 21474855 47 - 10000 100 00 - 9999 99 99 - 0999 09 99 - 0099 00 99 - 0001 00 01 - 0000 00 00 - -001 -0 01 - -099 -0 99 - -999 -9 99 - -1000 -10 00 - -10000 -100 00 - -2147481748 -21474817 48 - - Be careful of both overflow and sign adjustment due to the - asymmetric range of years. - */ - int neg = tim_p->tm_year < -YEAR_BASE; - int century = tim_p->tm_year >= 0 - ? tim_p->tm_year / 100 + YEAR_BASE / 100 - : abs (tim_p->tm_year + YEAR_BASE) / 100; - count += snprintf (&s[count], maxsize - count, "%s%.*d", - neg ? "-" : "", 2 - neg, century); - if (count >= maxsize) - return 0; - } - break; - case 'd': - case 'e': - if (count < maxsize - 2) - { - sprintf (&s[count], *format == 'd' ? "%.2d" : "%2d", - tim_p->tm_mday); - count += 2; - } - else - return 0; - break; - case 'D': - case 'x': - /* %m/%d/%y */ - if (count < maxsize - 8) - { - sprintf (&s[count], "%.2d/%.2d/%.2d", - tim_p->tm_mon + 1, tim_p->tm_mday, - tim_p->tm_year >= 0 ? tim_p->tm_year % 100 - : abs (tim_p->tm_year + YEAR_BASE) % 100); - count += 8; - } - else - return 0; - break; - case 'F': - { - /* Length is not known because of %C%y, so recurse. */ - size_t adjust = strftime (&s[count], maxsize - count, - "%C%y-%m-%d", tim_p); - if (adjust > 0) - count += adjust; - else - return 0; - } - break; - case 'g': - if (count < maxsize - 2) - { - /* Be careful of both overflow and negative years, thanks to - the asymmetric range of years. */ - int adjust = iso_year_adjust (tim_p); - int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100 - : abs (tim_p->tm_year + YEAR_BASE) % 100; - if (adjust < 0 && tim_p->tm_year <= -YEAR_BASE) - adjust = 1; - else if (adjust > 0 && tim_p->tm_year < -YEAR_BASE) - adjust = -1; - sprintf (&s[count], "%.2d", - ((year + adjust) % 100 + 100) % 100); - count += 2; - } - else - return 0; - break; - case 'G': - { - /* See the comments for 'C' and 'Y'; this is a variable length - field. Although there is no requirement for a minimum number - of digits, we use 4 for consistency with 'Y'. */ - int neg = tim_p->tm_year < -YEAR_BASE; - int adjust = iso_year_adjust (tim_p); - int century = tim_p->tm_year >= 0 - ? tim_p->tm_year / 100 + YEAR_BASE / 100 - : abs (tim_p->tm_year + YEAR_BASE) / 100; - int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100 - : abs (tim_p->tm_year + YEAR_BASE) % 100; - if (adjust < 0 && tim_p->tm_year <= -YEAR_BASE) - neg = adjust = 1; - else if (adjust > 0 && neg) - adjust = -1; - year += adjust; - if (year == -1) - { - year = 99; - --century; - } - else if (year == 100) - { - year = 0; - ++century; - } - count += snprintf (&s[count], maxsize - count, "%s%.*d%.2d", - neg ? "-" : "", 2 - neg, century, year); - if (count >= maxsize) - return 0; - } - break; - case 'H': - case 'k': - if (count < maxsize - 2) - { - sprintf (&s[count], *format == 'k' ? "%2d" : "%.2d", - tim_p->tm_hour); - count += 2; - } - else - return 0; - break; - case 'I': - case 'l': - if (count < maxsize - 2) - { - if (tim_p->tm_hour == 0 || - tim_p->tm_hour == 12) - { - s[count++] = '1'; - s[count++] = '2'; - } - else - { - sprintf (&s[count], *format == 'I' ? "%.2d" : "%2d", - tim_p->tm_hour % 12); - count += 2; - } - } - else - return 0; - break; - case 'j': - if (count < maxsize - 3) - { - sprintf (&s[count], "%.3d", - tim_p->tm_yday + 1); - count += 3; - } - else - return 0; - break; - case 'm': - if (count < maxsize - 2) - { - sprintf (&s[count], "%.2d", - tim_p->tm_mon + 1); - count += 2; - } - else - return 0; - break; - case 'M': - if (count < maxsize - 2) - { - sprintf (&s[count], "%.2d", - tim_p->tm_min); - count += 2; - } - else - return 0; - break; - case 'n': - if (count < maxsize - 1) - s[count++] = '\n'; - else - return 0; - break; - case 'p': - if (count < maxsize - 2) - { - if (tim_p->tm_hour < 12) - s[count++] = 'A'; - else - s[count++] = 'P'; - - s[count++] = 'M'; - } - else - return 0; - break; - case 'r': - if (count < maxsize - 11) - { - if (tim_p->tm_hour == 0 || - tim_p->tm_hour == 12) - { - s[count++] = '1'; - s[count++] = '2'; - } - else - { - sprintf (&s[count], "%.2d", tim_p->tm_hour % 12); - count += 2; - } - s[count++] = ':'; - sprintf (&s[count], "%.2d", - tim_p->tm_min); - count += 2; - s[count++] = ':'; - sprintf (&s[count], "%.2d", - tim_p->tm_sec); - count += 2; - s[count++] = ' '; - if (tim_p->tm_hour < 12) - s[count++] = 'A'; - else - s[count++] = 'P'; - - s[count++] = 'M'; - } - else - return 0; - break; - case 'R': - if (count < maxsize - 5) - { - sprintf (&s[count], "%.2d:%.2d", tim_p->tm_hour, tim_p->tm_min); - count += 5; - } - else - return 0; - break; - case 'S': - if (count < maxsize - 2) - { - sprintf (&s[count], "%.2d", - tim_p->tm_sec); - count += 2; - } - else - return 0; - break; - case 't': - if (count < maxsize - 1) - s[count++] = '\t'; - else - return 0; - break; - case 'T': - case 'X': - if (count < maxsize - 8) - { - sprintf (&s[count], "%.2d:%.2d:%.2d", tim_p->tm_hour, - tim_p->tm_min, tim_p->tm_sec); - count += 8; - } - else - return 0; - break; - case 'u': - if (count < maxsize - 1) - { - if (tim_p->tm_wday == 0) - s[count++] = '7'; - else - s[count++] = '0' + tim_p->tm_wday; - } - else - return 0; - break; - case 'U': - if (count < maxsize - 2) - { - sprintf (&s[count], "%.2d", - (tim_p->tm_yday + 7 - - tim_p->tm_wday) / 7); - count += 2; - } - else - return 0; - break; - case 'V': - if (count < maxsize - 2) - { - int adjust = iso_year_adjust (tim_p); - int wday = (tim_p->tm_wday) ? tim_p->tm_wday - 1 : 6; - int week = (tim_p->tm_yday + 10 - wday) / 7; - if (adjust > 0) - week = 1; - else if (adjust < 0) - /* Previous year has 53 weeks if current year starts on - Fri, and also if current year starts on Sat and - previous year was leap year. */ - week = 52 + (4 >= (wday - tim_p->tm_yday - - isleap (tim_p->tm_year - + (YEAR_BASE - 1 - - (tim_p->tm_year < 0 - ? 0 : 2000))))); - sprintf (&s[count], "%.2d", week); - count += 2; - } - else - return 0; - break; - case 'w': - if (count < maxsize - 1) - s[count++] = '0' + tim_p->tm_wday; - else - return 0; - break; - case 'W': - if (count < maxsize - 2) - { - int wday = (tim_p->tm_wday) ? tim_p->tm_wday - 1 : 6; - sprintf (&s[count], "%.2d", - (tim_p->tm_yday + 7 - wday) / 7); - count += 2; - } - else - return 0; - break; - case 'y': - if (count < maxsize - 2) - { - /* Be careful of both overflow and negative years, thanks to - the asymmetric range of years. */ - int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100 - : abs (tim_p->tm_year + YEAR_BASE) % 100; - sprintf (&s[count], "%.2d", year); - count += 2; - } - else - return 0; - break; - case 'Y': - { - /* Length is not known because of %C%y, so recurse. */ - size_t adjust = strftime (&s[count], maxsize - count, - "%C%y", tim_p); - if (adjust > 0) - count += adjust; - else - return 0; - } - break; - case 'z': -#ifndef _WIN32_WCE - if (tim_p->tm_isdst >= 0) - { - if (count < maxsize - 5) - { - long offset; - __tzinfo_type *tz = __gettzinfo (); - TZ_LOCK; - /* The sign of this is exactly opposite the envvar TZ. We - could directly use the global _timezone for tm_isdst==0, - but have to use __tzrule for daylight savings. */ - offset = -tz->__tzrule[tim_p->tm_isdst > 0].offset; - TZ_UNLOCK; - sprintf (&s[count], "%+03ld%.2ld", offset / SECSPERHOUR, - labs (offset / SECSPERMIN) % 60L); - count += 5; - } - else - return 0; - } - break; -#endif - case 'Z': - if (tim_p->tm_isdst >= 0) - { - int size; - TZ_LOCK; - size = strlen(_tzname[tim_p->tm_isdst > 0]); - for (i = 0; i < size; i++) - { - if (count < maxsize - 1) - s[count++] = _tzname[tim_p->tm_isdst > 0][i]; - else - { - TZ_UNLOCK; - return 0; - } - } - TZ_UNLOCK; - } - break; - case '%': - if (count < maxsize - 1) - s[count++] = '%'; - else - return 0; - break; - } - if (*format) - format++; - else - break; - } - if (maxsize) - s[count] = '\0'; - - return count; -} diff --git a/cpukit/shttpd/compat_wince.h b/cpukit/shttpd/compat_wince.h deleted file mode 100644 index 02f655707d..0000000000 --- a/cpukit/shttpd/compat_wince.h +++ /dev/null @@ -1,145 +0,0 @@ - -#ifndef INCLUDE_WINCE_COMPAT_H -#define INCLUDE_WINCE_COMPAT_H - -#ifdef __cplusplus -extern "C" { -#endif - -/*** ANSI C library ***/ - -/* Missing ANSI C definitions */ - -#define BUFSIZ 4096 - -#define ENOMEM ERROR_NOT_ENOUGH_MEMORY -#define EBADF ERROR_INVALID_HANDLE -#define EINVAL ERROR_INVALID_PARAMETER -#define ENOENT ERROR_FILE_NOT_FOUND -#define ERANGE ERROR_INSUFFICIENT_BUFFER -#define EINTR WSAEINTR - -/* - * Because we need a per-thread errno, we define a function - * pointer that we can call to return a pointer to the errno - * for the current thread. Then we define a macro for errno - * that dereferences this function's result. - * - * This makes it syntactically just like the "real" errno. - * - * Using a function pointer allows us to use a very fast - * function when there are no threads running and a slower - * function when there are multiple threads running. - */ -void __WinCE_Errno_New_Thread(int *Errno_Pointer); -void __WinCE_Errno_Thread_Exit(void); -extern int *(*__WinCE_Errno_Pointer_Function)(void); - -#define errno (*(*__WinCE_Errno_Pointer_Function)()) - -char *strerror(int errnum); - -struct tm { - int tm_sec; /* seconds after the minute - [0,59] */ - int tm_min; /* minutes after the hour - [0,59] */ - int tm_hour; /* hours since midnight - [0,23] */ - int tm_mday; /* day of the month - [1,31] */ - int tm_mon; /* months since January - [0,11] */ - int tm_year; /* years since 1900 */ - int tm_wday; /* days since Sunday - [0,6] */ - int tm_yday; /* days since January 1 - [0,365] */ - int tm_isdst; /* daylight savings time flag */ -}; - -struct tm *gmtime(const time_t *TimeP); /* for future use */ -struct tm *localtime(const time_t *TimeP); -time_t mktime(struct tm *tm); -time_t time(time_t *TimeP); - -size_t strftime(char *s, size_t maxsize, const char *format, const struct tm *tim_p); - -int _wrename(const wchar_t *oldname, const wchar_t *newname); -int _wremove(const wchar_t *filename); - -/* Environment variables are not supported */ -#define getenv(x) (NULL) - -/* Redefine fileno so that it returns an integer */ -#undef fileno -#define fileno(f) (int)_fileno(f) - -/* Signals are not supported */ -#define signal(num, handler) (0) -#define SIGTERM 0 -#define SIGINT 0 - - -/*** POSIX API ***/ - -/* Missing POSIX definitions */ - -#define FILENAME_MAX MAX_PATH - -struct _stat { - unsigned long st_size; - unsigned long st_ino; - int st_mode; - unsigned long st_atime; - unsigned long st_mtime; - unsigned long st_ctime; - unsigned short st_dev; - unsigned short st_nlink; - unsigned short st_uid; - unsigned short st_gid; -}; - -#define S_IFMT 0170000 -#define S_IFDIR 0040000 -#define S_IFREG 0100000 -#define S_IEXEC 0000100 -#define S_IWRITE 0000200 -#define S_IREAD 0000400 - -#define _S_IFDIR S_IFDIR /* MSVCRT compatibilit */ - -int _fstat(int handle, struct _stat *buffer); -int _wstat(const wchar_t *path, struct _stat *buffer); - -#define stat _stat /* NOTE: applies to _stat() and also struct _stat */ -#define fstat _fstat - -#define O_RDWR (1<<0) -#define O_RDONLY (2<<0) -#define O_WRONLY (3<<0) -#define O_MODE_MASK (3<<0) -#define O_TRUNC (1<<2) -#define O_EXCL (1<<3) -#define O_CREAT (1<<4) -#define O_BINARY 0 - -int _wopen(const wchar_t *filename, int oflag, ...); -int _close(int handle); -int _write(int handle, const void *buffer, unsigned int count); -int _read(int handle, void *buffer, unsigned int count); -long _lseek(int handle, long offset, int origin); - -#define close _close -#define write _write -#define read _read -#define lseek _lseek - -/* WinCE has only a Unicode version of this function */ -FILE *fdopen(int handle, const char *mode); - -int _wmkdir(const wchar_t *dirname); - -/* WinCE has no concept of current directory so we return a constant path */ -wchar_t *_wgetcwd(wchar_t *buffer, int maxlen); - -#define freopen(path, mode, stream) assert(0) - -#ifdef __cplusplus -} -#endif - -#endif /* INCLUDE_WINCE_COMPAT_H */ diff --git a/cpukit/shttpd/config.c b/cpukit/shttpd/config.c deleted file mode 100644 index e9240e549e..0000000000 --- a/cpukit/shttpd/config.c +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> - * All rights reserved - * - * "THE BEER-WARE LICENSE" (Revision 42): - * Sergey Lyubka wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. - */ - -#include "defs.h" - -#include <unistd.h> - -/* - * Configuration parameters setters - */ -static void -set_int(struct shttpd_ctx *ctx, void *ptr, const char *string) -{ - ctx = NULL; /* Unused */ - * (int *) ptr = atoi(string); -} - -static void -set_str(struct shttpd_ctx *ctx, void *ptr, const char *string) -{ - ctx = NULL; /* Unused */ - * (char **) ptr = my_strdup(string); -} - -static void -set_log_file(struct shttpd_ctx *ctx, void *ptr, const char *string) -{ - FILE **fp = ptr; - ctx = NULL; - - if ((*fp = fopen(string, "a")) == NULL) - elog(E_FATAL, NULL, "cannot open log file %s: %s", - string, strerror(errno)); -} - -#ifndef NO_SSL -/* - * Dynamically load SSL library. Set up ctx->ssl_ctx pointer. - */ -static void -set_ssl(struct shttpd_ctx *ctx, void *arg, const char *pem) -{ - SSL_CTX *CTX; - void *lib; - struct ssl_func *fp; - - arg = NULL; /* Unused */ - - /* Load SSL library dynamically */ - if ((lib = dlopen(SSL_LIB, RTLD_LAZY)) == NULL) - elog(E_FATAL, NULL, "set_ssl: cannot load %s", SSL_LIB); - - for (fp = ssl_sw; fp->name != NULL; fp++) - if ((fp->ptr.v_void = dlsym(lib, fp->name)) == NULL) - elog(E_FATAL, NULL,"set_ssl: cannot find %s", fp->name); - - /* Initialize SSL crap */ - SSL_library_init(); - - if ((CTX = SSL_CTX_new(SSLv23_server_method())) == NULL) - elog(E_FATAL, NULL, "SSL_CTX_new error"); - else if (SSL_CTX_use_certificate_file(CTX, pem, SSL_FILETYPE_PEM) == 0) - elog(E_FATAL, NULL, "cannot open %s", pem); - else if (SSL_CTX_use_PrivateKey_file(CTX, pem, SSL_FILETYPE_PEM) == 0) - elog(E_FATAL, NULL, "cannot open %s", pem); - ctx->ssl_ctx = CTX; -} -#endif /* NO_SSL */ - -static void -set_mime(struct shttpd_ctx *ctx, void *arg, const char *string) -{ - arg = NULL; - set_mime_types(ctx, string); -} - -#define OFS(x) offsetof(struct shttpd_ctx, x) -#define BOOL_OPT "0|1" -const struct opt options[] = { - {'d', "document_root", "Web root directory", set_str, - OFS(document_root), "directory", NULL, OPT_DIR}, - {'i', "index_files", "Index files", set_str, OFS(index_files), - "file_list", INDEX_FILES, OPT_ADVANCED}, - {'p', "listen_port", "Listening port", set_int, - OFS(port), "port", HTTP_PORT, OPT_INT | OPT_ADVANCED}, - {'D', "list_directories", "Directory listing", set_int, - OFS(dirlist), BOOL_OPT, "1", OPT_BOOL | OPT_ADVANCED}, -#ifndef NO_CGI - {'c', "cgi_extensions", "CGI extensions", set_str, - OFS(cgi_extensions), "ext_list", CGI_EXT, OPT_ADVANCED}, - {'C', "cgi_interpreter", "CGI interpreter", set_str, - OFS(cgi_interpreter), "file", NULL, OPT_FILE | OPT_ADVANCED}, - {'V', "cgi_envvar", "CGI envir variables", set_str, - OFS(cgi_vars), "X=Y,....", NULL, OPT_ADVANCED}, -#endif /* NO_CGI */ - {'N', "auth_realm", "Authentication realm", set_str, - OFS(auth_realm), "auth_realm", REALM, OPT_ADVANCED}, - {'l', "access_log", "Access log file", set_log_file, - OFS(access_log), "file", NULL, OPT_FILE | OPT_ADVANCED}, - {'e', "error_log", "Error log file", set_log_file, - OFS(error_log), "file", NULL, OPT_FILE | OPT_ADVANCED}, - {'m', "mime_types", "Mime types file", set_mime, - OFS(mime_file), "file", NULL, OPT_FILE | OPT_ADVANCED}, - {'P', "global_htpasswd", "Global passwords file", set_str, - OFS(global_passwd_file), "file", NULL, OPT_FILE | OPT_ADVANCED}, -#ifndef NO_SSL - {'s', "ssl_certificate", "SSL certificate file", set_ssl, - OFS(ssl_ctx), "pem_file", NULL, OPT_FILE | OPT_ADVANCED}, -#endif /* NO_SSL */ - {'U', "put_auth", "PUT,DELETE auth file",set_str, - OFS(put_auth_file), "file", NULL, OPT_FILE | OPT_ADVANCED}, - {'a', "aliases", "Aliases", set_str, - OFS(aliases), "X=Y,...", NULL, OPT_ADVANCED}, - {'b', "io_buf_size", "IO buffer size", set_int, OFS(io_buf_size), - "bytes", DFLT_IO_SIZ, OPT_INT | OPT_ADVANCED}, -#ifdef _WIN32 - {'S', "auto_start", "Autostart with Windows", set_int, - OFS(auto_start), BOOL_OPT, "1", OPT_BOOL}, -#else - {'I', "inetd_mode", "Inetd mode", set_int, - OFS(inetd_mode), BOOL_OPT, NULL, OPT_BOOL }, - {'u', "runtime_uid", "Run as user", set_str, - OFS(uid), "user_name", NULL, 0 }, -#endif /* _WIN32 */ - {0, NULL, NULL, NULL, 0, NULL, NULL, 0 } -}; - -static const struct opt * -find_option(int sw, const char *name) -{ - const struct opt *opt; - - for (opt = options; opt->sw != 0; opt++) - if (sw == opt->sw || (name && strcmp(opt->name, name) == 0)) - return (opt); - - return (NULL); -} - -static void -set_option(const struct opt *opt, const char *val, char **tmpvars) -{ - tmpvars += opt - options; - - if (*tmpvars != NULL) - free(*tmpvars); - - *tmpvars = my_strdup(val); -} - -/* - * Initialize shttpd context - */ -static void -initialize_context(struct shttpd_ctx *ctx, const char *config_file, - int argc, char *argv[], char **tmpvars) -{ - char line[FILENAME_MAX], root[FILENAME_MAX], - var[sizeof(line)], val[sizeof(line)]; - const char *arg; - size_t i; - const struct opt *opt; - FILE *fp; - struct tm *tm; - - current_time = time(NULL); - tm = localtime(¤t_time); - tz_offset = 0; -#if 0 - tm->tm_gmtoff - 3600 * (tm->tm_isdst > 0 ? 1 : 0); -#endif - - (void) memset(ctx, 0, sizeof(*ctx)); - - ctx->start_time = current_time; - InitializeCriticalSection(&ctx->mutex); - - LL_INIT(&ctx->connections); - LL_INIT(&ctx->mime_types); - LL_INIT(&ctx->registered_uris); - LL_INIT(&ctx->uri_auths); - LL_INIT(&ctx->error_handlers); - - /* First pass: set the defaults */ - for (opt = options; opt->sw != 0; opt++) - if (opt->def != NULL) - tmpvars[opt - options] = my_strdup(opt->def); - - /* Second pass: load config file */ - if (config_file != NULL && (fp = fopen(config_file, "r")) != NULL) { - DBG(("init_ctx: config file %s", config_file)); - - /* Loop through the lines in config file */ - while (fgets(line, sizeof(line), fp) != NULL) { - - /* Skip comments and empty lines */ - if (line[0] == '#' || line[0] == '\n') - continue; - - /* Trim trailing newline character */ - line[strlen(line) - 1] = '\0'; - - if (sscanf(line, "%s %[^#\n]", var, val) != 2) - elog(E_FATAL,0,"init_ctx: bad line: [%s]",line); - - if ((opt = find_option(0, var)) == NULL) - elog(E_FATAL, NULL, - "set_option: unknown variable [%s]", var); - set_option(opt, val, tmpvars); - } - (void) fclose(fp); - } - - /* Third pass: process command line args */ - for (i = 1; i < (size_t) argc && argv[i][0] == '-'; i++) - if ((opt = find_option(argv[i][1], NULL)) != NULL) { - arg = argv[i][2] ? &argv[i][2] : argv[++i]; - - if (arg == NULL) - usage(argv[0]); - - set_option(opt, arg, tmpvars); - } else { - usage(argv[0]); - } - - /* Call setters functions now */ - for (i = 0; i < NELEMS(options); i++) - if (tmpvars[i] != NULL) { - options[i].setter(ctx, - ((char *) ctx) + options[i].ofs, tmpvars[i]); - free(tmpvars[i]); - } - -#ifndef NO_SSL - /* If SSL is wanted and port is not overridden, set it to 443 */ - if (ctx->port == atoi(HTTP_PORT) && ctx->ssl_ctx != NULL) - ctx->port = 443; -#endif /* NO_SSL */ - - /* If document_root is not set, set it to current directory */ - if (ctx->document_root == NULL) { - (void) my_getcwd(root, sizeof(root)); - ctx->document_root = my_strdup(root); - } - -#ifdef _WIN32 - {WSADATA data; WSAStartup(MAKEWORD(2,2), &data);} -#endif /* _WIN32 */ - - DBG(("init_ctx: initialized context %p", (void *) ctx)); -} - -/* - * Show usage string and exit. - */ -void -usage(const char *prog) -{ - const struct opt *opt; - - (void) fprintf(stderr, - "SHTTPD version %s (c) Sergey Lyubka\n" - "usage: %s [OPTIONS] [config_file]\n" - "Note: config line keyword for every option is in the " - "round brackets\n", VERSION, prog); - -#if !defined(NO_AUTH) - (void) fprintf(stderr, "-A <htpasswd_file> <realm> <user> <passwd>\n"); -#endif /* NO_AUTH */ - - for (opt = options; opt->name != NULL; opt++) - (void) fprintf(stderr, "-%c <%s>\t\t%s (%s)\n", - opt->sw, opt->arg, opt->desc, opt->name); - - exit(EXIT_FAILURE); -} - -struct shttpd_ctx * -init_from_argc_argv(const char *config_file, int argc, char *argv[]) -{ - struct shttpd_ctx *ctx; - char *tmpvars[NELEMS(options)]; - size_t i; - - /* Initialize all temporary holders to NULL */ - for (i = 0; i < NELEMS(tmpvars); i++) - tmpvars[i] = NULL; - - if ((ctx = malloc(sizeof(*ctx))) != NULL) - initialize_context(ctx, config_file, argc, argv, tmpvars); - - return (ctx); -} - -struct shttpd_ctx * -shttpd_init(const char *config_file, ...) -{ - struct shttpd_ctx *ctx; - va_list ap; - const char *opt_name, *opt_value; - char *tmpvars[NELEMS(options)]; - const struct opt *opt; - size_t i; - - /* Initialize all temporary holders to NULL */ - for (i = 0; i < NELEMS(tmpvars); i++) - tmpvars[i] = NULL; - - if ((ctx = malloc(sizeof(*ctx))) != NULL) { - - va_start(ap, config_file); - while ((opt_name = va_arg(ap, const char *)) != NULL) { - opt_value = va_arg(ap, const char *); - - if ((opt = find_option(0, opt_name)) == NULL) - elog(E_FATAL, NULL, "shttpd_init: " - "unknown variable [%s]", opt_name); - set_option(opt, opt_value, tmpvars); - } - va_end(ap); - - initialize_context(ctx, config_file, 0, NULL, tmpvars); - } - - return (ctx); -} diff --git a/cpukit/shttpd/defs.h b/cpukit/shttpd/defs.h deleted file mode 100644 index 593dd8bbd0..0000000000 --- a/cpukit/shttpd/defs.h +++ /dev/null @@ -1,492 +0,0 @@ -/* - * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> - * All rights reserved - * - * "THE BEER-WARE LICENSE" (Revision 42): - * Sergey Lyubka wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. - */ - -#ifndef DEFS_HEADER_DEFINED -#define DEFS_HEADER_DEFINED - -#include "std_includes.h" -#include "llist.h" -#include "io.h" -#include "shttpd.h" -#include "md5.h" - -#define VERSION "1.37" /* Version */ - -#ifndef CONFIG -#define CONFIG "shttpd.conf" /* Configuration file */ -#endif /* CONFIG */ - -#define HTPASSWD ".htpasswd" /* Passwords file name */ -#define DFLT_IO_SIZ "16384" /* Default max request size */ -#define HTTP_PORT "80" /* Default listening port */ -#define INDEX_FILES "index.html index.htm index.php index.cgi" -#define CGI_EXT ".cgi .pl .php" /* Default CGI extensions */ -#define REALM "mydomain.com" /* Default authentication realm */ -#define DELIM_CHARS " ," /* Separators for lists */ - -#define EXPIRE_TIME 3600 /* Expiration time, seconds */ -#define ENV_MAX 4096 /* Size of environment block */ -#define CGI_ENV_VARS 64 /* Maximum vars passed to CGI */ -#ifdef __rtems__ -#if defined(__SIZEOF_SIZE_T__) && (__SIZEOF_SIZE_T__ <= 2) -/* HACK: Reduce the array size on targets with 16bit size_t */ -# if defined(__AVR__) -/* FIXME: 1500 is sufficient to avoid compilation breakdown. */ -# define URI_MAX (32767-1500) -# elif defined(__m32c__) -/* FIXME: 1500 is sufficient to avoid compilation breakdown. */ -# define URI_MAX (32767-1500) -# else -/* Theoretically, this should work on all targets with 16bit size_t - * In practice, it trips over other compiler limitations. */ -# define URI_MAX 32767 -# endif -#else // __SIZEOF_SIZE_T__ > 2 -/* HACK: 32768 is 1 too much to fit into 16bit array indices. */ -#define URI_MAX 32767 /* Maximum URI size */ -#endif -#else // __rtems__ -#define URI_MAX 32768 /* Maximum URI size */ -#endif -#define MIN_REQ_LEN 16 /* "GET / HTTP/1.1\n\n" */ - -#define NELEMS(ar) (sizeof(ar) / sizeof(ar[0])) - -#ifdef _DEBUG -#define DBG(x) do { printf x ; putchar('\n'); fflush(stdout); } while (0) -#else -#define DBG(x) -#endif /* DEBUG */ - -#ifdef EMBEDDED -#include "shttpd.h" -#endif /* EMBEDDED */ - -/* - * Darwin prior to 7.0 and Win32 do not have socklen_t - */ -#ifdef NO_SOCKLEN_T -typedef int socklen_t; -#endif /* NO_SOCKLEN_T */ - -/* - * For parsing. This guy represents a substring. - */ -struct vec { - const char *ptr; - int len; -}; - -enum {METHOD_GET, METHOD_POST, METHOD_PUT, METHOD_DELETE, METHOD_HEAD}; -enum {HDR_DATE, HDR_INT, HDR_STRING}; /* HTTP header types */ -enum {E_FATAL = 1, E_LOG = 2}; /* Flags for elog() function */ -typedef unsigned long big_int_t; /* Type for Content-Length */ - -/* - * Unified socket address - */ -struct usa { - socklen_t len; - union { - struct sockaddr sa; - struct sockaddr_in sin; - } u; -}; - -/* - * This thing is aimed to hold values of any type. - * Used to store parsed headers' values. - */ -union variant { - char *v_str; - int v_int; - big_int_t v_big_int; - time_t v_time; - void (*v_func)(void); - void *v_void; - struct vec v_vec; -}; - -/* - * This structure is used to hold mime types and associated file extensions. - */ -struct mime_type { - const char *ext; - int ext_len; - const char *mime; -}; - -struct mime_type_link { - struct llhead link; - char *ext; - int ext_len; - char *mime; -}; - -/* - * This is used only in embedded configuration. This structure holds a - * registered URI, associated callback function with callback data. - * For non-embedded compilation shttpd_callback_t is not defined, so - * we use union variant to keep the compiler silent. - */ -struct registered_uri { - struct llhead link; - const char *uri; - union variant callback; - void *callback_data; -}; - -/* - * User may bind a passwords file to any URI. This makes that URI password - * protected: anybody who accesses that URI will be asked to authorize. - */ -struct uri_auth { - struct llhead link; - const char *uri; - const char *file_name; - size_t uri_len; -}; - -/* - * User may want to handle certain errors. This structure holds the - * handlers for corresponding error codes. - */ -struct error_handler { - struct llhead link; - int code; - union variant callback; - void *callback_data; -}; - -struct http_header { - int len; /* Header name length */ - int type; /* Header type */ - size_t offset; /* Value placeholder */ - const char *name; /* Header name */ -}; - -/* - * This guy holds parsed HTTP headers - */ -struct headers { - union variant cl; /* Content-Length: */ - union variant ct; /* Content-Type: */ - union variant connection; /* Connection: */ - union variant ims; /* If-Modified-Since: */ - union variant user; /* Remote user name */ - union variant auth; /* Authorization */ - union variant useragent; /* User-Agent: */ - union variant referer; /* Referer: */ - union variant cookie; /* Cookie: */ - union variant location; /* Location: */ - union variant range; /* Range: */ - union variant status; /* Status: */ - union variant transenc; /* Transfer-Encoding: */ -}; - -/* Must go after union variant definition */ -#include "ssl.h" - -/* - * The communication channel - */ -union channel { - int fd; /* Regular static file */ - int sock; /* Connected socket */ - struct { - int sock; /* XXX important. must be first */ - SSL *ssl; /* shttpd_poll() assumes that */ - } ssl; /* SSL-ed socket */ - struct { - DIR *dirp; - char *path; - } dir; /* Opened directory */ - struct { - void *state; /* For keeping state */ - union variant func; /* User callback function */ - void *data; /* User defined parameters */ - } emb; /* Embedded, user callback */ -}; - -struct stream; - -/* - * IO class descriptor (file, directory, socket, SSL, CGI, etc) - * These classes are defined in io_*.c files. - */ -struct io_class { - const char *name; - int (*read)(struct stream *, void *buf, size_t len); - int (*write)(struct stream *, const void *buf, size_t len); - void (*close)(struct stream *); -}; - -/* - * Data exchange stream. It is backed by some communication channel: - * opened file, socket, etc. The 'read' and 'write' methods are - * determined by a communication channel. - */ -struct stream { - struct conn *conn; - union channel chan; /* Descriptor */ - struct io io; /* IO buffer */ - const struct io_class *io_class; /* IO class */ - int nread_last; /* Bytes last read */ - int headers_len; - big_int_t content_len; - unsigned int flags; -#define FLAG_HEADERS_PARSED 1 -#define FLAG_SSL_ACCEPTED 2 -#define FLAG_R 4 /* Can read in general */ -#define FLAG_W 8 /* Can write in general */ -#define FLAG_CLOSED 16 -#define FLAG_DONT_CLOSE 32 -#define FLAG_ALWAYS_READY 64 /* File, dir, user_func */ -}; - -struct conn { - struct llhead link; /* Connections chain */ - struct shttpd_ctx *ctx; /* Context this conn belongs to */ - struct usa sa; /* Remote socket address */ - time_t birth_time; /* Creation time */ - time_t expire_time; /* Expiration time */ - - int status; /* Reply status code */ - int method; /* Request method */ - char *uri; /* Decoded URI */ - unsigned long major_version; /* Major HTTP version number */ - unsigned long minor_version; /* Minor HTTP version number */ - char *request; /* Request line */ - char *headers; /* Request headers */ - char *query; /* QUERY_STRING part of the URI */ - char *path_info; /* PATH_INFO thing */ - const char *mime_type; /* Mime type */ - - struct headers ch; /* Parsed client headers */ - - struct stream loc; /* Local stream */ - struct stream rem; /* Remote stream */ -}; - - -/* - * SHTTPD context - */ -struct shttpd_ctx { - time_t start_time; /* Start time */ - int nactive; /* # of connections now */ - unsigned long nrequests; /* Requests made */ - uint64_t in, out; /* IN/OUT traffic counters */ -#if !defined(NO_SSL) - SSL_CTX *ssl_ctx; /* SSL context */ -#endif /* NO_SSL */ - struct llhead connections; /* List of connections */ - - struct llhead mime_types; /* Known mime types */ - struct llhead registered_uris;/* User urls */ - struct llhead uri_auths; /* User auth files */ - struct llhead error_handlers; /* Embedded error handlers */ - - FILE *access_log; /* Access log stream */ - FILE *error_log; /* Error log stream */ - char *put_auth_file; /* PUT auth file */ - char *document_root; /* Document root */ - char *index_files; /* Index files */ - char *aliases; /* Aliases */ - char *mime_file; /* Mime types file */ -#if !defined(NO_CGI) - char *cgi_vars; /* CGI environment variables */ - char *cgi_extensions; /* CGI extensions */ - char *cgi_interpreter; /* CGI script interpreter */ -#endif /* NO_CGI */ - char *auth_realm; /* Auth realm */ - char *global_passwd_file; /* Global passwords file */ - char *uid; /* Run as user */ - int port; /* Listening port */ - int dirlist; /* Directory listing */ - int gui; /* Show GUI flag */ - int auto_start; /* Start on OS boot */ - int io_buf_size; /* IO buffer size */ - int inetd_mode; /* Inetd flag */ -#if defined(_WIN32) - CRITICAL_SECTION mutex; /* For MT case */ - HANDLE ev[2]; /* For thread synchronization */ -#elif defined(__rtems__) - rtems_id mutex; -#endif /* _WIN32 */ -}; - -struct listener { - struct llhead link; - struct shttpd_ctx *ctx; /* Context that socket belongs */ - int sock; /* Listening socket */ -}; - -/* Option setter function */ -typedef void (*optset_t)(struct shttpd_ctx *, void *ptr, const char *string); -struct opt { - int sw; /* Command line switch */ - const char *name; /* Option name in config file */ - const char *desc; /* Description */ - optset_t setter; /* Option setter function */ - size_t ofs; /* Value offset in context */ - const char *arg; /* Argument format */ - const char *def; /* Default option value */ - unsigned int flags; /* Flags */ -#define OPT_BOOL 1 -#define OPT_INT 2 -#define OPT_FILE 4 -#define OPT_DIR 8 -#define OPT_ADVANCED 16 -}; - -extern const struct opt options[]; - -/* - * In SHTTPD, list of values are represented as comma or space separated - * string. For example, list of CGI extensions can be represented as - * ".cgi,.php,.pl", or ".cgi .php .pl". The macro that follows allows to - * loop through the individual values in that list. - * A "const char *" pointer and size_t variable must be passed to the macro. - * Spaces or commas can be used as delimiters (macro DELIM_CHARS) - */ -#define FOR_EACH_WORD_IN_LIST(s,len) \ - for (; s != NULL && (len = strcspn(s, DELIM_CHARS)) != 0; s += len + 1) - -/* - * shttpd.c - */ -extern time_t current_time; /* Current UTC time */ -extern int tz_offset; /* Offset from GMT time zone */ -extern const struct vec known_http_methods[]; - -extern void stop_stream(struct stream *stream); -extern void decode_url_encoded_string(const char *, int, char *dst, int); -extern void send_server_error(struct conn *, int code, const char *reason); -extern int get_headers_len(const char *buf, size_t buflen); -extern void parse_headers(const char *s, int len, struct headers *parsed); - -/* - * mime_type.c - */ -extern const char *get_mime_type(struct shttpd_ctx *, const char *uri, int len); -extern void set_mime_types(struct shttpd_ctx *ctx, const char *path); - -/* - * config.c - */ -extern void usage(const char *prog); -extern struct shttpd_ctx *init_from_argc_argv(const char *, int, char *[]); - -/* - * log.c - */ -extern void elog(int flags, struct conn *c, const char *fmt, ...); -extern void log_access(FILE *fp, const struct conn *c); - -/* - * string.c - */ -#ifndef HAVE_STRLCPY -extern void my_strlcpy(register char *, register const char *, size_t); -#else -#include <string.h> -#define my_strlcpy(d,s,l) strlcpy(d,s,l) -#endif - -#ifndef HAVE_STRNCASECMP -extern int my_strncasecmp(register const char *, - register const char *, size_t); -#else -#ifdef __rtems__ -/* strncasecmp should be in strings.h, but newlib has it in <string.h> */ -#include <string.h> -#else -#include <strings.h> -#endif -#define my_strncasecmp(s1,s2,l) strncasecmp(s1,s2,l) -#endif - -#ifndef HAVE_STRNDUP -extern char *my_strndup(const char *ptr, size_t len); -#else -#include <string.h> -#define my_strndup(x,l) strndup((x),(l)) -#endif - -#ifndef HAVE_STRDUP -extern char *my_strdup(const char *str); -#else -#include <string.h> -#define my_strdup(x) strdup(x) -#endif -extern int my_snprintf(char *buf, size_t buflen, const char *fmt, ...); - -/* - * compat_*.c - */ -extern void set_close_on_exec(int fd); -extern int set_non_blocking_mode(int fd); -#if __rtems__ -#define my_stat stat -#define my_open open -#define my_remove remove -#define my_rename rename -#define my_mkdir mkdir -#define my_getcwd getcwd -#else -extern int my_stat(const char *, struct stat *stp); -extern int my_open(const char *, int flags, int mode); -extern int my_remove(const char *); -extern int my_rename(const char *, const char *); -extern int my_mkdir(const char *, int); -extern char * my_getcwd(char *, int); -#endif -extern int spawn_process(struct conn *c, const char *prog, - char *envblk, char *envp[], int sock, const char *dir); - -/* - * io_*.c - */ -extern const struct io_class io_file; -extern const struct io_class io_socket; -extern const struct io_class io_ssl; -extern const struct io_class io_cgi; -extern const struct io_class io_dir; -extern const struct io_class io_embedded; - -extern int put_dir(const char *path); -extern void get_dir(struct conn *c); -extern void get_file(struct conn *c, struct stat *stp); -extern void ssl_handshake(struct stream *stream); -extern void setup_embedded_stream(struct conn *, union variant, void *); -extern struct registered_uri *is_registered_uri(struct shttpd_ctx *, - const char *uri); - -/* - * auth.c - */ -extern int check_authorization(struct conn *c, const char *path); -extern int is_authorized_for_put(struct conn *c); -extern void send_authorization_request(struct conn *c); -extern int edit_passwords(const char *fname, const char *domain, - const char *user, const char *pass); - -/* - * cgi.c - */ -extern int is_cgi(struct shttpd_ctx *ctx, const char *path); -extern int run_cgi(struct conn *c, const char *prog); -extern void do_cgi(struct conn *c); - -#define CGI_REPLY "HTTP/1.1 OK\r\n" -#define CGI_REPLY_LEN (sizeof(CGI_REPLY) - 1) - -#endif /* DEFS_HEADER_DEFINED */ diff --git a/cpukit/shttpd/io.h b/cpukit/shttpd/io.h deleted file mode 100644 index d774cc2724..0000000000 --- a/cpukit/shttpd/io.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> - * All rights reserved - * - * "THE BEER-WARE LICENSE" (Revision 42): - * Sergey Lyubka wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. - */ - -#ifndef IO_HEADER_INCLUDED -#define IO_HEADER_INCLUDED - -#include <assert.h> -#include <stddef.h> - -/* - * I/O buffer descriptor - */ -struct io { - char *buf; /* IO Buffer */ - size_t size; /* IO buffer size */ - size_t head; /* Bytes read */ - size_t tail; /* Bytes written */ - size_t total; /* Total bytes read */ -}; - -static __inline void -io_clear(struct io *io) -{ - assert(io->buf != NULL); - assert(io->size > 0); - io->total = io->tail = io->head = 0; -} - -static __inline char * -io_space(struct io *io) -{ - assert(io->buf != NULL); - assert(io->size > 0); - assert(io->head <= io->size); - return (io->buf + io->head); -} - -static __inline char * -io_data(struct io *io) -{ - assert(io->buf != NULL); - assert(io->size > 0); - assert(io->tail <= io->size); - return (io->buf + io->tail); -} - -static __inline size_t -io_space_len(const struct io *io) -{ - assert(io->buf != NULL); - assert(io->size > 0); - assert(io->head <= io->size); - return (io->size - io->head); -} - -static __inline size_t -io_data_len(const struct io *io) -{ - assert(io->buf != NULL); - assert(io->size > 0); - assert(io->head <= io->size); - assert(io->tail <= io->head); - return (io->head - io->tail); -} - -static __inline void -io_inc_tail(struct io *io, size_t n) -{ - assert(io->buf != NULL); - assert(io->size > 0); - assert(io->tail <= io->head); - assert(io->head <= io->size); - io->tail += n; - assert(io->tail <= io->head); - if (io->tail == io->head) - io->head = io->tail = 0; -} - -static __inline void -io_inc_head(struct io *io, size_t n) -{ - assert(io->buf != NULL); - assert(io->size > 0); - assert(io->tail <= io->head); - io->head += n; - io->total += n; - assert(io->head <= io->size); -} - -#endif /* IO_HEADER_INCLUDED */ diff --git a/cpukit/shttpd/io_cgi.c b/cpukit/shttpd/io_cgi.c deleted file mode 100644 index 70ff2725fc..0000000000 --- a/cpukit/shttpd/io_cgi.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> - * All rights reserved - * - * "THE BEER-WARE LICENSE" (Revision 42): - * Sergey Lyubka wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. - */ - -#include "defs.h" - -#include <unistd.h> - -static int -write_cgi(struct stream *stream, const void *buf, size_t len) -{ - assert(stream->chan.sock != -1); - assert(stream->flags & FLAG_W); - - return (send(stream->chan.sock, buf, len, 0)); -} - -static int -read_cgi(struct stream *stream, void *buf, size_t len) -{ - struct headers parsed; - char status[4]; - int n; - - assert(stream->chan.sock != -1); - assert(stream->flags & FLAG_R); - - stream->flags &= ~FLAG_DONT_CLOSE; - - n = recv(stream->chan.sock, buf, len, 0); - - if (stream->flags & FLAG_HEADERS_PARSED) - return (n); - - if (n <= 0 && ERRNO != EWOULDBLOCK) { - send_server_error(stream->conn, 500, "Error running CGI"); - return (n); - } - - /* - * CGI script may output Status: and Location: headers, which - * may alter the status code. Buffer in headers, parse - * them, send correct status code and then forward all data - * from CGI script back to the remote end. - * Reply line was alredy appended to the IO buffer in - * decide_what_to_do(), with blank status code. - */ - - stream->flags |= FLAG_DONT_CLOSE; - io_inc_head(&stream->io, n); - - stream->headers_len = get_headers_len(stream->io.buf, stream->io.head); - if (stream->headers_len < 0) { - stream->flags &= ~FLAG_DONT_CLOSE; - send_server_error(stream->conn, 500, "Bad headers sent"); - elog(E_LOG, stream->conn, "CGI script sent invalid headers: " - "[%.*s]", stream->io.head - CGI_REPLY_LEN, - stream->io.buf + CGI_REPLY_LEN); - return (0); - } - - /* - * If we did not received full headers yet, we must not send any - * data read from the CGI back to the client. Suspend sending by - * setting tail = head, which tells that there is no data in IO buffer - */ - - if (stream->headers_len == 0) { - stream->io.tail = stream->io.head; - return (0); - } - - /* Received all headers. Set status code for the connection. */ - (void) memset(&parsed, 0, sizeof(parsed)); - parse_headers(stream->io.buf, stream->headers_len, &parsed); - stream->content_len = parsed.cl.v_big_int; - stream->conn->status = (int) parsed.status.v_big_int; - - /* If script outputs 'Location:' header, set status code to 302 */ - if (parsed.location.v_vec.len > 0) - stream->conn->status = 302; - - /* - * If script did not output neither 'Location:' nor 'Status' headers, - * set the default status code 200, which means 'success'. - */ - if (stream->conn->status == 0) - stream->conn->status = 200; - - /* Append the status line to the beginning of the output */ - (void) my_snprintf(status, sizeof(status), "%3d", stream->conn->status); - (void) memcpy(stream->io.buf + 9, status, 3); - DBG(("read_cgi: content len %lu status %s", - stream->content_len, status)); - - /* Next time, pass output directly back to the client */ - assert((big_int_t) stream->headers_len <= stream->io.total); - stream->io.total -= stream->headers_len; - stream->io.tail = 0; - stream->flags |= FLAG_HEADERS_PARSED; - - /* Return 0 because we've already shifted the head */ - return (0); -} - -static void -close_cgi(struct stream *stream) -{ - assert(stream->chan.sock != -1); - (void) closesocket(stream->chan.sock); -} - -const struct io_class io_cgi = { - "cgi", - read_cgi, - write_cgi, - close_cgi -}; diff --git a/cpukit/shttpd/io_dir.c b/cpukit/shttpd/io_dir.c deleted file mode 100644 index ab331c7fc7..0000000000 --- a/cpukit/shttpd/io_dir.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> - * All rights reserved - * - * "THE BEER-WARE LICENSE" (Revision 42): - * Sergey Lyubka wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. - */ - -#include "defs.h" - -/* - * For a given PUT path, create all intermediate subdirectories - * for given path. Return 0 if the path itself is a directory, - * or -1 on error, 1 if OK. - */ -int -put_dir(const char *path) -{ - char buf[FILENAME_MAX]; - const char *s, *p; - struct stat st; - size_t len; - - for (s = p = path + 2; (p = strchr(s, '/')) != NULL; s = ++p) { - len = p - path; - assert(len < sizeof(buf)); - (void) memcpy(buf, path, len); - buf[len] = '\0'; - - /* Try to create intermediate directory */ - if (my_stat(buf, &st) == -1 && my_mkdir(buf, 0755) != 0) - return (-1); - - /* Is path itself a directory ? */ - if (p[1] == '\0') - return (0); - } - - return (1); -} - -static int -read_dir(struct stream *stream, void *buf, size_t len) -{ - struct dirent *dp = NULL; - char file[FILENAME_MAX], line[FILENAME_MAX + 512], - size[64], mod[64]; - struct stat st; - struct conn *c = stream->conn; - int n, nwritten = 0; - const char *slash = ""; - - assert(stream->chan.dir.dirp != NULL); - assert(stream->conn->uri[0] != '\0'); - - do { - if (len < sizeof(line)) - break; - - if ((dp = readdir(stream->chan.dir.dirp)) == NULL) { - stream->flags |= FLAG_CLOSED; - break; - } - DBG(("read_dir: %s", dp->d_name)); - - /* Do not show current dir and passwords file */ - if (strcmp(dp->d_name, ".") == 0 || - strcmp(dp->d_name, HTPASSWD) == 0) - continue; - - (void) my_snprintf(file, sizeof(file), - "%s%s%s", stream->chan.dir.path, slash, dp->d_name); - (void) my_stat(file, &st); - if (S_ISDIR(st.st_mode)) { - my_snprintf(size,sizeof(size),"%s","<DIR>"); - } else { - if (st.st_size < 1024) - (void) my_snprintf(size, sizeof(size), - "%lu", (unsigned long) st.st_size); - else if (st.st_size < ((size_t)1024 * (size_t)1024)) - (void) my_snprintf(size, sizeof(size), "%luk", - (unsigned long) (st.st_size >> 10) + 1); - else - (void) my_snprintf(size, sizeof(size), - "%.1fM", (float) st.st_size / 1048576); - } - (void) strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", - localtime(&st.st_mtime)); - - n = my_snprintf(line, sizeof(line), - "<tr><td><a href=\"%s%s%s\">%s%s</a></td>" - "<td> %s</td><td> %s</td></tr>\n", - c->uri, slash, dp->d_name, dp->d_name, - S_ISDIR(st.st_mode) ? "/" : "", mod, size); - (void) memcpy(buf, line, n); - buf = (char *) buf + n; - nwritten += n; - len -= n; - } while (dp != NULL); - - return (nwritten); -} - -static void -close_dir(struct stream *stream) -{ - assert(stream->chan.dir.dirp != NULL); - assert(stream->chan.dir.path != NULL); - (void) closedir(stream->chan.dir.dirp); - free(stream->chan.dir.path); -} - -void -get_dir(struct conn *c) -{ - if ((c->loc.chan.dir.dirp = opendir(c->loc.chan.dir.path)) == NULL) { - (void) free(c->loc.chan.dir.path); - send_server_error(c, 500, "Cannot open directory"); - } else { - c->loc.io.head = my_snprintf(c->loc.io.buf, c->loc.io.size, - "HTTP/1.1 200 OK\r\n" - "Content-Type: text/html; charset=utf-8\r\n\r\n" - "<html><head><title>Index of %s</title>" - "<style>th {text-align: left;}</style></head>" - "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">" - "<tr><th>Name</th><th>Modified</th><th>Size</th></tr>" - "<tr><td colspan=\"3\"><hr></td></tr>", - c->uri, c->uri); - io_clear(&c->rem.io); - c->status = 200; - c->loc.io_class = &io_dir; - c->loc.flags |= FLAG_R | FLAG_ALWAYS_READY; - } -} - -const struct io_class io_dir = { - "dir", - read_dir, - NULL, - close_dir -}; diff --git a/cpukit/shttpd/io_emb.c b/cpukit/shttpd/io_emb.c deleted file mode 100644 index ea5d036a6c..0000000000 --- a/cpukit/shttpd/io_emb.c +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> - * All rights reserved - * - * "THE BEER-WARE LICENSE" (Revision 42): - * Sergey Lyubka wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. - */ - -#include "defs.h" - -#ifdef HAVE_STRINGS_H -#include <strings.h> -#endif - -#if defined(EMBEDDED) -const char * -shttpd_version(void) -{ - return (VERSION); -} - -static void -call_user(struct conn *c, struct shttpd_arg *arg, shttpd_callback_t func) -{ - arg->priv = c; - arg->state = c->loc.chan.emb.state; - arg->out.buf = io_space(&c->loc.io); - arg->out.len = io_space_len(&c->loc.io); - arg->out.num_bytes = 0; - arg->in.buf = io_data(&c->rem.io);; - arg->in.len = io_data_len(&c->rem.io); - arg->in.num_bytes = 0; - - func(arg); - - io_inc_head(&c->loc.io, arg->out.num_bytes); - io_inc_tail(&c->rem.io, arg->in.num_bytes); - c->loc.chan.emb.state = arg->state; /* Save state */ - - /* - * If callback finished output, that means it did all cleanup. - * If the connection is terminated unexpectedly, we canna call - * the callback via the stream close() method from disconnect. - * However, if cleanup is already done, we set close() method to - * NULL, to prevent the call from disconnect(). - */ - - if (arg->flags & SHTTPD_END_OF_OUTPUT) - c->loc.flags &= ~FLAG_DONT_CLOSE; - else - c->loc.flags |= FLAG_DONT_CLOSE; -} - -static int -do_embedded(struct stream *stream, void *buf, size_t len) -{ - struct shttpd_arg arg; - buf = NULL; len = 0; /* Squash warnings */ - - arg.user_data = stream->conn->loc.chan.emb.data; - arg.flags = 0; - - call_user(stream->conn, &arg, (shttpd_callback_t) - stream->conn->loc.chan.emb.func.v_func); - - return (0); -} - -static void -close_embedded(struct stream *stream) -{ - struct shttpd_arg arg; - struct conn *c = stream->conn; - - arg.flags = SHTTPD_CONNECTION_ERROR; - arg.user_data = c->loc.chan.emb.data; - - /* - * Do not call the user function if SHTTPD_END_OF_OUTPUT was set, - * i.e. the callback already terminated correctly - */ - if (stream->flags & FLAG_DONT_CLOSE) - call_user(stream->conn, &arg, (shttpd_callback_t) - c->loc.chan.emb.func.v_func); -} - -size_t -shttpd_printf(struct shttpd_arg *arg, const char *fmt, ...) -{ - struct conn *c = arg->priv; - struct io *io = &c->loc.io; - char *buf = io_space(io) + arg->out.num_bytes; - int buflen, len = 0; - va_list ap; - - assert(buf <= io->buf + io->size); - - if ((buflen = (io->buf + io->size) - buf) > 0) { - va_start(ap, fmt); - len = vsnprintf(buf, buflen, fmt, ap); - va_end(ap); - - if (len < 0 || len > buflen) - len = buflen; - arg->out.num_bytes += len; - } - - return (len); -} - -const char * -shttpd_get_header(struct shttpd_arg *arg, const char *header_name) -{ - struct conn *c = arg->priv; - char *p, *s, *e; - size_t len; - - p = c->headers; - e = c->request + c->rem.headers_len; - len = strlen(header_name); - - while (p < e) { - if ((s = strchr(p, '\n')) != NULL) - s[s[-1] == '\r' ? -1 : 0] = '\0'; - if (my_strncasecmp(header_name, p, len) == 0) - return (p + len + 2); - - p += strlen(p) + 1; - } - - return (NULL); -} - -const char * -shttpd_get_env(struct shttpd_arg *arg, const char *env_name) -{ - struct conn *c = arg->priv; - struct vec *vec; - - if (strcmp(env_name, "REQUEST_METHOD") == 0) { - return (known_http_methods[c->method].ptr); - } else if (strcmp(env_name, "REQUEST_URI") == 0) { - return (c->uri); - } else if (strcmp(env_name, "QUERY_STRING") == 0) { - return (c->query); - } else if (strcmp(env_name, "REMOTE_USER") == 0) { - vec = &c->ch.user.v_vec; - if (vec->len > 0) { - ((char *) vec->ptr)[vec->len] = '\0'; - return (vec->ptr); - } - } else if (strcmp(env_name, "REMOTE_ADDR") == 0) { - return (inet_ntoa(c->sa.u.sin.sin_addr));/* FIXME NOT MT safe */ - } - - return (NULL); -} - -void -shttpd_get_http_version(struct shttpd_arg *arg, unsigned long *major, unsigned long *minor) -{ - struct conn *c = arg->priv; - - *major = c->major_version; - *minor = c->minor_version; -} - -void -shttpd_register_uri(struct shttpd_ctx *ctx, - const char *uri, shttpd_callback_t callback, void *data) -{ - struct registered_uri *e; - - if ((e = malloc(sizeof(*e))) != NULL) { - e->uri = my_strdup(uri); - e->callback.v_func = (void (*)(void)) callback; - e->callback_data = data; - LL_TAIL(&ctx->registered_uris, &e->link); - } -} - -#if 0 -struct shttpd_ctx * -shttpd_init2(const char *config_file, char *names[], char *values[], size_t n) -{ - size_t i; - - for (i = 0; i < n; i++) - set_option(names[i], values[i]); - - return (init_ctx(config_file, 0, NULL)); -} -#endif - -void -shttpd_protect_uri(struct shttpd_ctx *ctx, const char *uri, const char *file) -{ - struct uri_auth *auth; - - if ((auth = malloc(sizeof(*auth))) != NULL) { - auth->uri = my_strdup(uri); - auth->file_name = my_strdup(file); - auth->uri_len = strlen(uri); - LL_ADD(&ctx->uri_auths, &auth->link); - } -} - -int -shttpd_get_var(const char *var, const char *buf, int buf_len, - char *value, int value_len) -{ - const char *p, *e, *s; - size_t var_len; - - var_len = strlen(var); - e = buf + buf_len - var_len; - - /* buf is "var1=val1&var2=val2...". Find variable first */ - for (p = buf; p < e; p++) - if (!my_strncasecmp(var, p, var_len) && p[var_len] == '=') { - - /* Found. Shift to variable value */ - e = buf + buf_len; - p += var_len + 1; - - /* Find where the value ends */ - if ((s = memchr(p, '&', e - p)) == NULL) - s = e; - - /* Copy value into the buffer, decoding it */ - decode_url_encoded_string(p, s - p, value, value_len); - - return (1); - } - - return (0); -} - -static int -match_regexp(const char *regexp, const char *text) -{ - if (*regexp == '\0') - return (*text == '\0'); - - if (*regexp == '*') - do { - if (match_regexp(regexp + 1, text)) - return (1); - } while (*text++ != '\0'); - - if (*text != '\0' && *regexp == *text) - return (match_regexp(regexp + 1, text + 1)); - - return (0); -} - -struct registered_uri * -is_registered_uri(struct shttpd_ctx *ctx, const char *uri) -{ - struct llhead *lp; - struct registered_uri *reg_uri; - - LL_FOREACH(&ctx->registered_uris, lp) { - reg_uri = LL_ENTRY(lp, struct registered_uri, link); - if (match_regexp(reg_uri->uri, uri)) - return (reg_uri); - } - - return (NULL); -} - -void -setup_embedded_stream(struct conn *c, union variant func, void *data) -{ - c->loc.chan.emb.state = NULL; - c->loc.chan.emb.func = func; - c->loc.chan.emb.data = data; - c->loc.io_class = &io_embedded; - c->loc.flags |= FLAG_R | FLAG_W |FLAG_ALWAYS_READY; -} - -void -shttpd_handle_error(struct shttpd_ctx *ctx, int code, - shttpd_callback_t func, void *data) -{ - struct error_handler *e; - - if ((e = malloc(sizeof(*e))) != NULL) { - e->code = code; - e->callback.v_func = (void (*)(void)) func; - e->callback_data = data; - LL_TAIL(&ctx->error_handlers, &e->link); - } -} - -const struct io_class io_embedded = { - "embedded", - do_embedded, - (int (*)(struct stream *, const void *, size_t)) do_embedded, - close_embedded -}; - -#endif /* EMBEDDED */ diff --git a/cpukit/shttpd/io_file.c b/cpukit/shttpd/io_file.c deleted file mode 100644 index fedc2df28c..0000000000 --- a/cpukit/shttpd/io_file.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> - * All rights reserved - * - * "THE BEER-WARE LICENSE" (Revision 42): - * Sergey Lyubka wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. - */ - -#include "defs.h" - -#include <unistd.h> - -static int -write_file(struct stream *stream, const void *buf, size_t len) -{ - struct stat st; - struct stream *rem = &stream->conn->rem; - int n, fd = stream->chan.fd; - - assert(fd != -1); - n = write(fd, buf, len); - - DBG(("put_file(%p, %d): %d bytes", (void *) stream, len, n)); - - if (n <= 0 || (rem->io.total >= (big_int_t) rem->headers_len)) { - (void) fstat(fd, &st); - stream->io.head = stream->headers_len = - my_snprintf(stream->io.buf, - stream->io.size, "HTTP/1.1 %d OK\r\n" - "Content-Length: %lu\r\nConnection: close\r\n\r\n", - stream->conn->status, st.st_size); - stop_stream(stream); - } - - return (n); -} - -static int -read_file(struct stream *stream, void *buf, size_t len) -{ -#ifdef USE_SENDFILE - struct iovec vec; - struct sf_hdtr hd = {&vec, 1, NULL, 0}, *hdp = &hd; - int sock, fd, n; - size_t nbytes; - off_t sent; - - sock = stream->conn->rem.chan.sock; - fd = stream->chan.fd; - - /* If this is the first call for this file, send the headers */ - vec.iov_base = stream->io.buf; - vec.iov_len = stream->headers_len; - if (stream->io.total > 0) - hdp = NULL; - - nbytes = stream->content_len - stream->io.total; - n = sendfile(fd, sock, lseek(fd, 0, SEEK_CUR), nbytes, hdp, &sent, 0); - - if (n == -1 && ERRNO != EAGAIN) { - stream->flags &= ~FLAG_DONT_CLOSE; - return (n); - } - - stream->conn->ctx->out += sent; - - /* If we have sent the HTTP headers in this turn, clear them off */ - if (stream->io.total == 0) { - assert(sent >= stream->headers_len); - sent -= stream->headers_len; - io_clear(&stream->io); - } - - (void) lseek(fd, sent, SEEK_CUR); - stream->io.total += sent; - stream->flags |= FLAG_DONT_CLOSE; - - return (0); -#endif /* USE_SENDFILE */ - - assert(stream->chan.fd != -1); - return (read(stream->chan.fd, buf, len)); -} - -static void -close_file(struct stream *stream) -{ - assert(stream->chan.fd != -1); - (void) close(stream->chan.fd); -} - -void -get_file(struct conn *c, struct stat *stp) -{ - char date[64], lm[64], etag[64], range[64] = ""; - size_t n, status = 200; - unsigned long r1, r2; - const char *fmt = "%a, %d %b %Y %H:%M:%S GMT", *msg = "OK"; - big_int_t cl; /* Content-Length */ - - if (c->mime_type == NULL) - c->mime_type = get_mime_type(c->ctx, c->uri, strlen(c->uri)); - cl = (big_int_t) stp->st_size; - - /* If Range: header specified, act accordingly */ - if (c->ch.range.v_vec.len > 0 && - (n = sscanf(c->ch.range.v_vec.ptr,"bytes=%lu-%lu",&r1, &r2)) > 0) { - status = 206; - (void) lseek(c->loc.chan.fd, r1, SEEK_SET); - cl = n == 2 ? r2 - r1 + 1: cl - r1; - (void) my_snprintf(range, sizeof(range), - "Content-Range: bytes %lu-%lu/%lu\r\n", - r1, r1 + cl - 1, (unsigned long) stp->st_size); - msg = "Partial Content"; - } - - /* Prepare Etag, Date, Last-Modified headers */ - (void) strftime(date, sizeof(date), fmt, localtime(¤t_time)); - (void) strftime(lm, sizeof(lm), fmt, localtime(&stp->st_mtime)); - (void) my_snprintf(etag, sizeof(etag), "%lx.%lx", - (unsigned long) stp->st_mtime, (unsigned long) stp->st_size); - - /* - * We do not do io_inc_head here, because it will increase 'total' - * member in io. We want 'total' to be equal to the content size, - * and exclude the headers length from it. - */ - c->loc.io.head = c->loc.headers_len = my_snprintf(c->loc.io.buf, - c->loc.io.size, - "HTTP/1.1 %d %s\r\n" - "Date: %s\r\n" - "Last-Modified: %s\r\n" - "Etag: \"%s\"\r\n" - "Content-Type: %s\r\n" - "Content-Length: %lu\r\n" - "Connection: close\r\n" - "%s\r\n", - status, msg, date, lm, etag, c->mime_type, cl, range); - - c->status = status; - c->loc.content_len = cl; - c->loc.io_class = &io_file; - c->loc.flags |= FLAG_R | FLAG_ALWAYS_READY; - - if (c->method == METHOD_HEAD) - stop_stream(&c->loc); -} - -const struct io_class io_file = { - "file", - read_file, - write_file, - close_file -}; diff --git a/cpukit/shttpd/io_socket.c b/cpukit/shttpd/io_socket.c deleted file mode 100644 index 151419af51..0000000000 --- a/cpukit/shttpd/io_socket.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> - * All rights reserved - * - * "THE BEER-WARE LICENSE" (Revision 42): - * Sergey Lyubka wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. - */ - -#include "defs.h" - -#include <unistd.h> - -static int -read_socket(struct stream *stream, void *buf, size_t len) -{ - assert(stream->chan.sock != -1); - return (recv(stream->chan.sock, buf, len, 0)); -} - -static int -write_socket(struct stream *stream, const void *buf, size_t len) -{ - assert(stream->chan.sock != -1); - return (send(stream->chan.sock, buf, len, 0)); -} - -static void -close_socket(struct stream *stream) -{ - assert(stream->chan.sock != -1); - (void) closesocket(stream->chan.sock); -} - -const struct io_class io_socket = { - "socket", - read_socket, - write_socket, - close_socket -}; diff --git a/cpukit/shttpd/io_ssl.c b/cpukit/shttpd/io_ssl.c deleted file mode 100644 index 753257fd8d..0000000000 --- a/cpukit/shttpd/io_ssl.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> - * All rights reserved - * - * "THE BEER-WARE LICENSE" (Revision 42): - * Sergey Lyubka wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. - */ - -#include "defs.h" - -#if !defined(NO_SSL) -struct ssl_func ssl_sw[] = { - {"SSL_free", {0}}, - {"SSL_accept", {0}}, - {"SSL_connect", {0}}, - {"SSL_read", {0}}, - {"SSL_write", {0}}, - {"SSL_get_error", {0}}, - {"SSL_set_fd", {0}}, - {"SSL_new", {0}}, - {"SSL_CTX_new", {0}}, - {"SSLv23_server_method", {0}}, - {"SSL_library_init", {0}}, - {"SSL_CTX_use_PrivateKey_file", {0}}, - {"SSL_CTX_use_certificate_file",{0}}, - {NULL, {0}} -}; - -void -ssl_handshake(struct stream *stream) -{ - int n; - - if ((n = SSL_accept(stream->chan.ssl.ssl)) == 0) { - n = SSL_get_error(stream->chan.ssl.ssl, n); - if (n != SSL_ERROR_WANT_READ && n != SSL_ERROR_WANT_WRITE) - stream->flags |= FLAG_CLOSED; - elog(E_LOG, stream->conn, "SSL_accept error %d", n); - } else { - DBG(("handshake: SSL accepted")); - stream->flags |= FLAG_SSL_ACCEPTED; - } -} - -static int -read_ssl(struct stream *stream, void *buf, size_t len) -{ - int nread = 0; - - assert(stream->chan.ssl.ssl != NULL); - - if (!(stream->flags & FLAG_SSL_ACCEPTED)) - ssl_handshake(stream); - - if (stream->flags & FLAG_SSL_ACCEPTED) - nread = SSL_read(stream->chan.ssl.ssl, buf, len); - - return (nread); -} - -static int -write_ssl(struct stream *stream, const void *buf, size_t len) -{ - assert(stream->chan.ssl.ssl != NULL); - return (SSL_write(stream->chan.ssl.ssl, buf, len)); -} - -static void -close_ssl(struct stream *stream) -{ - assert(stream->chan.ssl.sock != -1); - assert(stream->chan.ssl.ssl != NULL); - (void) closesocket(stream->chan.ssl.sock); - SSL_free(stream->chan.ssl.ssl); -} - -const struct io_class io_ssl = { - "ssl", - read_ssl, - write_ssl, - close_ssl -}; -#endif /* !NO_SSL */ diff --git a/cpukit/shttpd/llist.h b/cpukit/shttpd/llist.h deleted file mode 100644 index 04e79bba12..0000000000 --- a/cpukit/shttpd/llist.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> - * All rights reserved - * - * "THE BEER-WARE LICENSE" (Revision 42): - * Sergey Lyubka wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. - */ - -#ifndef LLIST_HEADER_INCLUDED -#define LLIST_HEADER_INCLUDED - -/* - * Linked list macros. - */ -struct llhead { - struct llhead *prev; - struct llhead *next; -}; - -#define LL_INIT(N) ((N)->next = (N)->prev = (N)) - -#define LL_HEAD(H) struct llhead H = { &H, &H } - -#define LL_ENTRY(P,T,N) ((T *)((char *)(P) - offsetof(T, N))) - -#define LL_ADD(H, N) \ - do { \ - ((H)->next)->prev = (N); \ - (N)->next = ((H)->next); \ - (N)->prev = (H); \ - (H)->next = (N); \ - } while (0) - -#define LL_TAIL(H, N) \ - do { \ - ((H)->prev)->next = (N); \ - (N)->prev = ((H)->prev); \ - (N)->next = (H); \ - (H)->prev = (N); \ - } while (0) - -#define LL_DEL(N) \ - do { \ - ((N)->next)->prev = ((N)->prev); \ - ((N)->prev)->next = ((N)->next); \ - LL_INIT(N); \ - } while (0) - -#define LL_EMPTY(N) ((N)->next == (N)) - -#define LL_FOREACH(H,N) for (N = (H)->next; N != (H); N = (N)->next) - -#define LL_FOREACH_SAFE(H,N,T) \ - for (N = (H)->next, T = (N)->next; N != (H); \ - N = (T), T = (N)->next) - -#endif /* LLIST_HEADER_INCLUDED */ diff --git a/cpukit/shttpd/log.c b/cpukit/shttpd/log.c deleted file mode 100644 index 4786daec1e..0000000000 --- a/cpukit/shttpd/log.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> - * All rights reserved - * - * "THE BEER-WARE LICENSE" (Revision 42): - * Sergey Lyubka wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. - */ - -#include "defs.h" - -/* - * Log function - */ -void -elog(int flags, struct conn *c, const char *fmt, ...) -{ - char date[64], buf[URI_MAX]; - int len; - FILE *fp = c == NULL ? NULL : c->ctx->error_log; - va_list ap; - - /* Print to stderr */ - if (c == NULL || c->ctx->inetd_mode == 0) { - va_start(ap, fmt); - (void) vfprintf(stderr, fmt, ap); - (void) fputc('\n', stderr); - va_end(ap); - } - - strftime(date, sizeof(date), "%a %b %d %H:%M:%S %Y", - localtime(¤t_time)); - - len = my_snprintf(buf, sizeof(buf), - "[%s] [error] [client %s] \"%s\" ", - date, c ? inet_ntoa(c->sa.u.sin.sin_addr) : "-", - c && c->request ? c->request : "-"); - - va_start(ap, fmt); - (void) vsnprintf(buf + len, sizeof(buf) - len, fmt, ap); - va_end(ap); - - buf[sizeof(buf) - 1] = '\0'; - - if (fp != NULL && (flags & (E_FATAL | E_LOG))) { - (void) fprintf(fp, "%s\n", buf); - (void) fflush(fp); - } - -#if defined(_WIN32) && !defined(NO_GUI) - { - extern HWND hLog; - - if (hLog != NULL) - SendMessage(hLog, WM_APP, 0, (LPARAM) buf); - } -#endif /* _WIN32 */ - - if (flags & E_FATAL) - exit(EXIT_FAILURE); -} - -/* - * HACK: m68k-gcc <= 4.2.1 ICEs on the snprintf below for some - * coldfire variants for yet unknown reasons. - * C.f.: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=32307 - - * T.S, 2008/3/25 -- 4.2.3 still has this problem - */ -#if defined(__GNUC__) && \ - ( (__GNUC__ < 4 ) || \ - ( (__GNUC__ == 4 ) && (__GNUC_MINOR__ < 2 ) ) || \ - ( (__GNUC__ == 4 ) && (__GNUC_MINOR__ == 2 ) && (__GNUC_PATCHLEVEL__ <= 3 ) ) ) -#if defined(__mcoldfire__) -#define SPLIT_SNPRINTF 1 -#endif /* __mcoldfire__ */ -#endif /* __GNUC__ */ - -void -log_access(FILE *fp, const struct conn *c) -{ - static const struct vec dash = {"-", 1}; - - const struct vec *user = &c->ch.user.v_vec; - const struct vec *referer = &c->ch.referer.v_vec; - const struct vec *user_agent = &c->ch.useragent.v_vec; - char date[64], buf[URI_MAX], *q1 = "\"", *q2 = "\""; - - if (user->len == 0) - user = ‐ - - if (referer->len == 0) { - referer = ‐ - q1 = ""; - } - - if (user_agent->len == 0) { - user_agent = ‐ - q2 = ""; - } - - (void) strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S", - localtime(¤t_time)); - -#if SPLIT_SNPRINTF - { - int num; - num = my_snprintf(buf, sizeof(buf), - "%s - %.*s [%s %+05d] \"%s\" %d %lu", - inet_ntoa(c->sa.u.sin.sin_addr), user->len, user->ptr, - date, tz_offset, c->request ? c->request : "-", - c->status, c->loc.io.total ); - my_snprintf(&buf[num], sizeof(buf)-num, " %s%.*s%s" " %s%.*s%s", - q1, referer->len, referer->ptr, q1, - q2, user_agent->len, user_agent->ptr, q2); - } -#else - (void) my_snprintf(buf, sizeof(buf), - "%s - %.*s [%s %+05d] \"%s\" %d %lu %s%.*s%s %s%.*s%s", - inet_ntoa(c->sa.u.sin.sin_addr), user->len, user->ptr, - date, tz_offset, c->request ? c->request : "-", - c->status, (unsigned long) c->loc.io.total, - q1, referer->len, referer->ptr, q1, - q2, user_agent->len, user_agent->ptr, q2); -#endif - - if (fp != NULL) { - (void) fprintf(fp, "%s\n", buf); - (void) fflush(fp); - } - -#if defined(_WIN32) && !defined(NO_GUI) - { - extern HWND hLog; - - if (hLog != NULL) - SendMessage(hLog, WM_APP, 0, (LPARAM) buf); - } -#endif /* _WIN32 */ -} diff --git a/cpukit/shttpd/md5.c b/cpukit/shttpd/md5.c deleted file mode 100644 index 4e9c4701d6..0000000000 --- a/cpukit/shttpd/md5.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * This code implements the MD5 message-digest algorithm. - * The algorithm is due to Ron Rivest. This code was - * written by Colin Plumb in 1993, no copyright is claimed. - * This code is in the public domain; do with it what you wish. - * - * Equivalent code is available from RSA Data Security, Inc. - * This code has been tested against that, and is equivalent, - * except that you don't need to include two pages of legalese - * with every copy. - * - * To compute the message digest of a chunk of bytes, declare an - * MD5Context structure, pass it to MD5Init, call MD5Update as - * needed on buffers full of bytes, and then call MD5Final, which - * will fill a supplied 16-byte array with the digest. - */ - -#include "defs.h" - -#ifndef HAVE_MD5 -#if __BYTE_ORDER == 1234 -#define byteReverse(buf, len) /* Nothing */ -#else -/* - * Note: this code is harmless on little-endian machines. - */ -static void byteReverse(unsigned char *buf, unsigned longs) -{ - uint32_t t; - do { - t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 | - ((unsigned) buf[1] << 8 | buf[0]); - *(uint32_t *) buf = t; - buf += 4; - } while (--longs); -} -#endif /* __BYTE_ORDER */ - -/* The four core functions - F1 is optimized somewhat */ - -/* #define F1(x, y, z) (x & y | ~x & z) */ -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -/* This is the central step in the MD5 algorithm. */ -#define MD5STEP(f, w, x, y, z, data, s) \ -( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) - -/* - * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious - * initialization constants. - */ -void MD5Init(MD5_CTX *ctx) -{ - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; - - ctx->bits[0] = 0; - ctx->bits[1] = 0; -} - -/* - * The core of the MD5 algorithm, this alters an existing MD5 hash to - * reflect the addition of 16 longwords of new data. MD5Update blocks - * the data and converts bytes into longwords for this routine. - */ -static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) -{ - register uint32_t a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} - -/* - * Update context to reflect the concatenation of another buffer full - * of bytes. - */ -void -MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len) -{ - uint32_t t; - - /* Update bitcount */ - - t = ctx->bits[0]; - if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) - ctx->bits[1]++; /* Carry from low to high */ - ctx->bits[1] += len >> 29; - - t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ - - /* Handle any leading odd-sized chunks */ - - if (t) { - unsigned char *p = (unsigned char *) ctx->in + t; - - t = 64 - t; - if (len < t) { - memcpy(p, buf, len); - return; - } - memcpy(p, buf, t); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32_t *) ctx->in); - buf += t; - len -= t; - } - /* Process data in 64-byte chunks */ - - while (len >= 64) { - memcpy(ctx->in, buf, 64); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32_t *) ctx->in); - buf += 64; - len -= 64; - } - - /* Handle any remaining bytes of data. */ - - memcpy(ctx->in, buf, len); -} - -/* - * Final wrapup - pad to 64-byte boundary with the bit pattern - * 1 0* (64-bit count of bits processed, MSB-first) - */ -void -MD5Final(unsigned char digest[16], MD5_CTX *ctx) -{ - unsigned count; - unsigned char *p; - - /* Compute number of bytes mod 64 */ - count = (ctx->bits[0] >> 3) & 0x3F; - - /* Set the first char of padding to 0x80. This is safe since there is - always at least one byte free */ - p = ctx->in + count; - *p++ = 0x80; - - /* Bytes of padding needed to make 64 bytes */ - count = 64 - 1 - count; - - /* Pad out to 56 mod 64 */ - if (count < 8) { - /* Two lots of padding: Pad the first block to 64 bytes */ - memset(p, 0, count); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32_t *) ctx->in); - - /* Now fill the next block with 56 bytes */ - memset(ctx->in, 0, 56); - } else { - /* Pad block to 56 bytes */ - memset(p, 0, count - 8); - } - byteReverse(ctx->in, 14); - - /* Append length in bits and transform */ - ((uint32_t *) ctx->in)[14] = ctx->bits[0]; - ((uint32_t *) ctx->in)[15] = ctx->bits[1]; - - MD5Transform(ctx->buf, (uint32_t *) ctx->in); - byteReverse((unsigned char *) ctx->buf, 4); - memcpy(digest, ctx->buf, 16); - memset((char *) ctx, 0, sizeof(ctx)); /* In case it's sensitive */ -} - -#endif /* !HAVE_MD5 */ diff --git a/cpukit/shttpd/md5.h b/cpukit/shttpd/md5.h deleted file mode 100644 index fcca00ecfb..0000000000 --- a/cpukit/shttpd/md5.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> - * All rights reserved - * - * "THE BEER-WARE LICENSE" (Revision 42): - * Sergey Lyubka wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. - */ - -#ifndef MD5_HEADER_INCLUDED -#define MD5_HEADER_INCLUDED - -typedef struct MD5Context { - uint32_t buf[4]; - uint32_t bits[2]; - unsigned char in[64]; -} MD5_CTX; - -extern void MD5Init(MD5_CTX *ctx); -extern void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len); -extern void MD5Final(unsigned char digest[16], MD5_CTX *ctx); - -#endif /*MD5_HEADER_INCLUDED */ diff --git a/cpukit/shttpd/mime_type.c b/cpukit/shttpd/mime_type.c deleted file mode 100644 index 7c9422d284..0000000000 --- a/cpukit/shttpd/mime_type.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> - * All rights reserved - * - * "THE BEER-WARE LICENSE" (Revision 42): - * Sergey Lyubka wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. - */ - -#include "defs.h" - -#ifdef HAVE_STRINGS_H -#include <strings.h> -#endif - -static const struct mime_type default_mime_types[] = { - {"html", 4, "text/html" }, - {"htm", 3, "text/html" }, - {"txt", 3, "text/plain" }, - {"css", 3, "text/css" }, - {"ico", 3, "image/x-icon" }, - {"gif", 3, "image/gif" }, - {"jpg", 3, "image/jpeg" }, - {"jpeg", 4, "image/jpeg" }, - {"png", 3, "image/png" }, - {"svg", 3, "image/svg+xml" }, - {"torrent", 7, "application/x-bittorrent" }, - {"wav", 3, "audio/x-wav" }, - {"mp3", 3, "audio/x-mp3" }, - {"mid", 3, "audio/mid" }, - {"m3u", 3, "audio/x-mpegurl" }, - {"ram", 3, "audio/x-pn-realaudio" }, - {"ra", 2, "audio/x-pn-realaudio" }, - {"doc", 3, "application/msword", }, - {"exe", 3, "application/octet-stream" }, - {"zip", 3, "application/x-zip-compressed" }, - {"xls", 3, "application/excel" }, - {"tgz", 3, "application/x-tar-gz" }, - {"tar.gz", 6, "application/x-tar-gz" }, - {"tar", 3, "application/x-tar" }, - {"gz", 2, "application/x-gunzip" }, - {"arj", 3, "application/x-arj-compressed" }, - {"rar", 3, "application/x-arj-compressed" }, - {"rtf", 3, "application/rtf" }, - {"pdf", 3, "application/pdf" }, - {"mpg", 3, "video/mpeg" }, - {"mpeg", 4, "video/mpeg" }, - {"asf", 3, "video/x-ms-asf" }, - {"avi", 3, "video/x-msvideo" }, - {"bmp", 3, "image/bmp" }, - {NULL, 0, NULL } -}; - -const char * -get_mime_type(struct shttpd_ctx *ctx, const char *uri, int len) -{ - struct llhead *lp; - const struct mime_type *mt; - struct mime_type_link *mtl; - const char *s; - - /* Firt, loop through the custom mime types if any */ - LL_FOREACH(&ctx->mime_types, lp) { - mtl = LL_ENTRY(lp, struct mime_type_link, link); - s = uri + len - mtl->ext_len; - if (s > uri && s[-1] == '.' && - !my_strncasecmp(mtl->ext, s, mtl->ext_len)) - return (mtl->mime); - } - - /* If no luck, try built-in mime types */ - for (mt = default_mime_types; mt->ext != NULL; mt++) { - s = uri + len - mt->ext_len; - if (s > uri && s[-1] == '.' && - !my_strncasecmp(mt->ext, s, mt->ext_len)) - return (mt->mime); - } - - /* Oops. This extension is unknown to us. Fallback to text/plain */ - return ("text/plain"); -} - -void -set_mime_types(struct shttpd_ctx *ctx, const char *path) -{ - FILE *fp; - char line[512], ext[sizeof(line)], mime[sizeof(line)], *s; - - if ((fp = fopen(path, "r")) == NULL) - elog(E_FATAL, NULL, "set_mime_types: fopen(%s): %s", - path, strerror(errno)); - - while (fgets(line, sizeof(line), fp) != NULL) { - /* Skip empty lines */ - if (line[0] == '#' || line[0] == '\n') - continue; - if (sscanf(line, "%s", mime)) { - s = line + strlen(mime); - while (*s && *s != '\n' && sscanf(s, "%s", ext)) { - shttpd_add_mime_type(ctx, ext, mime); - s += strlen(mime); - } - } - } - - (void) fclose(fp); -} diff --git a/cpukit/shttpd/preinstall.am b/cpukit/shttpd/preinstall.am deleted file mode 100644 index 9983a14e70..0000000000 --- a/cpukit/shttpd/preinstall.am +++ /dev/null @@ -1,39 +0,0 @@ -## Automatically generated by ampolish3 - Do not edit - -if AMPOLISH3 -$(srcdir)/preinstall.am: Makefile.am - $(AMPOLISH3) $(srcdir)/Makefile.am > $(srcdir)/preinstall.am -endif - -PREINSTALL_DIRS = -DISTCLEANFILES = $(PREINSTALL_DIRS) - -all-local: $(TMPINSTALL_FILES) - -TMPINSTALL_FILES = -CLEANFILES = $(TMPINSTALL_FILES) - -all-am: $(PREINSTALL_FILES) - -PREINSTALL_FILES = -CLEANFILES += $(PREINSTALL_FILES) - -$(PROJECT_LIB)/$(dirstamp): - @$(MKDIR_P) $(PROJECT_LIB) - @: > $(PROJECT_LIB)/$(dirstamp) -PREINSTALL_DIRS += $(PROJECT_LIB)/$(dirstamp) - -if LIBSHTTPD -$(PROJECT_INCLUDE)/shttpd/$(dirstamp): - @$(MKDIR_P) $(PROJECT_INCLUDE)/shttpd - @: > $(PROJECT_INCLUDE)/shttpd/$(dirstamp) -PREINSTALL_DIRS += $(PROJECT_INCLUDE)/shttpd/$(dirstamp) - -$(PROJECT_LIB)/libshttpd.a: libshttpd.a $(PROJECT_LIB)/$(dirstamp) - $(INSTALL_DATA) $< $(PROJECT_LIB)/libshttpd.a -TMPINSTALL_FILES += $(PROJECT_LIB)/libshttpd.a - -$(PROJECT_INCLUDE)/shttpd/shttpd.h: shttpd.h $(PROJECT_INCLUDE)/shttpd/$(dirstamp) - $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/shttpd/shttpd.h -PREINSTALL_FILES += $(PROJECT_INCLUDE)/shttpd/shttpd.h -endif diff --git a/cpukit/shttpd/shttpd.1 b/cpukit/shttpd/shttpd.1 deleted file mode 100644 index a7ec641ab5..0000000000 --- a/cpukit/shttpd/shttpd.1 +++ /dev/null @@ -1,135 +0,0 @@ -.\" Process this file with -.\" groff -man -Tascii shttpd.1 -.\" $Id$ -.Dd Nov 10, 2006 -.Dt SHTTPD 1 -.Sh NAME -.Nm shttpd -.Nd lightweight web server -.Sh SYNOPSIS -.Nm -.Op Ar OPTIONS -.Op Ar config_file -.Nm -.Fl A Ar htpasswd_file realm username password -.Sh DESCRIPTION -.Nm -is small, fast and easy to use web server with CGI, SSL, Digest Authorization -support. It can be run as stand-alone server, be managed by -.Xr inetd 8 -, or be embedded into existing C/C++ application. -.Pp -Unlike other web servers, -.Nm -does not expect CGI scirpts to be put in a special directory. They may be -anywhere. CGI files are recognized by an extension, which is -.Dq .cgi -by default. -.Pp -By default -.Nm -does not use SSL and starts listening on port 80. Specifying the -.Fl s Ar pem_file -option automatically switches -.Nm -to SSL mode on port 443. -.Pp -.Nm -can take configuration parameters from two sources: from the command -line and from the configuration file. Command line parameters have -higher priority. Every command line parameter has associated configuration -file keyword, except -.Fl A -parameter. -In the configuration file, blank lines and lines started with -.Dq # -character are ignored. All other lines must start with the keyword -followed by a whitespace followed by keyword's value. -If both command line parameter and configuration -file option are not specified, the default value is taken. The configuration -file may not be present at all. -.Pp -If -.Nm -should be managed by -.Xr inetd 8 , -add this line to -.Pa inetd.conf : -.Pp -.Dl http stream tcp nowait nobody /path/to/shttpd shttpd -I1 -d /my/www -.Pp -.Sh OPTIONS -Below is the list of command line parameters. In the brackets there are -corresponding configuration file keywords. -.Bl -tag -width indent -.It Fl A Ar htpasswd server_name user_name user_password -Edit the passwords file. Functionality similar to Apache's -.Ic htdigest -utility. -.It Fl C Ar file ( Cm cgi_interpreter Ar file ) -Force -.Ar file -to be a CGI interpreter for all CGI scripts. Default: none. -.It Fl D Ar 0|1 ( Cm list_directories Ar 0|1 ) -Disable directory listing. Default: enabled. -.It Fl I Ar 0|1 ( Cm inetd_mode Ar 0|1 ) -Enable inetd mode. Default: disabled. -.It Fl N Ar realm ( Cm server_name Ar realm ) -Authorization realm. Default: -.Dq mydomain.com . -.It Fl P Ar file ( Cm global_htpasswd Ar file ) -Location of global passwords file. Per-directory .htpasswd files are -ignored, if this option is set. Default: not set. -.It Fl U Ar file ( Cm put_auth Ar file ) -PUT and DELETE passwords file. This must be specified if PUT or -DELETE methods are used. Default: none. -.It Fl V Ar string ( Cm cgi_envvar Ar string ) -Pass additional environment variables to the CGI script. These must be -comma-separated list of var=val pairs, like this: "VAR1=VAL1,VAR2=VAL2". -Default: not set. -.It Fl a Ar string ( Cm aliases Ar string ) -Attach directories (even those outside document_root) to URIs. The -.Ar string -must be comma-separated list of var=val pairs, like this: -"/etc/=/my_etc,/tmp=/my_tmp". Default: not set. -.It Fl c Ar string ( Cm cgi_extension Ar string ) -CGI filename pattern. For every requested file, -.Nm -uses the pattern to figure out whether to return the file content, -ot run the file as CGI application. Default: -.Dq .cgi . -.It Fl d Ar directory ( Cm document_root Ar directory ) -Location of the WWW root directory. Default: working directory from which -.Nm -has been started. -.It Fl e Ar file ( Cm error_log Ar file ) -Error log file. Default: not set, no errors are logged. -.It Fl l Ar file ( Cm access_log Ar file ) -Access log file. Default: not set, no logging is done. -.It Fl m Ar file ( Cm mime_types Ar file ) -Location of mime types file. Default: not set, builtins are used. -.It Fl p Ar port ( Cm listen_port Ar port ) -Listening port. Default: 80 for non-SSL and 443 for SSL mode. -.It Fl s Ar pem_file ( Cm ssl_certificate Ar pem_file ) -Location of SSL certificate file. Default: not set. -.It Fl u Ar login ( Cm runtime_uid Ar login ) -Switch to given user ID after startup. Default: not set -.El -.Pp -.Sh EMBEDDING -.Nm -can be built as a library to embed web server functionality -into C/C++ application. The API functions are declared in a header -file -.Pa shttpd.h . -Please refer to the source package for a header file and the examples. -.Sh FILES -.Pa /usr/local/etc/shttpd.conf -.br -.Sh SEE ALSO -.Xr inetd 8 . -.Sh COPYRIGHT -.Nm -is licensed under the terms of beerware license. -.Sh AUTHOR -.An Sergey Lyubka Aq valenok@gmail.com . diff --git a/cpukit/shttpd/shttpd.c b/cpukit/shttpd/shttpd.c deleted file mode 100644 index 66dc7fd846..0000000000 --- a/cpukit/shttpd/shttpd.c +++ /dev/null @@ -1,1135 +0,0 @@ -/* - * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> - * All rights reserved - * - * "THE BEER-WARE LICENSE" (Revision 42): - * Sergey Lyubka wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. - */ - -/* - * Small and portable HTTP server, http://shttpd.sourceforge.net - * $Id$ - */ - -#include "defs.h" - -#include <unistd.h> -#ifdef HAVE_STRINGS_H -#include <strings.h> -#endif - -time_t current_time; /* Current UTC time */ -int tz_offset; /* Time zone offset from UTC */ - -static LL_HEAD(listeners); /* List of listening sockets */ - -const struct vec known_http_methods[] = { - {"GET", 3}, - {"POST", 4}, - {"PUT", 3}, - {"DELETE", 6}, - {"HEAD", 4}, - {NULL, 0} -}; - -/* - * This structure tells how HTTP headers must be parsed. - * Used by parse_headers() function. - */ -#define OFFSET(x) offsetof(struct headers, x) -static const struct http_header http_headers[] = { - {16, HDR_INT, OFFSET(cl), "Content-Length: " }, - {14, HDR_STRING, OFFSET(ct), "Content-Type: " }, - {12, HDR_STRING, OFFSET(useragent), "User-Agent: " }, - {19, HDR_DATE, OFFSET(ims), "If-Modified-Since: " }, - {15, HDR_STRING, OFFSET(auth), "Authorization: " }, - {9, HDR_STRING, OFFSET(referer), "Referer: " }, - {8, HDR_STRING, OFFSET(cookie), "Cookie: " }, - {10, HDR_STRING, OFFSET(location), "Location: " }, - {8, HDR_INT, OFFSET(status), "Status: " }, - {7, HDR_STRING, OFFSET(range), "Range: " }, - {12, HDR_STRING, OFFSET(connection), "Connection: " }, - {19, HDR_STRING, OFFSET(transenc), "Transfer-Encoding: " }, - {0, HDR_INT, 0, NULL } -}; - -struct shttpd_ctx *init_ctx(const char *config_file, int argc, char *argv[]); - -void -decode_url_encoded_string(const char *src, int src_len, char *dst, int dst_len) -{ - int i, j, a, b; -#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W') - - for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) - switch (src[i]) { - case '%': - if (isxdigit(((unsigned char *) src)[i + 1]) && - isxdigit(((unsigned char *) src)[i + 2])) { - a = tolower(((unsigned char *)src)[i + 1]); - b = tolower(((unsigned char *)src)[i + 2]); - dst[j] = (HEXTOI(a) << 4) | HEXTOI(b); - i += 2; - } else { - dst[j] = '%'; - } - break; - case '+': - dst[j] = ' '; - break; - default: - dst[j] = src[i]; - break; - } - - dst[j] = '\0'; /* Null-terminate the destination */ -} - -void -shttpd_add_mime_type(struct shttpd_ctx *ctx, const char *ext, const char *mime) -{ - struct mime_type_link *e; - const char *error_msg = "shttpd_add_mime_type: no memory"; - - if ((e = malloc(sizeof(*e))) == NULL) { - elog(E_FATAL, 0, error_msg); - } else if ((e->ext= my_strdup(ext)) == NULL) { - elog(E_FATAL, 0, error_msg); - } else if ((e->mime = my_strdup(mime)) == NULL) { - elog(E_FATAL, 0, error_msg); - } else { - e->ext_len = strlen(ext); - LL_TAIL(&ctx->mime_types, &e->link); - } -} - - -static const char * -is_alias(struct shttpd_ctx *ctx, const char *uri, - struct vec *a_uri, struct vec *a_path) -{ - const char *p, *s = ctx->aliases; - size_t len; - - DBG(("is_alias: aliases [%s]", s == NULL ? "" : s)); - - FOR_EACH_WORD_IN_LIST(s, len) { - if ((p = memchr(s, '=', len)) != NULL && - memcmp(uri, s, p - s) == 0) { - a_uri->ptr = s; - a_uri->len = p - s; - a_path->ptr = ++p; - a_path->len = (s + len) - p; - return (s); - } - } - - return (NULL); -} - -void -stop_stream(struct stream *stream) -{ - if (stream->io_class != NULL && stream->io_class->close != NULL) - stream->io_class->close(stream); - - stream->io_class= NULL; - stream->flags |= FLAG_CLOSED; - stream->flags &= ~(FLAG_R | FLAG_W | FLAG_ALWAYS_READY); - - DBG(("%d %s stopped. %lu of content data, %d now in a buffer", - stream->conn->rem.chan.sock, - stream->io_class ? stream->io_class->name : "(null)", - (unsigned long) stream->io.total, io_data_len(&stream->io))); -} - -/* - * Setup listening socket on given port, return socket - */ -static int -open_listening_port(int port) -{ - int sock, on = 1; - struct usa sa; - -#ifdef _WIN32 - {WSADATA data; WSAStartup(MAKEWORD(2,2), &data);} -#endif /* _WIN32 */ - - sa.len = sizeof(sa.u.sin); - sa.u.sin.sin_family = AF_INET; - sa.u.sin.sin_port = htons((uint16_t) port); - sa.u.sin.sin_addr.s_addr = htonl(INADDR_ANY); - - if ((sock = socket(PF_INET, SOCK_STREAM, 6)) == -1) - goto fail; - if (set_non_blocking_mode(sock) != 0) - goto fail; - if (setsockopt(sock, SOL_SOCKET, - SO_REUSEADDR,(char *) &on, sizeof(on)) != 0) - goto fail; - if (bind(sock, &sa.u.sa, sa.len) < 0) - goto fail; - if (listen(sock, 128) != 0) - goto fail; - -#ifndef _WIN32 - (void) fcntl(sock, F_SETFD, FD_CLOEXEC); -#endif /* !_WIN32 */ - - return (sock); -fail: - if (sock != -1) - (void) closesocket(sock); - elog(E_LOG, NULL, "open_listening_port(%d): %s", port, strerror(errno)); - return (-1); -} - -/* - * Check whether full request is buffered Return headers length, or 0 - */ -int -get_headers_len(const char *buf, size_t buflen) -{ - const char *s, *e; - int len = 0; - - for (s = buf, e = s + buflen - 1; len == 0 && s < e; s++) - /* Control characters are not allowed but >=128 is. */ - if (!isprint(*(unsigned char *)s) && *s != '\r' && *s != '\n' && *(unsigned char *)s < 128) - len = -1; - else if (s[0] == '\n' && s[1] == '\n') - len = s - buf + 2; - else if (s[0] == '\n' && &s[1] < e && - s[1] == '\r' && s[2] == '\n') - len = s - buf + 3; - - return (len); -} - -/* - * Send error message back to a client. - */ -void -send_server_error(struct conn *c, int status, const char *reason) -{ -#ifdef EMBEDDED - struct llhead *lp; - struct error_handler *e; - - LL_FOREACH(&c->ctx->error_handlers, lp) { - e = LL_ENTRY(lp, struct error_handler, link); - - if (e->code == status) { - if (c->loc.io_class != NULL && - c->loc.io_class->close != NULL) - c->loc.io_class->close(&c->loc); - io_clear(&c->loc.io); - setup_embedded_stream(c, e->callback, NULL); - return; - } - } -#endif /* EMBEDDED */ - - io_clear(&c->loc.io); - c->loc.headers_len = c->loc.io.head = my_snprintf(c->loc.io.buf, - c->loc.io.size, "HTTP/1.1 %d %s\r\n\r\n%d %s", - status, reason, status, reason); - c->status = status; - stop_stream(&c->loc); -} - -/* - * Convert month to the month number. Return -1 on error, or month number - */ -static int -montoi(const char *s) -{ - static const char *ar[] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" - }; - size_t i; - - for (i = 0; i < sizeof(ar) / sizeof(ar[0]); i++) - if (!strcmp(s, ar[i])) - return (i); - - return (-1); -} - -/* - * Parse date-time string, and return the corresponding time_t value - */ -static time_t -date_to_epoch(const char *s) -{ - struct tm tm, *tmp; - char mon[32]; - int sec, min, hour, mday, month, year; - - (void) memset(&tm, 0, sizeof(tm)); - sec = min = hour = mday = month = year = 0; - - if (((sscanf(s, "%d/%3s/%d %d:%d:%d", - &mday, mon, &year, &hour, &min, &sec) == 6) || - (sscanf(s, "%d %3s %d %d:%d:%d", - &mday, mon, &year, &hour, &min, &sec) == 6) || - (sscanf(s, "%*3s, %d %3s %d %d:%d:%d", - &mday, mon, &year, &hour, &min, &sec) == 6) || - (sscanf(s, "%d-%3s-%d %d:%d:%d", - &mday, mon, &year, &hour, &min, &sec) == 6)) && - (month = montoi(mon)) != -1) { - tm.tm_mday = mday; - tm.tm_mon = month; - tm.tm_year = year; - tm.tm_hour = hour; - tm.tm_min = min; - tm.tm_sec = sec; - } - - if (tm.tm_year > 1900) - tm.tm_year -= 1900; - else if (tm.tm_year < 70) - tm.tm_year += 100; - - /* Set Daylight Saving Time field */ - tmp = localtime(¤t_time); - tm.tm_isdst = tmp->tm_isdst; - - return (mktime(&tm)); -} - -static void -remove_double_dots(char *s) -{ - char *p = s; - - while (*s != '\0') { - *p++ = *s++; - if (s[-1] == '/') - while (*s == '.' || *s == '/') - s++; - } - *p = '\0'; -} - -void -parse_headers(const char *s, int len, struct headers *parsed) -{ - const struct http_header *h; - union variant *v; - const char *p, *e = s + len; - - DBG(("parsing headers (len %d): [%.*s]", len, len, s)); - - /* Loop through all headers in the request */ - while (s < e) { - - /* Find where this header ends */ - for (p = s; p < e && *p != '\n'; ) p++; - - /* Is this header known to us ? */ - for (h = http_headers; h->len != 0; h++) - if (e - s > h->len && - !my_strncasecmp(s, h->name, h->len)) - break; - - /* If the header is known to us, store its value */ - if (h->len != 0) { - - /* Shift to where value starts */ - s += h->len; - - /* Find place to store the value */ - v = (union variant *) ((char *) parsed + h->offset); - - /* Fetch header value into the connection structure */ - if (h->type == HDR_STRING) { - v->v_vec.ptr = s; - v->v_vec.len = p - s; - if (p[-1] == '\r' && v->v_vec.len > 0) - v->v_vec.len--; - } else if (h->type == HDR_INT) { - v->v_big_int = strtoul(s, NULL, 10); - } else if (h->type == HDR_DATE) { - v->v_time = date_to_epoch(s); - } - } - - s = p + 1; /* Shift to the next header */ - } -} - -/* - * For given directory path, substitute it to valid index file. - * Return 0 if index file has been found, -1 if not found - */ -static int -find_index_file(struct conn *c, char *path, size_t maxpath, struct stat *stp) -{ - char buf[FILENAME_MAX]; - const char *s = c->ctx->index_files; - size_t len; - - FOR_EACH_WORD_IN_LIST(s, len) { - my_snprintf(buf, sizeof(buf), "%s%c%.*s",path, DIRSEP, len, s); - if (my_stat(buf, stp) == 0) { - my_strlcpy(path, buf, maxpath); - c->mime_type = get_mime_type(c->ctx, s, len); - return (0); - } - } - - return (-1); -} - -/* - * Try to open requested file, return 0 if OK, -1 if error. - * If the file is given arguments using PATH_INFO mechanism, - * initialize pathinfo pointer. - */ -static int -get_path_info(struct conn *c, char *path, struct stat *stp) -{ - char *p, *e; - - if (my_stat(path, stp) == 0) - return (0); - - p = path + strlen(path); - e = path + strlen(c->ctx->document_root) + 2; - - /* Strip directory parts of the path one by one */ - for (; p > e; p--) - if (*p == '/') { - *p = '\0'; - if (!my_stat(path, stp) && !S_ISDIR(stp->st_mode)) { - c->path_info = p + 1; - return (0); - } else { - *p = '/'; - } - } - - return (-1); -} - - -static void -decide_what_to_do(struct conn *c) -{ - char path[URI_MAX], buf[1024]; - struct vec alias_uri, alias_path; - struct stat st; - int rc; -#ifdef EMBEDDED - struct registered_uri *ruri; -#endif /* EMBEDDED */ - - DBG(("decide_what_to_do: [%s]", c->uri)); - - if ((c->query = strchr(c->uri, '?')) != NULL) - *c->query++ = '\0'; - - decode_url_encoded_string(c->uri, strlen(c->uri), - c->uri, strlen(c->uri) + 1); - remove_double_dots(c->uri); - - if (strlen(c->uri) + strlen(c->ctx->document_root) >= sizeof(path)) { - send_server_error(c, 400, "URI is too long"); - return; - } - - (void) my_snprintf(path, sizeof(path), "%s%s", - c->ctx->document_root, c->uri); - - /* User may use the aliases - check URI for mount point */ - if (is_alias(c->ctx, c->uri, &alias_uri, &alias_path) != NULL) { - (void) my_snprintf(path, sizeof(path), "%.*s%s", - alias_path.len, alias_path.ptr, c->uri + alias_uri.len); - DBG(("using alias %.*s -> %.*s", alias_uri.len, alias_uri.ptr, - alias_path.len, alias_path.ptr)); - } - -#if !defined(NO_AUTH) - if (check_authorization(c, path) != 1) { - send_authorization_request(c); - } else -#endif /* NO_AUTH */ -#ifdef EMBEDDED - if ((ruri = is_registered_uri(c->ctx, c->uri)) != NULL) { - setup_embedded_stream(c, ruri->callback, ruri->callback_data); - } else -#endif /* EMBEDDED */ - if (strstr(path, HTPASSWD)) { - /* Do not allow to view passwords files */ - send_server_error(c, 403, "Forbidden"); - } else -#if !defined(NO_AUTH) - if ((c->method == METHOD_PUT || c->method == METHOD_DELETE) && - (c->ctx->put_auth_file == NULL || !is_authorized_for_put(c))) { - send_authorization_request(c); - } else -#endif /* NO_AUTH */ - if (c->method == METHOD_PUT) { - c->status = my_stat(path, &st) == 0 ? 200 : 201; - - if (c->ch.range.v_vec.len > 0) { - send_server_error(c, 501, "PUT Range Not Implemented"); - } else if ((rc = put_dir(path)) == 0) { - send_server_error(c, 200, "OK"); - } else if (rc == -1) { - send_server_error(c, 500, "PUT Directory Error"); - } else if (c->rem.content_len == 0) { - send_server_error(c, 411, "Length Required"); - } else if ((c->loc.chan.fd = my_open(path, O_WRONLY | O_BINARY | - O_CREAT | O_NONBLOCK | O_TRUNC, 0644)) == -1) { - send_server_error(c, 500, "PUT Error"); - } else { - DBG(("PUT file [%s]", c->uri)); - c->loc.io_class = &io_file; - c->loc.flags |= FLAG_W | FLAG_ALWAYS_READY ; - } - } else if (c->method == METHOD_DELETE) { - DBG(("DELETE [%s]", c->uri)); - if (my_remove(path) == 0) - send_server_error(c, 200, "OK"); - else - send_server_error(c, 500, "DELETE Error"); - } else if (get_path_info(c, path, &st) != 0) { - send_server_error(c, 404, "Not Found"); - } else if (S_ISDIR(st.st_mode) && path[strlen(path) - 1] != '/') { - (void) my_snprintf(buf, sizeof(buf), - "Moved Permanently\r\nLocation: %s/", c->uri); - send_server_error(c, 301, buf); - } else if (S_ISDIR(st.st_mode) && - find_index_file(c, path, sizeof(path) - 1, &st) == -1 && - c->ctx->dirlist == 0) { - send_server_error(c, 403, "Directory Listing Denied"); - } else if (S_ISDIR(st.st_mode) && c->ctx->dirlist) { - if ((c->loc.chan.dir.path = my_strdup(path)) != NULL) - get_dir(c); - else - send_server_error(c, 500, "GET Directory Error"); - } else if (S_ISDIR(st.st_mode) && c->ctx->dirlist == 0) { - send_server_error(c, 403, "Directory listing denied"); -#ifndef NO_CGI - } else if (is_cgi(c->ctx, path)) { - if (c->method != METHOD_POST && c->method != METHOD_GET) { - send_server_error(c, 501, "Bad method "); - } else if ((run_cgi(c, path)) == -1) { - send_server_error(c, 500, "Cannot exec CGI"); - } else { - do_cgi(c); - } -#endif /* NO_CGI */ - } else if (c->ch.ims.v_time && st.st_mtime <= c->ch.ims.v_time) { - send_server_error(c, 304, "Not Modified"); - } else if ((c->loc.chan.fd = my_open(path, - O_RDONLY | O_BINARY, 0644)) != -1) { - get_file(c, &st); - } else { - send_server_error(c, 500, "Internal Error"); - } -} - -static int -set_request_method(struct conn *c) -{ - const struct vec *v; - - assert(c->rem.io.head >= MIN_REQ_LEN); - - /* Set the request method */ - for (v = known_http_methods; v->ptr != NULL; v++) - if (!memcmp(c->rem.io.buf, v->ptr, v->len)) { - c->method = v - known_http_methods; - break; - } - - return (v->ptr == NULL); -} - -static void -parse_http_request(struct conn *c) -{ - char *s, *e, *p, *start; - char *end_number; - int uri_len, req_len; - - s = c->rem.io.buf; - req_len = c->rem.headers_len = get_headers_len(s, c->rem.io.head); - - if (req_len == 0 && io_space_len(&c->rem.io) == 0) - send_server_error(c, 400, "Request is too big"); - - if (req_len == 0) - return; - else if (req_len < MIN_REQ_LEN) - send_server_error(c, 400, "Bad request"); - else if (set_request_method(c)) - send_server_error(c, 501, "Method Not Implemented"); - else if ((c->request = my_strndup(s, req_len)) == NULL) - send_server_error(c, 500, "Cannot allocate request"); - - if (c->loc.flags & FLAG_CLOSED) - return; - - DBG(("Conn %d: parsing request: [%.*s]", c->rem.chan.sock, req_len, s)); - c->rem.flags |= FLAG_HEADERS_PARSED; - - /* Set headers pointer. Headers follow the request line */ - c->headers = memchr(c->request, '\n', req_len); - assert(c->headers != NULL); - assert(c->headers < c->request + req_len); - if (c->headers > c->request && c->headers[-1] == '\r') - c->headers[-1] = '\0'; - *c->headers++ = '\0'; - - /* - * Now make a copy of the URI, because it will be URL-decoded, - * and we need a copy of unmodified URI for the access log. - * First, we skip the REQUEST_METHOD and shift to the URI. - */ - for (p = c->request, e = p + req_len; *p != ' ' && p < e; p++); - while (p < e && *p == ' ') p++; - - /* Now remember where URI starts, and shift to the end of URI */ - for (start = p; p < e && !isspace((unsigned char)*p); ) p++; - uri_len = p - start; - /* Skip space following the URI */ - while (p < e && *p == ' ') p++; - - /* Now comes the HTTP-Version in the form HTTP/<major>.<minor> */ - if (strncmp(p, "HTTP/", 5) != 0) { - send_server_error(c, 400, "Bad HTTP version"); - return; - } - p += 5; - /* Parse the HTTP major version number */ - c->major_version = strtoul(p, &end_number, 10); - if (end_number == p || *end_number != '.') { - send_server_error(c, 400, "Bad HTTP major version"); - return; - } - p = end_number + 1; - /* Parse the minor version number */ - c->minor_version = strtoul(p, &end_number, 10); - if (end_number == p || *end_number != '\0') { - send_server_error(c, 400, "Bad HTTP minor version"); - return; - } - /* Version must be <=1.1 */ - if (c->major_version > 1 || - (c->major_version == 1 && c->minor_version > 1)) { - send_server_error(c, 505, "HTTP version not supported"); - return; - } - - if (uri_len <= 0) { - send_server_error(c, 400, "Bad URI"); - } else if ((c->uri = malloc(uri_len + 1)) == NULL) { - send_server_error(c, 500, "Cannot allocate URI"); - } else { - my_strlcpy(c->uri, (char *) start, uri_len + 1); - parse_headers(c->headers, - (c->request + req_len) - c->headers, &c->ch); - - /* Remove the length of request from total, count only data */ - assert(c->rem.io.total >= (big_int_t) req_len); - c->rem.io.total -= req_len; - - c->rem.content_len = c->ch.cl.v_big_int; - io_inc_tail(&c->rem.io, req_len); - - decide_what_to_do(c); - } -} - -void -shttpd_add_socket(struct shttpd_ctx *ctx, int sock) -{ - struct conn *c; - struct usa sa; - int l = ctx->inetd_mode ? E_FATAL : E_LOG; -#if !defined(NO_SSL) - SSL *ssl = NULL; -#endif /* NO_SSL */ - - sa.len = sizeof(sa.u.sin); - (void) set_non_blocking_mode(sock); - - if (getpeername(sock, &sa.u.sa, &sa.len)) { - elog(l, NULL, "add_socket: %s", strerror(errno)); -#if !defined(NO_SSL) - } else if (ctx->ssl_ctx && (ssl = SSL_new(ctx->ssl_ctx)) == NULL) { - elog(l, NULL, "add_socket: SSL_new: %s", strerror(ERRNO)); - (void) closesocket(sock); - } else if (ctx->ssl_ctx && SSL_set_fd(ssl, sock) == 0) { - elog(l, NULL, "add_socket: SSL_set_fd: %s", strerror(ERRNO)); - (void) closesocket(sock); - SSL_free(ssl); -#endif /* NO_SSL */ - } else if ((c = calloc(1, sizeof(*c) + 2 * ctx->io_buf_size)) == NULL) { - -#if !defined(NO_SSL) - if (ssl) - SSL_free(ssl); -#endif /* NO_SSL */ - (void) closesocket(sock); - elog(l, NULL, "add_socket: calloc: %s", strerror(ERRNO)); - } else { - ctx->nrequests++; - c->rem.conn = c->loc.conn = c; - c->ctx = ctx; - c->sa = sa; - c->birth_time = current_time; - c->expire_time = current_time + EXPIRE_TIME; - - set_close_on_exec(sock); - - c->loc.io_class = NULL; - - c->rem.io_class = &io_socket; - c->rem.chan.sock = sock; - - /* Set IO buffers */ - c->loc.io.buf = (char *) (c + 1); - c->rem.io.buf = c->loc.io.buf + ctx->io_buf_size; - c->loc.io.size = c->rem.io.size = ctx->io_buf_size; - -#if !defined(NO_SSL) - if (ssl) { - c->rem.io_class = &io_ssl; - c->rem.chan.ssl.sock = sock; - c->rem.chan.ssl.ssl = ssl; - ssl_handshake(&c->rem); - } -#endif /* NO_SSL */ - - EnterCriticalSection(&ctx->mutex); - LL_TAIL(&ctx->connections, &c->link); - ctx->nactive++; - LeaveCriticalSection(&ctx->mutex); - - DBG(("%s:%hu connected (socket %d)", - inet_ntoa(* (struct in_addr *) &sa.u.sin.sin_addr.s_addr), - ntohs(sa.u.sin.sin_port), sock)); - } -} - -int -shttpd_active(struct shttpd_ctx *ctx) -{ - return (ctx->nactive); -} - -/* - * Setup a listening socket on given port. Return opened socket or -1 - */ -int -shttpd_listen(struct shttpd_ctx *ctx, int port) -{ - struct listener *l; - int sock; - - if ((sock = open_listening_port(port)) == -1) { - } else if ((l = calloc(1, sizeof(*l))) == NULL) { - (void) closesocket(sock); - } else { - l->sock = sock; - l->ctx = ctx; - LL_TAIL(&listeners, &l->link); - DBG(("shttpd_listen: added socket %d", sock)); - } - - return (sock); -} - -int -shttpd_accept(int lsn_sock, int milliseconds) -{ - struct timeval tv; - struct usa sa; - fd_set read_set; - int sock = -1; - - tv.tv_sec = milliseconds / 1000; - tv.tv_usec = milliseconds % 1000; - sa.len = sizeof(sa.u.sin); - FD_ZERO(&read_set); - FD_SET(lsn_sock, &read_set); - - if (select(lsn_sock + 1, &read_set, NULL, NULL, &tv) == 1) - sock = accept(lsn_sock, &sa.u.sa, &sa.len); - - return (sock); -} - -static void -read_stream(struct stream *stream) -{ - int n, len; - - len = io_space_len(&stream->io); - assert(len > 0); - - /* Do not read more that needed */ - if (stream->content_len > 0 && - stream->io.total + len > stream->content_len) - len = stream->content_len - stream->io.total; - - /* Read from underlying channel */ - n = stream->nread_last = stream->io_class->read(stream, - io_space(&stream->io), len); - - if (n > 0) - io_inc_head(&stream->io, n); - else if (n == -1 && (ERRNO == EINTR || ERRNO == EWOULDBLOCK)) - n = n; /* Ignore EINTR and EAGAIN */ - else if (!(stream->flags & FLAG_DONT_CLOSE)) - stop_stream(stream); - - DBG(("read_stream (%d %s): read %d/%d/%lu bytes (errno %d)", - stream->conn->rem.chan.sock, - stream->io_class ? stream->io_class->name : "(null)", - n, len, (unsigned long) stream->io.total, ERRNO)); - - /* - * Close the local stream if everything was read - * XXX We do not close the remote stream though! It may be - * a POST data completed transfer, we do not want the socket - * to be closed. - */ - if (stream->content_len > 0 && stream == &stream->conn->loc) { - assert(stream->io.total <= stream->content_len); - if (stream->io.total == stream->content_len) - stop_stream(stream); - } - - stream->conn->expire_time = current_time + EXPIRE_TIME; -} - -static void -write_stream(struct stream *from, struct stream *to) -{ - int n, len; - - len = io_data_len(&from->io); - assert(len > 0); - - /* TODO: should be assert on CAN_WRITE flag */ - n = to->io_class->write(to, io_data(&from->io), len); - to->conn->expire_time = current_time + EXPIRE_TIME; - DBG(("write_stream (%d %s): written %d/%d bytes (errno %d)", - to->conn->rem.chan.sock, - to->io_class ? to->io_class->name : "(null)", n, len, ERRNO)); - - if (n > 0) - io_inc_tail(&from->io, n); - else if (n == -1 && (ERRNO == EINTR || ERRNO == EWOULDBLOCK)) - n = n; /* Ignore EINTR and EAGAIN */ - else if (!(to->flags & FLAG_DONT_CLOSE)) - stop_stream(to); -} - - -static void -disconnect(struct conn *c) -{ - static const struct vec ka = {"keep-alive", 10}; - int dont_close; - - DBG(("Disconnecting %d (%.*s)", c->rem.chan.sock, - c->ch.connection.v_vec.len, c->ch.connection.v_vec.ptr)); - -#if !defined(_WIN32) || defined(NO_GUI) - if (c->ctx->access_log != NULL) -#endif /* _WIN32 */ - log_access(c->ctx->access_log, c); - - /* In inetd mode, exit if request is finished. */ - if (c->ctx->inetd_mode) - exit(0); - - if (c->loc.io_class != NULL && c->loc.io_class->close != NULL) - c->loc.io_class->close(&c->loc); - - /* - * Check the "Connection: " header before we free c->request - * If it its 'keep-alive', then do not close the connection - */ - dont_close = c->ch.connection.v_vec.len >= ka.len && - !my_strncasecmp(ka.ptr, c->ch.connection.v_vec.ptr, ka.len); - - if (c->request) - free(c->request); - if (c->uri) - free(c->uri); - - /* Handle Keep-Alive */ - dont_close = 0; - if (dont_close) { - c->loc.io_class = NULL; - c->loc.flags = c->rem.flags = 0; - c->query = c->request = c->uri = c->path_info = NULL; - c->mime_type = NULL; - (void) memset(&c->ch, 0, sizeof(c->ch)); - io_clear(&c->rem.io); - io_clear(&c->loc.io); - c->rem.io.total = c->loc.io.total = 0; - } else { - if (c->rem.io_class != NULL) - c->rem.io_class->close(&c->rem); - - EnterCriticalSection(&c->ctx->mutex); - LL_DEL(&c->link); - c->ctx->nactive--; - assert(c->ctx->nactive >= 0); - LeaveCriticalSection(&c->ctx->mutex); - - free(c); - } -} - -static void -add_to_set(int fd, fd_set *set, int *max_fd) -{ - FD_SET(fd, set); - if (fd > *max_fd) - *max_fd = fd; -} - -/* - * One iteration of server loop. This is the core of the data exchange. - */ -void -shttpd_poll(struct shttpd_ctx *ctx, int milliseconds) -{ - struct llhead *lp, *tmp; - struct listener *l; - struct conn *c; - struct timeval tv; /* Timeout for select() */ - fd_set read_set, write_set; - int sock, max_fd = -1, msec = milliseconds; - struct usa sa; - - current_time = time(0); - FD_ZERO(&read_set); - FD_ZERO(&write_set); - - /* Add listening sockets to the read set */ - LL_FOREACH(&listeners, lp) { - l = LL_ENTRY(lp, struct listener, link); - FD_SET(l->sock, &read_set); - if (l->sock > max_fd) - max_fd = l->sock; - DBG(("FD_SET(%d) (listening)", l->sock)); - } - - /* Multiplex streams */ - LL_FOREACH(&ctx->connections, lp) { - c = LL_ENTRY(lp, struct conn, link); - - /* If there is a space in remote IO, check remote socket */ - if (io_space_len(&c->rem.io)) - add_to_set(c->rem.chan.fd, &read_set, &max_fd); - -#if !defined(NO_CGI) - /* - * If there is a space in local IO, and local endpoint is - * CGI, check local socket for read availability - */ - if (io_space_len(&c->loc.io) && (c->loc.flags & FLAG_R) && - c->loc.io_class == &io_cgi) - add_to_set(c->loc.chan.fd, &read_set, &max_fd); - - /* - * If there is some data read from remote socket, and - * local endpoint is CGI, check local for write availability - */ - if (io_data_len(&c->rem.io) && (c->loc.flags & FLAG_W) && - c->loc.io_class == &io_cgi) - add_to_set(c->loc.chan.fd, &write_set, &max_fd); -#endif /* NO_CGI */ - - /* - * If there is some data read from local endpoint, check the - * remote socket for write availability - */ - if (io_data_len(&c->loc.io)) - add_to_set(c->rem.chan.fd, &write_set, &max_fd); - - if (io_space_len(&c->loc.io) && (c->loc.flags & FLAG_R) && - (c->loc.flags & FLAG_ALWAYS_READY)) - msec = 0; - - if (io_data_len(&c->rem.io) && (c->loc.flags & FLAG_W) && - (c->loc.flags & FLAG_ALWAYS_READY)) - msec = 0; - } - - tv.tv_sec = msec / 1000; - tv.tv_usec = msec % 1000; - - /* Check IO readiness */ - if (select(max_fd + 1, &read_set, &write_set, NULL, &tv) < 0) { -#ifdef _WIN32 - /* - * On windows, if read_set and write_set are empty, - * select() returns "Invalid parameter" error - * (at least on my Windows XP Pro). So in this case, - * we sleep here. - */ - Sleep(milliseconds); -#endif /* _WIN32 */ - DBG(("select: %d", ERRNO)); - return; - } - - /* Check for incoming connections on listener sockets */ - LL_FOREACH(&listeners, lp) { - l = LL_ENTRY(lp, struct listener, link); - if (!FD_ISSET(l->sock, &read_set)) - continue; - do { - sa.len = sizeof(sa.u.sin); - if ((sock = accept(l->sock, &sa.u.sa, &sa.len)) != -1) { -#if defined(_WIN32) - shttpd_add_socket(ctx, sock); -#else - if (sock < FD_SETSIZE) { - shttpd_add_socket(ctx, sock); - } else { - elog(E_LOG, NULL, - "shttpd_poll: ctx %p: disarding " - "socket %d, too busy", ctx, sock); - (void) closesocket(sock); - } -#endif /* _WIN32 */ - } - } while (sock != -1); - } - - /* Process all connections */ - LL_FOREACH_SAFE(&ctx->connections, lp, tmp) { - c = LL_ENTRY(lp, struct conn, link); - - /* Read from remote end if it is ready */ - if (FD_ISSET(c->rem.chan.fd, &read_set) && - io_space_len(&c->rem.io)) - read_stream(&c->rem); - - /* If the request is not parsed yet, do so */ - if (!(c->rem.flags & FLAG_HEADERS_PARSED)) - parse_http_request(c); - - DBG(("loc: %u [%.*s]", io_data_len(&c->loc.io), - io_data_len(&c->loc.io), io_data(&c->loc.io))); - DBG(("rem: %u [%.*s]", io_data_len(&c->rem.io), - io_data_len(&c->rem.io), io_data(&c->rem.io))); - - /* Read from the local end if it is ready */ - if (io_space_len(&c->loc.io) && - ((c->loc.flags & FLAG_ALWAYS_READY) - -#if !defined(NO_CGI) - ||(c->loc.io_class == &io_cgi && - FD_ISSET(c->loc.chan.fd, &read_set)) -#endif /* NO_CGI */ - )) - read_stream(&c->loc); - - if (io_data_len(&c->rem.io) > 0 && (c->loc.flags & FLAG_W) && - c->loc.io_class != NULL && c->loc.io_class->write != NULL) - write_stream(&c->rem, &c->loc); - - if (io_data_len(&c->loc.io) > 0 && c->rem.io_class != NULL) - write_stream(&c->loc, &c->rem); - - if (c->rem.nread_last > 0) - c->ctx->in += c->rem.nread_last; - if (c->loc.nread_last > 0) - c->ctx->out += c->loc.nread_last; - - /* Check whether we should close this connection */ - if ((current_time > c->expire_time) || - (c->rem.flags & FLAG_CLOSED) || - ((c->loc.flags & FLAG_CLOSED) && !io_data_len(&c->loc.io))) - disconnect(c); - } -} - -/* - * Deallocate shttpd object, free up the resources - */ -void -shttpd_fini(struct shttpd_ctx *ctx) -{ - struct llhead *lp, *tmp; - struct mime_type_link *mtl; - struct conn *c; - struct listener *l; - struct registered_uri *ruri; - - /* Free configured mime types */ - LL_FOREACH_SAFE(&ctx->mime_types, lp, tmp) { - mtl = LL_ENTRY(lp, struct mime_type_link, link); - free(mtl->mime); - free(mtl->ext); - free(mtl); - } - -#if 0 - struct opt *opt; - /* Free strdup-ed temporary vars */ - for (opt = options; opt->sw != 0; opt++) - if (opt->tmp) { - free(opt->tmp); - opt->tmp = NULL; - } -#endif - - /* Free all connections */ - LL_FOREACH_SAFE(&ctx->connections, lp, tmp) { - c = LL_ENTRY(lp, struct conn, link); - disconnect(c); - } - - /* Free registered URIs (must be done after disconnect()) */ - LL_FOREACH_SAFE(&ctx->registered_uris, lp, tmp) { - ruri = LL_ENTRY(lp, struct registered_uri, link); - free((void *)ruri->uri); - free(ruri); - } - - /* Free listener sockets for this context */ - LL_FOREACH_SAFE(&listeners, lp, tmp) { - l = LL_ENTRY(lp, struct listener, link); - (void) closesocket(l->sock); - LL_DEL(&l->link); - free(l); - } - - if (ctx->access_log) (void) fclose(ctx->access_log); - if (ctx->error_log) (void) fclose(ctx->error_log); - if (ctx->put_auth_file) free(ctx->put_auth_file); - if (ctx->document_root) free(ctx->document_root); - if (ctx->index_files) free(ctx->index_files); - if (ctx->aliases) free(ctx->aliases); -#if !defined(NO_CGI) - if (ctx->cgi_vars) free(ctx->cgi_vars); - if (ctx->cgi_extensions) free(ctx->cgi_extensions); - if (ctx->cgi_interpreter) free(ctx->cgi_interpreter); -#endif /* NO_CGI */ - if (ctx->auth_realm) free(ctx->auth_realm); - if (ctx->global_passwd_file) free(ctx->global_passwd_file); - if (ctx->uid) free(ctx->uid); - - /* TODO: free SSL context */ - - free(ctx); -} diff --git a/cpukit/shttpd/shttpd.h b/cpukit/shttpd/shttpd.h deleted file mode 100644 index 8ac1dd8ff4..0000000000 --- a/cpukit/shttpd/shttpd.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * $Id$ - */ - -#ifndef SHTTPD_HEADER_INCLUDED -#define SHTTPD_HEADER_INCLUDED - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * This structure is passed to the user callback function - */ -struct shttpd_arg { - void *priv; /* Private! Do not touch! */ - void *state; /* User state */ - void *user_data; /* User-defined data */ - - struct { - char *buf; /* Buffer pointer */ - int len; /* Size of a buffer */ - int num_bytes; /* Bytes processed by callback */ - } in, out; /* POST data buffer (in) and output buffer (out) */ - - unsigned int flags; -#define SHTTPD_END_OF_OUTPUT 1 -#define SHTTPD_CONNECTION_ERROR 2 -#define SHTTPD_MORE_POST_DATA 4 -#define SHTTPD_POST_BUFFER_FULL 8 -}; - -/* - * User callback function. Called when certain registered URLs have been - * requested. These are the requirements to the callback function: - * - * 1. it must copy data into 'out_buf', not more than 'out_buf_max_len' bytes, - * and record how many bytes are copied, into 'out_buf_written_len' - * 2. it must not block the execution - * 3. it must set 'last' in shttpd_arg to 1 if there is no more data - * 4. for POST requests, it must process the incoming data (in_buf), and - * set 'in_buf_read_len', which is how many bytes of POST data is read - * and can be discarded by SHTTPD. - */ -typedef void (*shttpd_callback_t)(struct shttpd_arg *); - -/* - * shttpd_init Initialize shttpd context. Parameters: configuration - * file name (may be NULL), then NULL-terminated - * sequence of pairs "option_name", "option_value". - * shttpd_init2 Same as shttpd_init, but the list of option/value - * pairs is passed in arrays - * shttpd_fini Dealocate the context - * shttpd_register_uri Setup the callback function for specified URL. - * shttpd_protect_uri Associate authorization file with an URL. - * shttpd_add_mime_type Add mime type - * shtppd_listen Setup a listening socket in the SHTTPD context - * shttpd_poll Do connections processing - * shttpd_version return string with SHTTPD version - * shttpd_get_var Return POST/GET variable value for given variable name. - * shttpd_get_header return value of the specified HTTP header - * shttpd_get_env return string values for the following - * pseudo-variables: "REQUEST_METHOD", "REQUEST_URI", - * "REMOTE_USER" and "REMOTE_ADDR". - */ - -struct shttpd_ctx; - -struct shttpd_ctx *shttpd_init(const char *config_file, ...); -struct shttpd_ctx *shttpd_init2(const char *config_file, - char *names[], char *values[], size_t num_options); -void shttpd_fini(struct shttpd_ctx *); -void shttpd_add_mime_type(struct shttpd_ctx *, - const char *ext, const char *mime); -int shttpd_listen(struct shttpd_ctx *ctx, int port); -void shttpd_register_uri(struct shttpd_ctx *ctx, - const char *uri, shttpd_callback_t callback, void *user_data); -void shttpd_protect_uri(struct shttpd_ctx *ctx, - const char *uri, const char *file); -void shttpd_poll(struct shttpd_ctx *, int milliseconds); -const char *shttpd_version(void); -int shttpd_get_var(const char *var, const char *buf, int buf_len, - char *value, int value_len); -const char *shttpd_get_header(struct shttpd_arg *, const char *); -const char *shttpd_get_env(struct shttpd_arg *, const char *); -void shttpd_get_http_version(struct shttpd_arg *, - unsigned long *major, unsigned long *minor); -size_t shttpd_printf(struct shttpd_arg *, const char *fmt, ...); -void shttpd_handle_error(struct shttpd_ctx *ctx, int status, - shttpd_callback_t func, void *data); - -/* - * The following three functions are for applications that need to - * load-balance the connections on their own. Many threads may be spawned - * with one SHTTPD context per thread. Boss thread may only wait for - * new connections by means of shttpd_accept(). Then it may scan thread - * pool for the idle thread by means of shttpd_active(), and add new - * connection to the context by means of shttpd_add(). - */ -void shttpd_add_socket(struct shttpd_ctx *, int sock); -int shttpd_accept(int lsn_sock, int milliseconds); -int shttpd_active(struct shttpd_ctx *); - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* SHTTPD_HEADER_INCLUDED */ diff --git a/cpukit/shttpd/ssl.h b/cpukit/shttpd/ssl.h deleted file mode 100644 index 5aeae4a99b..0000000000 --- a/cpukit/shttpd/ssl.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> - * All rights reserved - * - * "THE BEER-WARE LICENSE" (Revision 42): - * Sergey Lyubka wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. - */ - -/* - * Snatched from OpenSSL includes. I put the prototypes here to be independent - * from the OpenSSL source installation. Having this, shttpd + SSL can be - * built on any system with binary SSL libraries installed. - */ - -typedef struct ssl_st SSL; -typedef struct ssl_method_st SSL_METHOD; -typedef struct ssl_ctx_st SSL_CTX; - -#define SSL_ERROR_WANT_READ 2 -#define SSL_ERROR_WANT_WRITE 3 -#define SSL_FILETYPE_PEM 1 - -/* - * Dynamically loaded SSL functionality - */ -struct ssl_func { - const char *name; /* SSL function name */ - union variant ptr; /* Function pointer */ -}; - -extern struct ssl_func ssl_sw[]; - -#define FUNC(x) ssl_sw[x].ptr.v_func - -#define SSL_free(x) (* (void (*)(SSL *)) FUNC(0))(x) -#define SSL_accept(x) (* (int (*)(SSL *)) FUNC(1))(x) -#define SSL_connect(x) (* (int (*)(SSL *)) FUNC(2))(x) -#define SSL_read(x,y,z) (* (int (*)(SSL *, void *, int)) FUNC(3))((x),(y),(z)) -#define SSL_write(x,y,z) \ - (* (int (*)(SSL *, const void *,int)) FUNC(4))((x), (y), (z)) -#define SSL_get_error(x,y)(* (int (*)(SSL *, int)) FUNC(5))((x), (y)) -#define SSL_set_fd(x,y) (* (int (*)(SSL *, int)) FUNC(6))((x), (y)) -#define SSL_new(x) (* (SSL * (*)(SSL_CTX *)) FUNC(7))(x) -#define SSL_CTX_new(x) (* (SSL_CTX * (*)(SSL_METHOD *)) FUNC(8))(x) -#define SSLv23_server_method() (* (SSL_METHOD * (*)(void)) FUNC(9))() -#define SSL_library_init() (* (int (*)(void)) FUNC(10))() -#define SSL_CTX_use_PrivateKey_file(x,y,z) (* (int (*)(SSL_CTX *, \ - const char *, int)) FUNC(11))((x), (y), (z)) -#define SSL_CTX_use_certificate_file(x,y,z) (* (int (*)(SSL_CTX *, \ - const char *, int)) FUNC(12))((x), (y), (z)) diff --git a/cpukit/shttpd/standalone.c b/cpukit/shttpd/standalone.c deleted file mode 100644 index 40e7ef82b8..0000000000 --- a/cpukit/shttpd/standalone.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> - * All rights reserved - * - * "THE BEER-WARE LICENSE" (Revision 42): - * Sergey Lyubka wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. - */ - -#include "defs.h" - -static const char *config_file = CONFIG; -static int exit_flag; - -static void -signal_handler(int sig_num) -{ - switch (sig_num) { -#ifndef _WIN32 - case SIGCHLD: - while (waitpid(-1, &sig_num, WNOHANG) > 0) ; - break; -#endif /* !_WIN32 */ - default: - exit_flag = sig_num; - break; - } -} - -int -main(int argc, char *argv[]) -{ - struct shttpd_ctx *ctx; - - current_time = time(NULL); - if (argc > 1 && argv[argc - 2][0] != '-' && argv[argc - 1][0] != '-') - config_file = argv[argc - 1]; - -#if !defined(NO_AUTH) - if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'A') { - if (argc != 6) - usage(argv[0]); - exit(edit_passwords(argv[2],argv[3],argv[4],argv[5])); - } -#endif /* NO_AUTH */ - - ctx = init_from_argc_argv(config_file, argc, argv); - - if (ctx->inetd_mode) - (void) freopen("/dev/null", "a", stderr); - - if (ctx->inetd_mode) - shttpd_add_socket(ctx, fileno(stdin)); - else if (shttpd_listen(ctx, ctx->port) == -1) - elog(E_FATAL, NULL, "Cannot open socket on port %d", ctx->port); - -#ifndef _WIN32 - /* Switch to alternate UID, it is safe now, after shttpd_listen() */ - if (ctx->uid != NULL) { - struct passwd *pw; - - if ((pw = getpwnam(ctx->uid)) == NULL) - elog(E_FATAL, 0, "main: unknown user [%s]", ctx->uid); - else if (setgid(pw->pw_gid) == -1) - elog(E_FATAL, NULL, "main: setgid(%s): %s", - ctx->uid, strerror(errno)); - else if (setuid(pw->pw_uid) == -1) - elog(E_FATAL, NULL, "main: setuid(%s): %s", - ctx->uid, strerror(errno)); - } - (void) signal(SIGCHLD, signal_handler); - (void) signal(SIGPIPE, SIG_IGN); -#endif /* _WIN32 */ - - (void) signal(SIGTERM, signal_handler); - (void) signal(SIGINT, signal_handler); - - elog(E_LOG, NULL, "shttpd %s started on port %d, serving %s", - VERSION, ctx->port, ctx->document_root); - - while (exit_flag == 0) - shttpd_poll(ctx, 5000); - - elog(E_LOG, NULL, "%d requests %.2lf Mb in %.2lf Mb out. " - "Exit on signal %d", ctx->nrequests, (double) (ctx->in / 1048576), - (double) ctx->out / 1048576, exit_flag); - - shttpd_fini(ctx); - - return (EXIT_SUCCESS); -} diff --git a/cpukit/shttpd/std_includes.h b/cpukit/shttpd/std_includes.h deleted file mode 100644 index f61503ce69..0000000000 --- a/cpukit/shttpd/std_includes.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> - * All rights reserved - * - * "THE BEER-WARE LICENSE" (Revision 42): - * Sergey Lyubka wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. - */ - -#ifndef STD_HEADERS_INCLUDED -#define STD_HEADERS_INCLUDED - -#ifndef _WIN32_WCE /* Some ANSI #includes are not available on Windows CE */ -#include <sys/types.h> -#include <sys/stat.h> -#include <time.h> -#include <errno.h> -#include <signal.h> -#include <fcntl.h> -#endif /* _WIN32_WCE */ - -#include <stdlib.h> -#include <stdarg.h> -#include <assert.h> -#include <string.h> -#include <ctype.h> -#include <limits.h> -#include <stddef.h> -#include <stdio.h> -#include <wchar.h> - -#if defined(_WIN32) /* Windows specific */ -#include "compat_win32.h" -#elif defined(__rtems__) /* RTEMS specific */ -#include "compat_rtems.h" -#else /* UNIX specific */ -#include "compat_unix.h" -#endif /* _WIN32 */ - -#endif /* STD_HEADERS_INCLUDED */ diff --git a/cpukit/shttpd/string.c b/cpukit/shttpd/string.c deleted file mode 100644 index d77f32c417..0000000000 --- a/cpukit/shttpd/string.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> - * All rights reserved - * - * "THE BEER-WARE LICENSE" (Revision 42): - * Sergey Lyubka wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. - */ - -#include "defs.h" - -#ifndef HAVE_STRLCPY -void -my_strlcpy(register char *dst, register const char *src, size_t n) -{ - for (; *src != '\0' && n > 1; n--) - *dst++ = *src++; - *dst = '\0'; -} -#endif - -#ifndef HAVE_STRNCASECMP -int -my_strncasecmp(const char *str1, const char *str2, size_t len) -{ - register const unsigned char *s1 = (unsigned char *) str1, - *s2 = (unsigned char *) str2, *e; - int ret; - - for (e = s1 + len - 1; s1 < e && *s1 != '\0' && *s2 != '\0' && - tolower(*s1) == tolower(*s2); s1++, s2++) ; - ret = tolower(*s1) - tolower(*s2); - - return (ret); -} -#endif - -#ifndef HAVE_STRNDUP -char * -my_strndup(const char *ptr, size_t len) -{ - char *p; - - if ((p = malloc(len + 1)) != NULL) - my_strlcpy(p, ptr, len + 1); - - return (p); - -} -#endif - -#ifndef HAVE_STRDUP -char * -my_strdup(const char *str) -{ - return (my_strndup(str, strlen(str))); -} -#endif - -/* - * Sane snprintf(). Acts like snprintf(), but never return -1 or the - * value bigger than supplied buffer. - * Thanks Adam Zeldis to pointing snprintf()-caused vulnerability - * in his audit report. - */ -int -my_snprintf(char *buf, size_t buflen, const char *fmt, ...) -{ - va_list ap; - int n; - - if (buflen == 0) - return (0); - - va_start(ap, fmt); - n = vsnprintf(buf, buflen, fmt, ap); - va_end(ap); - - if (n < 0 || (size_t) n >= buflen) - n = buflen - 1; - buf[n] = '\0'; - - return (n); -} |