Author: dmacvicar
Date: Thu Oct 16 19:23:14 2008
New Revision: 11382
URL: http://svn.opensuse.org/viewcvs/zypp?rev=11382&view=rev
Log:
add embeded http library so we can test remote scenarios
Added:
trunk/libzypp/vendor/
trunk/libzypp/vendor/CMakeLists.txt
trunk/libzypp/vendor/shttpd/
trunk/libzypp/vendor/shttpd/CMakeLists.txt
trunk/libzypp/vendor/shttpd/auth.c
trunk/libzypp/vendor/shttpd/cgi.c
trunk/libzypp/vendor/shttpd/compat_rtems.c
trunk/libzypp/vendor/shttpd/compat_rtems.h
trunk/libzypp/vendor/shttpd/compat_unix.c
trunk/libzypp/vendor/shttpd/compat_unix.h
trunk/libzypp/vendor/shttpd/compat_win32.c
trunk/libzypp/vendor/shttpd/compat_win32.h
trunk/libzypp/vendor/shttpd/compat_wince.c
trunk/libzypp/vendor/shttpd/compat_wince.h
trunk/libzypp/vendor/shttpd/config.h
trunk/libzypp/vendor/shttpd/defs.h
trunk/libzypp/vendor/shttpd/io.h
trunk/libzypp/vendor/shttpd/io_cgi.c
trunk/libzypp/vendor/shttpd/io_dir.c
trunk/libzypp/vendor/shttpd/io_emb.c
trunk/libzypp/vendor/shttpd/io_file.c
trunk/libzypp/vendor/shttpd/io_socket.c
trunk/libzypp/vendor/shttpd/io_ssi.c
trunk/libzypp/vendor/shttpd/io_ssl.c
trunk/libzypp/vendor/shttpd/llist.h
trunk/libzypp/vendor/shttpd/log.c
trunk/libzypp/vendor/shttpd/md5.c
trunk/libzypp/vendor/shttpd/md5.h
trunk/libzypp/vendor/shttpd/shttpd.c
trunk/libzypp/vendor/shttpd/shttpd.h
trunk/libzypp/vendor/shttpd/ssl.h
trunk/libzypp/vendor/shttpd/standalone.c
trunk/libzypp/vendor/shttpd/std_includes.h
trunk/libzypp/vendor/shttpd/string.c
Modified:
trunk/libzypp/CMakeLists.txt
Modified: trunk/libzypp/CMakeLists.txt
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/CMakeLists.txt?rev=11382&r1=11381&r2=11382&view=diff
==============================================================================
--- trunk/libzypp/CMakeLists.txt (original)
+++ trunk/libzypp/CMakeLists.txt Thu Oct 16 19:23:14 2008
@@ -38,7 +38,7 @@
FOREACH( loop_var ${ARGV} )
SET_SOURCE_FILES_PROPERTIES( ${loop_var}_test.cc COMPILE_FLAGS "-DBOOST_TEST_DYN_LINK -DBOOST_TEST_MAIN -DBOOST_AUTO_TEST_MAIN=\"\" " )
ADD_EXECUTABLE( ${loop_var}_test ${loop_var}_test.cc )
- TARGET_LINK_LIBRARIES( ${loop_var}_test zypp boost_unit_test_framework)
+ TARGET_LINK_LIBRARIES( ${loop_var}_test zypp boost_unit_test_framework zypp_test_utils)
ADD_TEST( ${loop_var}_test ${CMAKE_CURRENT_BINARY_DIR}/${loop_var}_test)
ENDFOREACH( loop_var )
ENDMACRO(ADD_TESTS)
@@ -161,6 +161,7 @@
#ADD_SUBDIRECTORY( examples )
ADD_SUBDIRECTORY( po EXCLUDE_FROM_ALL )
ADD_SUBDIRECTORY( doc )
+ADD_SUBDIRECTORY( vendor )
ADD_SUBDIRECTORY( tests EXCLUDE_FROM_ALL )
INCLUDE(CTest)
Added: trunk/libzypp/vendor/CMakeLists.txt
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/CMakeLists.txt?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/CMakeLists.txt (added)
+++ trunk/libzypp/vendor/CMakeLists.txt Thu Oct 16 19:23:14 2008
@@ -0,0 +1,2 @@
+ADD_SUBDIRECTORY(shttpd)
+
Added: trunk/libzypp/vendor/shttpd/CMakeLists.txt
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/CMakeLists.txt?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/CMakeLists.txt (added)
+++ trunk/libzypp/vendor/shttpd/CMakeLists.txt Thu Oct 16 19:23:14 2008
@@ -0,0 +1,29 @@
+SET(shttp_SOURCES
+ auth.c
+ cgi.c
+ compat_unix.c
+ config.h
+ defs.h
+ io_cgi.c
+ io_dir.c
+ io_emb.c
+ io_file.c
+ io.h
+ io_socket.c
+ io_ssi.c
+ io_ssl.c
+ llist.h
+ log.c
+ md5.c
+ md5.h
+ shttpd.c
+ shttpd.h
+ ssl.h
+ standalone.c
+ std_includes.h
+ string.c
+)
+
+ADD_LIBRARY(shttp ${shttp_SOURCES})
+TARGET_LINK_LIBRARIES(shttp dl pthread)
+
Added: trunk/libzypp/vendor/shttpd/auth.c
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/auth.c?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/auth.c (added)
+++ trunk/libzypp/vendor/shttpd/auth.c Thu Oct 16 19:23:14 2008
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka
+ * 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_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, &_shttpd_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);
+ DBG(("%s: uri [%.*s] expected_resp [%.*s] resp [%.*s]",
+ "check_password", digest->uri.len, digest->uri.ptr,
+ 32, resp, digest->resp.len, digest->resp.ptr));
+
+ 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->options[OPT_AUTH_GPASSWD] != NULL) {
+ /* Use global passwords file */
+ _shttpd_snprintf(name, sizeof(name), "%s",
+ ctx->options[OPT_AUTH_GPASSWD]);
+ } else {
+ /*
+ * Try to find .htpasswd in requested directory.
+ * Given the path, create the path to .htpasswd file
+ * in the same directory. Find the right-most
+ * directory separator character first. That would be the
+ * directory name. If directory separator character is not
+ * found, 'e' will point to 'p'.
+ */
+ for (p = path, e = p + strlen(p) - 1; e > p; e--)
+ if (IS_DIRSEP_CHAR(*e))
+ break;
+
+ /*
+ * Make up the path by concatenating directory name and
+ * .htpasswd file name.
+ */
+ (void) _shttpd_snprintf(name, sizeof(name), "%.*s/%s",
+ (int) (e - p), p, HTPASSWD);
+ }
+
+ if ((fd = _shttpd_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 &&
+ !_shttpd_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->options[OPT_AUTH_REALM],
+ domain.ptr, domain.len)) {
+ ok = check_password(c->method, &ha1, &digest);
+ break;
+ }
+ }
+ }
+
+ return (ok);
+}
+
+int
+_shttpd_check_authorization(struct conn *c, const char *path)
+{
+ FILE *fp = NULL;
+ int len, n, authorized = 1;
+ const char *p, *s = c->ctx->options[OPT_PROTECT];
+ char protected_path[FILENAME_MAX];
+
+ FOR_EACH_WORD_IN_LIST(s, len) {
+
+ if ((p = memchr(s, '=', len)) == NULL || p >= s + len || p == s)
+ continue;
+
+ if (!memcmp(c->uri, s, p - s)) {
+
+ n = s + len - p;
+ if (n > (int) sizeof(protected_path) - 1)
+ n = sizeof(protected_path) - 1;
+
+ _shttpd_strlcpy(protected_path, p + 1, n);
+
+ if ((fp = fopen(protected_path, "r")) == NULL)
+ _shttpd_elog(E_LOG, c,
+ "check_auth: cannot open %s: %s",
+ protected_path, strerror(errno));
+ break;
+ }
+ }
+
+ if (fp == NULL)
+ fp = open_auth_file(c->ctx, path);
+
+ if (fp != NULL) {
+ authorized = authorize(c, fp);
+ (void) fclose(fp);
+ }
+
+ return (authorized);
+}
+
+int
+_shttpd_is_authorized_for_put(struct conn *c)
+{
+ FILE *fp;
+ int ret = 0;
+
+ if ((fp = fopen(c->ctx->options[OPT_AUTH_PUT], "r")) != NULL) {
+ ret = authorize(c, fp);
+ (void) fclose(fp);
+ }
+
+ return (ret);
+}
+
+void
+_shttpd_send_authorization_request(struct conn *c)
+{
+ char buf[512];
+
+ (void) _shttpd_snprintf(buf, sizeof(buf), "Unauthorized\r\n"
+ "WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", "
+ "nonce=\"%lu\"", c->ctx->options[OPT_AUTH_REALM],
+ (unsigned long) _shttpd_current_time);
+
+ _shttpd_send_server_error(c, 401, buf);
+}
+
+/*
+ * Edit the passwords file.
+ */
+int
+_shttpd_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) _shttpd_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)
+ _shttpd_elog(E_FATAL, NULL,
+ "Cannot open %s: %s", fname, strerror(errno));
+ else if ((fp2 = fopen(tmp, "w+")) == NULL)
+ _shttpd_elog(E_FATAL, NULL,
+ "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) _shttpd_remove(fname);
+ (void) _shttpd_rename(tmp, fname);
+
+ return (ret);
+}
+#endif /* NO_AUTH */
Added: trunk/libzypp/vendor/shttpd/cgi.c
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/cgi.c?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/cgi.c (added)
+++ trunk/libzypp/vendor/shttpd/cgi.c Thu Oct 16 19:23:14 2008
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka
+ * 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 */
+};
+
+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, *fname, *root = c->ctx->options[OPT_ROOT];
+ size_t len;
+
+ blk->len = blk->nvars = 0;
+
+ /* SCRIPT_FILENAME */
+ fname = prog;
+ if ((s = strrchr(prog, '/')))
+ fname = s + 1;
+
+ /* 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->loc_port);
+ addenv(blk, "SERVER_NAME=%s", c->ctx->options[OPT_AUTH_REALM]);
+ addenv(blk, "SERVER_ROOT=%s", root);
+ addenv(blk, "DOCUMENT_ROOT=%s", root);
+ addenv(blk, "REQUEST_METHOD=%s",
+ _shttpd_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(root));
+ addenv(blk, "SCRIPT_FILENAME=%s", fname); /* 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->options[OPT_CGI_ENVIRONMENT];
+ 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
+_shttpd_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);
+ pair[0] = pair[1] = -1;
+
+ /* CGI must be executed in its own directory */
+ (void) _shttpd_snprintf(dir, sizeof(dir), "%s", prog);
+ for (p = dir + strlen(dir) - 1; p > dir; p--)
+ if (*p == '/') {
+ *p++ = '\0';
+ break;
+ }
+
+ if (shttpd_socketpair(pair) != 0) {
+ ret = -1;
+ } else if (_shttpd_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
+_shttpd_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 = &_shttpd_io_cgi;
+ c->loc.flags = FLAG_R;
+ if (c->method == METHOD_POST)
+ c->loc.flags |= FLAG_W;
+}
+
+#endif /* !NO_CGI */
Added: trunk/libzypp/vendor/shttpd/compat_rtems.c
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/compat_rtems.c?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/compat_rtems.c (added)
+++ trunk/libzypp/vendor/shttpd/compat_rtems.c Thu Oct 16 19:23:14 2008
@@ -0,0 +1,198 @@
+/**********************************************************************
+ *
+ * rtems shttpd management
+ *
+ * FILE NAME : rtems_shttpd.c
+ *
+ * AUTHOR : Steven Johnson
+ *
+ * DESCRIPTION : Defines the interface functions to the shttp daemon
+ *
+ * REVISION : $Id: compat_rtems.c,v 1.2 2006/11/12 03:29:17 infidel Exp $
+ *
+ * COMMENTS :
+ *
+ **********************************************************************/
+
+ /**********************************************************************
+ * INCLUDED MODULES
+ **********************************************************************/
+#include
+#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;
+ 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, 9000);
+
+ 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,
+ rtems_unsigned32 stack_size,
+ rtems_mode initial_modes,
+ rtems_attribute attribute_set,
+ rtems_shttpd_init init_callback,
+ rtems_shttpd_addpages addpages_callback,
+ char *webroot
+ )
+{
+ 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;
+ 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);
+}
+
+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);
+}
+
+#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
Added: trunk/libzypp/vendor/shttpd/compat_rtems.h
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/compat_rtems.h?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/compat_rtems.h (added)
+++ trunk/libzypp/vendor/shttpd/compat_rtems.h Thu Oct 16 19:23:14 2008
@@ -0,0 +1,60 @@
+/**
+ * @file rtems/rtems-shttpd.h
+ */
+
+#ifndef _rtems_rtems_webserver_h
+#define _rtems_rtems_webserver_h
+
+#include "shttpd.h"
+
+#include
+#include
+#include
+#include
+
+/* 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 O_BINARY 0
+#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,
+ rtems_unsigned32 stack_size,
+ rtems_mode initial_modes,
+ rtems_attribute attribute_set,
+ rtems_shttpd_init init_callback,
+ rtems_shttpd_addpages addpages_callback,
+ char *webroot
+ );
+void rtems_terminate_webserver(void);
+int rtems_webserver_ok(void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Added: trunk/libzypp/vendor/shttpd/compat_unix.c
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/compat_unix.c?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/compat_unix.c (added)
+++ trunk/libzypp/vendor/shttpd/compat_unix.c Thu Oct 16 19:23:14 2008
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka
+ * 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
+_shttpd_set_close_on_exec(int fd)
+{
+ (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
+}
+
+int
+_shttpd_stat(const char *path, struct stat *stp)
+{
+ return (stat(path, stp));
+}
+
+int
+_shttpd_open(const char *path, int flags, int mode)
+{
+ return (open(path, flags, mode));
+}
+
+int
+_shttpd_remove(const char *path)
+{
+ return (remove(path));
+}
+
+int
+_shttpd_rename(const char *path1, const char *path2)
+{
+ return (rename(path1, path2));
+}
+
+int
+_shttpd_mkdir(const char *path, int mode)
+{
+ return (mkdir(path, mode));
+}
+
+char *
+_shttpd_getcwd(char *buffer, int maxlen)
+{
+ return (getcwd(buffer, maxlen));
+}
+
+int
+_shttpd_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
+_shttpd_spawn_process(struct conn *c, const char *prog, char *envblk,
+ char *envp[], int sock, const char *dir)
+{
+ int ret;
+ pid_t pid;
+ const char *p, *interp = c->ctx->options[OPT_CGI_INTERPRETER];
+
+ envblk = NULL; /* unused */
+
+ if ((pid = vfork()) == -1) {
+
+ ret = -1;
+ _shttpd_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);
+
+ if ((p = strrchr(prog, '/')) != NULL)
+ p++;
+ else
+ p = prog;
+
+ /* Execute CGI program */
+ if (interp == NULL) {
+ (void) execle(p, p, NULL, envp);
+ _shttpd_elog(E_FATAL, c, "redirect: exec(%s)", prog);
+ } else {
+ (void) execle(interp, interp, p, NULL, envp);
+ _shttpd_elog(E_FATAL, c, "redirect: exec(%s %s)",
+ interp, prog);
+ }
+
+ /* UNREACHED */
+ exit(EXIT_FAILURE);
+
+ } else {
+
+ /* Parent */
+ ret = 0;
+ (void) closesocket(sock);
+ }
+
+ return (ret);
+}
+#endif /* !NO_CGI */
Added: trunk/libzypp/vendor/shttpd/compat_unix.h
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/compat_unix.h?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/compat_unix.h (added)
+++ trunk/libzypp/vendor/shttpd/compat_unix.h Thu Oct 16 19:23:14 2008
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2004-2007 Sergey Lyubka
+ * 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
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#if !defined(NO_THREADS)
+#include "pthread.h"
+#define _beginthread(a, b, c) do { pthread_t tid; \
+ pthread_create(&tid, NULL, (void *(*)(void *))a, c); } while (0)
+#endif /* !NO_THREADS */
+
+#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
Added: trunk/libzypp/vendor/shttpd/compat_win32.c
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/compat_win32.c?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/compat_win32.c (added)
+++ trunk/libzypp/vendor/shttpd/compat_win32.c Thu Oct 16 19:23:14 2008
@@ -0,0 +1,687 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka
+ * 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 SERVICE_STATUS ss;
+static SERVICE_STATUS_HANDLE hStatus;
+static SERVICE_DESCRIPTION service_descr = {"Web server"};
+
+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);
+ }
+}
+
+static int
+protect_against_code_disclosure(const wchar_t *path)
+{
+ WIN32_FIND_DATAW data;
+ HANDLE handle;
+ const wchar_t *p;
+
+ /*
+ * Protect against CGI code disclosure under Windows.
+ * This is very nasty hole. Windows happily opens files with
+ * some garbage in the end of file name. So fopen("a.cgi ", "r")
+ * actually opens "a.cgi", and does not return an error! And since
+ * "a.cgi " does not have valid CGI extension, this leads to
+ * the CGI code disclosure.
+ * To protect, here we delete all fishy characters from the
+ * end of file name.
+ */
+
+ if ((handle = FindFirstFileW(path, &data)) == INVALID_HANDLE_VALUE)
+ return (FALSE);
+
+ FindClose(handle);
+
+ for (p = path + wcslen(path); p > path && p[-1] != L'\\';)
+ p--;
+
+ if (!(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
+ wcscmp(data.cFileName, p) != 0)
+ return (FALSE);
+
+ return (TRUE);
+}
+
+int
+_shttpd_open(const char *path, int flags, int mode)
+{
+ char buf[FILENAME_MAX];
+ wchar_t wbuf[FILENAME_MAX];
+
+ _shttpd_strlcpy(buf, path, sizeof(buf));
+ fix_directory_separators(buf);
+ MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf));
+
+ if (protect_against_code_disclosure(wbuf) == FALSE)
+ return (-1);
+
+ return (_wopen(wbuf, flags));
+}
+
+int
+_shttpd_stat(const char *path, struct stat *stp)
+{
+ char buf[FILENAME_MAX], *p;
+ wchar_t wbuf[FILENAME_MAX];
+
+ _shttpd_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
+_shttpd_remove(const char *path)
+{
+ char buf[FILENAME_MAX];
+ wchar_t wbuf[FILENAME_MAX];
+
+ _shttpd_strlcpy(buf, path, sizeof(buf));
+ fix_directory_separators(buf);
+
+ MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf));
+
+ return (_wremove(wbuf));
+}
+
+int
+_shttpd_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];
+
+ _shttpd_strlcpy(buf1, path1, sizeof(buf1));
+ _shttpd_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
+_shttpd_mkdir(const char *path, int mode)
+{
+ char buf[FILENAME_MAX];
+ wchar_t wbuf[FILENAME_MAX];
+
+ _shttpd_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 *
+_shttpd_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 {
+ _shttpd_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
+_shttpd_set_non_blocking_mode(int fd)
+{
+ unsigned long on = 1;
+
+ return (ioctlsocket(fd, FIONBIO, &on));
+}
+
+void
+_shttpd_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;
+};
+
+
+enum ready_mode_t {IS_READY_FOR_READ, IS_READY_FOR_WRITE};
+
+/*
+ * Wait until given socket is in ready state. Always return TRUE.
+ */
+static int
+is_socket_ready(int sock, enum ready_mode_t mode)
+{
+ fd_set read_set, write_set;
+
+ FD_ZERO(&read_set);
+ FD_ZERO(&write_set);
+
+ if (mode == IS_READY_FOR_READ)
+ FD_SET(sock, &read_set);
+ else
+ FD_SET(sock, &write_set);
+
+ select(sock + 1, &read_set, &write_set, NULL, NULL);
+
+ return (TRUE);
+}
+
+/*
+ * 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 &&
+ is_socket_ready(tp->s, IS_READY_FOR_READ) &&
+ (n = recv(tp->s, buf, max_recv, 0)) > 0) {
+ if (n == -1 && ERRNO == EWOULDBLOCK)
+ continue;
+ 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 (is_socket_ready(tp->s, IS_READY_FOR_WRITE) &&
+ (k = send(tp->s, buf + sent, n - sent, 0)) <= 0) {
+ if (k == -1 && ERRNO == EWOULDBLOCK) {
+ k = 0;
+ continue;
+ }
+ 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
+_shttpd_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, *interp, 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 = h[1];
+ si.hStdInput = h[0];
+
+ /* If CGI file is a script, try to read the interpreter line */
+ interp = c->ctx->options[OPT_CGI_INTERPRETER];
+ if (interp == 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);
+ }
+ interp = line + 2;
+ (void) _shttpd_snprintf(cmdline, sizeof(cmdline), "%s%s%s",
+ line + 2, line[2] == '\0' ? "" : " ", prog);
+ }
+
+ if ((p = strrchr(prog, '/')) != NULL)
+ prog = p + 1;
+
+ (void) _shttpd_snprintf(cmdline, sizeof(cmdline), "%s %s", interp, prog);
+
+ (void) _shttpd_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) {
+ _shttpd_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 */
+
+#define ID_TRAYICON 100
+#define ID_QUIT 101
+static NOTIFYICONDATA ni;
+
+static LRESULT CALLBACK
+WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ POINT pt;
+ HMENU hMenu;
+
+ switch (msg) {
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case ID_QUIT:
+ exit(EXIT_SUCCESS);
+ break;
+ }
+ break;
+ case WM_USER:
+ switch (lParam) {
+ case WM_RBUTTONUP:
+ case WM_LBUTTONUP:
+ case WM_LBUTTONDBLCLK:
+ hMenu = CreatePopupMenu();
+ 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));
+}
+
+static void
+systray(void *arg)
+{
+ WNDCLASS cls;
+ HWND hWnd;
+ MSG msg;
+
+ (void) memset(&cls, 0, sizeof(cls));
+
+ cls.lpfnWndProc = (WNDPROC) WindowProc;
+ cls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ cls.lpszClassName = "shttpd v." VERSION;
+
+ if (!RegisterClass(&cls))
+ _shttpd_elog(E_FATAL, NULL, "RegisterClass: %d", ERRNO);
+ else if ((hWnd = CreateWindow(cls.lpszClassName, "",
+ WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL, NULL, arg)) == NULL)
+ _shttpd_elog(E_FATAL, NULL, "CreateWindow: %d", ERRNO);
+ ShowWindow(hWnd, SW_HIDE);
+
+ ni.cbSize = sizeof(ni);
+ ni.uID = ID_TRAYICON;
+ ni.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
+ ni.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ ni.hWnd = hWnd;
+ _shttpd_snprintf(ni.szTip, sizeof(ni.szTip), "SHTTPD web server");
+ ni.uCallbackMessage = WM_USER;
+ Shell_NotifyIcon(NIM_ADD, &ni);
+
+ while (GetMessage(&msg, hWnd, 0, 0)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+}
+
+int
+_shttpd_set_systray(struct shttpd_ctx *ctx, const char *opt)
+{
+ HWND hWnd;
+ char title[512];
+ static WNDPROC oldproc;
+
+ if (!_shttpd_is_true(opt))
+ return (TRUE);
+
+ FreeConsole();
+ GetConsoleTitle(title, sizeof(title));
+ hWnd = FindWindow(NULL, title);
+ ShowWindow(hWnd, SW_HIDE);
+ _beginthread(systray, 0, hWnd);
+
+ return (TRUE);
+}
+
+int
+_shttpd_set_nt_service(struct shttpd_ctx *ctx, const char *action)
+{
+ SC_HANDLE hSCM, hService;
+ char path[FILENAME_MAX], key[128];
+ HKEY hKey;
+ DWORD dwData;
+
+
+ if (!strcmp(action, "install")) {
+ if ((hSCM = OpenSCManager(NULL, NULL,
+ SC_MANAGER_ALL_ACCESS)) == NULL)
+ _shttpd_elog(E_FATAL, NULL, "Error opening SCM (%d)", ERRNO);
+
+ GetModuleFileName(NULL, path, sizeof(path));
+
+ hService = CreateService(hSCM, SERVICE_NAME, SERVICE_NAME,
+ SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
+ SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, path,
+ NULL, NULL, NULL, NULL, NULL);
+
+ if (!hService)
+ _shttpd_elog(E_FATAL, NULL,
+ "Error installing service (%d)", ERRNO);
+
+ ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION,
+ &service_descr);
+ _shttpd_elog(E_FATAL, NULL, "Service successfully installed");
+
+
+ } else if (!strcmp(action, "uninstall")) {
+
+ if ((hSCM = OpenSCManager(NULL, NULL,
+ SC_MANAGER_ALL_ACCESS)) == NULL) {
+ _shttpd_elog(E_FATAL, NULL, "Error opening SCM (%d)", ERRNO);
+ } else if ((hService = OpenService(hSCM,
+ SERVICE_NAME, DELETE)) == NULL) {
+ _shttpd_elog(E_FATAL, NULL,
+ "Error opening service (%d)", ERRNO);
+ } else if (!DeleteService(hService)) {
+ _shttpd_elog(E_FATAL, NULL,
+ "Error deleting service (%d)", ERRNO);
+ } else {
+ _shttpd_elog(E_FATAL, NULL, "Service deleted");
+ }
+
+ } else {
+ _shttpd_elog(E_FATAL, NULL, "Use -service ");
+ }
+
+ /* NOTREACHED */
+ return (TRUE);
+}
+
+static void WINAPI
+ControlHandler(DWORD code)
+{
+ if (code == SERVICE_CONTROL_STOP || code == SERVICE_CONTROL_SHUTDOWN) {
+ ss.dwWin32ExitCode = 0;
+ ss.dwCurrentState = SERVICE_STOPPED;
+ }
+
+ SetServiceStatus(hStatus, &ss);
+}
+
+static void WINAPI
+ServiceMain(int argc, char *argv[])
+{
+ char path[MAX_PATH], *p, *av[] = {"shttpd_service", path, NULL};
+ struct shttpd_ctx *ctx;
+
+ ss.dwServiceType = SERVICE_WIN32;
+ ss.dwCurrentState = SERVICE_RUNNING;
+ ss.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
+
+ hStatus = RegisterServiceCtrlHandler(SERVICE_NAME, ControlHandler);
+ SetServiceStatus(hStatus, &ss);
+
+ GetModuleFileName(NULL, path, sizeof(path));
+
+ if ((p = strrchr(path, DIRSEP)) != NULL)
+ *++p = '\0';
+
+ strcat(path, CONFIG_FILE); /* woo ! */
+
+ ctx = shttpd_init(NELEMS(av) - 1, av);
+ if ((ctx = shttpd_init(NELEMS(av) - 1, av)) == NULL)
+ _shttpd_elog(E_FATAL, NULL, "Cannot initialize SHTTP context");
+
+ while (ss.dwCurrentState == SERVICE_RUNNING)
+ shttpd_poll(ctx, INT_MAX);
+ shttpd_fini(ctx);
+
+ ss.dwCurrentState = SERVICE_STOPPED;
+ ss.dwWin32ExitCode = -1;
+ SetServiceStatus(hStatus, &ss);
+}
+
+void
+try_to_run_as_nt_service(void)
+{
+ static SERVICE_TABLE_ENTRY service_table[] = {
+ {SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain},
+ {NULL, NULL}
+ };
+
+ if (StartServiceCtrlDispatcher(service_table))
+ exit(EXIT_SUCCESS);
+}
Added: trunk/libzypp/vendor/shttpd/compat_win32.h
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/compat_win32.h?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/compat_win32.h (added)
+++ trunk/libzypp/vendor/shttpd/compat_win32.h Thu Oct 16 19:23:14 2008
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2004-2007 Sergey Lyubka
+ * 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
+#include
+#include
+#include
+#include
+#include
+
+#ifndef _WIN32_WCE
+
+#include
+#include
+#include
+
+#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"ssleay32.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 popen(x,y) _popen(x, y)
+#define pclose(x) _pclose(x)
+#define dlopen(x,y) LoadLibraryW(x)
+#define dlsym(x,y) (void *) GetProcAddress(x,y)
+#define _POSIX_
+
+#ifdef __LCC__
+#include
+#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);
Added: trunk/libzypp/vendor/shttpd/compat_wince.c
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/compat_wince.c?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/compat_wince.c (added)
+++ trunk/libzypp/vendor/shttpd/compat_wince.c Thu Oct 16 19:23:14 2008
@@ -0,0 +1,1593 @@
+/*
+ vi:ts=8:sw=8:noet
+ * Copyright (c) 2006 Luke Dunstan
+ * 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
+#include
+
+#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
+ size_t strftime(char *<[s]>, size_t <[maxsize]>,
+ const char *<[format]>, const struct tm *<[timp]>);
+
+TRAD_SYNOPSIS
+ #include
+ 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;
+}
Added: trunk/libzypp/vendor/shttpd/compat_wince.h
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/compat_wince.h?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/compat_wince.h (added)
+++ trunk/libzypp/vendor/shttpd/compat_wince.h Thu Oct 16 19:23:14 2008
@@ -0,0 +1,145 @@
+
+#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 */
Added: trunk/libzypp/vendor/shttpd/config.h
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/config.h?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/config.h (added)
+++ trunk/libzypp/vendor/shttpd/config.h Thu Oct 16 19:23:14 2008
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka
+ * 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 CONFIG_HEADER_DEFINED
+#define CONFIG_HEADER_DEFINED
+
+#undef VERSION
+#define VERSION "1.42" /* Version */
+#define CONFIG_FILE "shttpd.conf" /* Configuration file */
+#define HTPASSWD ".htpasswd" /* Passwords file name */
+#define URI_MAX 16384 /* Default max request size */
+#define LISTENING_PORTS "80" /* Default listening ports */
+#define INDEX_FILES "index.html,index.htm,index.php,index.cgi"
+#define CGI_EXT "cgi,pl,php" /* Default CGI extensions */
+#define SSI_EXT "shtml,shtm" /* Default SSI 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 */
+#define SERVICE_NAME "SHTTPD " VERSION /* NT service name */
+
+#endif /* CONFIG_HEADER_DEFINED */
Added: trunk/libzypp/vendor/shttpd/defs.h
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/defs.h?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/defs.h (added)
+++ trunk/libzypp/vendor/shttpd/defs.h Thu Oct 16 19:23:14 2008
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka
+ * 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 "md5.h"
+#include "config.h"
+#include "shttpd.h"
+
+#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 */
+
+/*
+ * 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;
+};
+
+#if !defined(FALSE)
+enum {FALSE, TRUE};
+#endif /* !FALSE */
+
+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 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 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 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 */
+#define FLAG_SUSPEND 128
+};
+
+struct worker {
+ struct llhead link;
+ int num_conns; /* Num of active connections */
+ int exit_flag; /* Ditto - exit flag */
+ int ctl[2]; /* Control socket pair */
+ struct shttpd_ctx *ctx; /* Context reference */
+ struct llhead connections; /* List of connections */
+};
+
+struct conn {
+ struct llhead link; /* Connections chain */
+ struct worker *worker; /* Worker this conn belongs to */
+ 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 loc_port; /* Local port */
+ 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 */
+ struct vec mime_type; /* Mime type */
+
+ struct headers ch; /* Parsed client headers */
+
+ struct stream loc; /* Local stream */
+ struct stream rem; /* Remote stream */
+
+#if !defined(NO_SSI)
+ void *ssi; /* SSI descriptor */
+#endif /* NO_SSI */
+};
+
+enum {
+ OPT_ROOT, OPT_INDEX_FILES, OPT_PORTS, OPT_DIR_LIST,
+ OPT_CGI_EXTENSIONS, OPT_CGI_INTERPRETER, OPT_CGI_ENVIRONMENT,
+ OPT_SSI_EXTENSIONS, OPT_AUTH_REALM, OPT_AUTH_GPASSWD,
+ OPT_AUTH_PUT, OPT_ACCESS_LOG, OPT_ERROR_LOG, OPT_MIME_TYPES,
+ OPT_SSL_CERTIFICATE, OPT_ALIASES, OPT_ACL, OPT_INETD, OPT_UID,
+ OPT_CFG_URI, OPT_PROTECT, OPT_SERVICE, OPT_HIDE, OPT_THREADS,
+ NUM_OPTIONS
+};
+
+/*
+ * SHTTPD context
+ */
+struct shttpd_ctx {
+ SSL_CTX *ssl_ctx; /* SSL context */
+
+ struct llhead registered_uris;/* User urls */
+ struct llhead error_handlers; /* Embedded error handlers */
+ struct llhead acl; /* Access control list */
+ struct llhead ssi_funcs; /* SSI callback functions */
+ struct llhead listeners; /* Listening sockets */
+ struct llhead workers; /* Worker workers */
+
+ FILE *access_log; /* Access log stream */
+ FILE *error_log; /* Error log stream */
+
+ char *options[NUM_OPTIONS]; /* Configurable options */
+#if defined(__rtems__)
+ rtems_id mutex;
+#endif /* _WIN32 */
+};
+
+struct listener {
+ struct llhead link;
+ struct shttpd_ctx *ctx; /* Context that socket belongs */
+ int sock; /* Listening socket */
+ int is_ssl; /* Should be SSL-ed */
+};
+
+/* Types of messages that could be sent over the control socket */
+enum {CTL_PASS_SOCKET, CTL_WAKEUP};
+
+/*
+ * 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).
+ *
+ * In every iteration of the loop, "s" points to the current value, and
+ * "len" specifies its length. The code inside loop must not change
+ * "s" and "len" parameters.
+ */
+#define FOR_EACH_WORD_IN_LIST(s,len) \
+ for (; s != NULL && (len = strcspn(s, DELIM_CHARS)) != 0; \
+ s += len, s+= strspn(s, DELIM_CHARS))
+
+/*
+ * IPv4 ACL entry. Specifies subnet with deny/allow flag
+ */
+struct acl {
+ struct llhead link;
+ uint32_t ip; /* IP, in network byte order */
+ uint32_t mask; /* Also in network byte order */
+ int flag; /* Either '+' or '-' */
+};
+
+/*
+ * shttpd.c
+ */
+extern time_t _shttpd_current_time; /* Current UTC time */
+extern int _shttpd_tz_offset; /* Offset from GMT time zone */
+extern const struct vec _shttpd_known_http_methods[];
+
+extern void _shttpd_stop_stream(struct stream *stream);
+extern int _shttpd_url_decode(const char *, int, char *dst, int);
+extern void _shttpd_send_server_error(struct conn *, int, const char *);
+extern int _shttpd_get_headers_len(const char *buf, size_t buflen);
+extern void _shttpd_parse_headers(const char *s, int, struct headers *);
+extern int _shttpd_is_true(const char *str);
+extern int _shttpd_socketpair(int pair[2]);
+extern void _shttpd_get_mime_type(struct shttpd_ctx *,
+ const char *, int, struct vec *);
+
+#define IS_TRUE(ctx, opt) _shttpd_is_true((ctx)->options[opt])
+
+/*
+ * config.c
+ */
+extern void _shttpd_usage(const char *prog);
+
+/*
+ * log.c
+ */
+extern void _shttpd_elog(int flags, struct conn *c, const char *fmt, ...);
+extern void _shttpd_log_access(FILE *fp, const struct conn *c);
+
+/*
+ * string.c
+ */
+extern void _shttpd_strlcpy(register char *, register const char *, size_t);
+extern int _shttpd_strncasecmp(register const char *,
+ register const char *, size_t);
+extern char *_shttpd_strndup(const char *ptr, size_t len);
+extern char *_shttpd_strdup(const char *str);
+extern int _shttpd_snprintf(char *buf, size_t len, const char *fmt, ...);
+extern int _shttpd_match_extension(const char *path, const char *ext_list);
+
+/*
+ * compat_*.c
+ */
+extern void _shttpd_set_close_on_exec(int fd);
+extern int _shttpd_set_non_blocking_mode(int fd);
+extern int _shttpd_stat(const char *, struct stat *stp);
+extern int _shttpd_open(const char *, int flags, int mode);
+extern int _shttpd_remove(const char *);
+extern int _shttpd_rename(const char *, const char *);
+extern int _shttpd_mkdir(const char *, int);
+extern char * _shttpd_getcwd(char *, int);
+extern int _shttpd_spawn_process(struct conn *c, const char *prog,
+ char *envblk, char *envp[], int sock, const char *dir);
+
+extern int _shttpd_set_nt_service(struct shttpd_ctx *, const char *);
+extern int _shttpd_set_systray(struct shttpd_ctx *, const char *);
+extern void _shttpd_try_to_run_as_nt_service(void);
+
+/*
+ * io_*.c
+ */
+extern const struct io_class _shttpd_io_file;
+extern const struct io_class _shttpd_io_socket;
+extern const struct io_class _shttpd_io_ssl;
+extern const struct io_class _shttpd_io_cgi;
+extern const struct io_class _shttpd_io_dir;
+extern const struct io_class _shttpd_io_embedded;
+extern const struct io_class _shttpd_io_ssi;
+
+extern int _shttpd_put_dir(const char *path);
+extern void _shttpd_get_dir(struct conn *c);
+extern void _shttpd_get_file(struct conn *c, struct stat *stp);
+extern void _shttpd_ssl_handshake(struct stream *stream);
+extern void _shttpd_setup_embedded_stream(struct conn *,
+ union variant, void *);
+extern struct registered_uri *_shttpd_is_registered_uri(struct shttpd_ctx *,
+ const char *uri);
+extern void _shttpd_do_ssi(struct conn *);
+extern void _shttpd_ssi_func_destructor(struct llhead *lp);
+
+/*
+ * auth.c
+ */
+extern int _shttpd_check_authorization(struct conn *c, const char *path);
+extern int _shttpd_is_authorized_for_put(struct conn *c);
+extern void _shttpd_send_authorization_request(struct conn *c);
+extern int _shttpd_edit_passwords(const char *fname, const char *domain,
+ const char *user, const char *pass);
+
+/*
+ * cgi.c
+ */
+extern int _shttpd_run_cgi(struct conn *c, const char *prog);
+extern void _shttpd_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 */
Added: trunk/libzypp/vendor/shttpd/io.h
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/io.h?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/io.h (added)
+++ trunk/libzypp/vendor/shttpd/io.h Thu Oct 16 19:23:14 2008
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka
+ * 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
+#include
+
+/*
+ * 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 */
Added: trunk/libzypp/vendor/shttpd/io_cgi.c
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/io_cgi.c?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/io_cgi.c (added)
+++ trunk/libzypp/vendor/shttpd/io_cgi.c Thu Oct 16 19:23:14 2008
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka
+ * 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 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) {
+ _shttpd_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 = _shttpd_get_headers_len(stream->io.buf,
+ stream->io.head);
+ if (stream->headers_len < 0) {
+ stream->flags &= ~FLAG_DONT_CLOSE;
+ _shttpd_send_server_error(stream->conn, 500,
+ "Bad headers sent");
+ _shttpd_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));
+ _shttpd_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) _shttpd_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 _shttpd_io_cgi = {
+ "cgi",
+ read_cgi,
+ write_cgi,
+ close_cgi
+};
Added: trunk/libzypp/vendor/shttpd/io_dir.c
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/io_dir.c?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/io_dir.c (added)
+++ trunk/libzypp/vendor/shttpd/io_dir.c Thu Oct 16 19:23:14 2008
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka
+ * 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
+_shttpd_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 (_shttpd_stat(buf, &st) == -1 &&
+ _shttpd_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)
+{
+ static const char footer[] = "</table></body></html>\n";
+
+ 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)
+ 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) _shttpd_snprintf(file, sizeof(file),
+ "%s%s%s", stream->chan.dir.path, slash, dp->d_name);
+ (void) _shttpd_stat(file, &st);
+ if (S_ISDIR(st.st_mode)) {
+ _shttpd_snprintf(size,sizeof(size),"%s","<DIR>");
+ } else {
+ if (st.st_size < 1024)
+ (void) _shttpd_snprintf(size, sizeof(size),
+ "%lu", (unsigned long) st.st_size);
+ else if (st.st_size < 1024 * 1024)
+ (void) _shttpd_snprintf(size,
+ sizeof(size), "%luk",
+ (unsigned long) (st.st_size >> 10) + 1);
+ else
+ (void) _shttpd_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 = _shttpd_snprintf(line, sizeof(line),
+ "<tr><td>%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);
+
+ /* Append proper HTML footer for the page */
+ if (dp == NULL && len >= sizeof(footer)) {
+ (void) memcpy(buf, footer, sizeof(footer));
+ nwritten += sizeof(footer);
+ stream->flags |= FLAG_CLOSED;
+ }
+
+ 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
+_shttpd_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);
+ _shttpd_send_server_error(c, 500, "Cannot open directory");
+ } else {
+ c->loc.io.head = _shttpd_snprintf(c->loc.io.buf, c->loc.io.size,
+ "HTTP/1.1 200 OK\r\n"
+ "Connection: close\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>"
+ "<tr><th>Name</th><th>Modified</th><th>Size</th></tr>"
+ "<tr><hr></td></tr>",
+ c->uri, c->uri);
+ io_clear(&c->rem.io);
+ c->status = 200;
+ c->loc.io_class = &_shttpd_io_dir;
+ c->loc.flags |= FLAG_R | FLAG_ALWAYS_READY;
+ }
+}
+
+const struct io_class _shttpd_io_dir = {
+ "dir",
+ read_dir,
+ NULL,
+ close_dir
+};
Added: trunk/libzypp/vendor/shttpd/io_emb.c
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/io_emb.c?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/io_emb.c (added)
+++ trunk/libzypp/vendor/shttpd/io_emb.c Thu Oct 16 19:23:14 2008
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka
+ * 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"
+
+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;
+
+ if (io_data_len(&c->rem.io) >= c->rem.io.size)
+ arg->flags |= SHTTPD_POST_BUFFER_FULL;
+
+ if (c->rem.content_len > 0 && c->rem.io.total < c->rem.content_len)
+ arg->flags |= SHTTPD_MORE_POST_DATA;
+
+ 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;
+
+ if (arg->flags & SHTTPD_SUSPEND)
+ c->loc.flags |= FLAG_SUSPEND;
+}
+
+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, ...)
+{
+ char *buf = arg->out.buf + arg->out.num_bytes;
+ int buflen = arg->out.len - arg->out.num_bytes, len = 0;
+ va_list ap;
+
+ if (buflen > 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 (_shttpd_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 (_shttpd_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 = _shttpd_strdup(uri);
+ e->callback.v_func = (void (*)(void)) callback;
+ e->callback_data = data;
+ LL_TAIL(&ctx->registered_uris, &e->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; /* End of QUERY_STRING buffer */
+
+ /* buf is "var1=val1&var2=val2...". Find variable first */
+ for (p = buf; p + var_len < e; p++)
+ if ((p == buf || p[-1] == '&') &&
+ p[var_len] == '=' &&
+ !_shttpd_strncasecmp(var, p, var_len)) {
+
+ /* Point 'p' to var value, 's' to the end of value */
+ p += var_len + 1;
+ if ((s = memchr(p, '&', e - p)) == NULL)
+ s = e;
+
+ /* URL-decode value. Return result length */
+ return (_shttpd_url_decode(p, s - p, value, value_len));
+ }
+
+ return (-1);
+}
+
+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 *
+_shttpd_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
+_shttpd_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 = &_shttpd_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);
+ }
+}
+
+void
+shttpd_wakeup(const void *priv)
+{
+ const struct conn *conn = priv;
+ char buf[sizeof(int) + sizeof(void *)];
+ int cmd = CTL_WAKEUP;
+
+#if 0
+ conn->flags &= ~SHTTPD_SUSPEND;
+#endif
+ (void) memcpy(buf, &cmd, sizeof(cmd));
+ (void) memcpy(buf + sizeof(cmd), conn, sizeof(conn));
+
+ (void) send(conn->worker->ctl[1], buf, sizeof(buf), 0);
+}
+
+const struct io_class _shttpd_io_embedded = {
+ "embedded",
+ do_embedded,
+ (int (*)(struct stream *, const void *, size_t)) do_embedded,
+ close_embedded
+};
Added: trunk/libzypp/vendor/shttpd/io_file.c
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/io_file.c?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/io_file.c (added)
+++ trunk/libzypp/vendor/shttpd/io_file.c Thu Oct 16 19:23:14 2008
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka
+ * 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 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, (int) len, n));
+
+ if (n <= 0 || (rem->io.total >= (big_int_t) rem->content_len)) {
+ (void) fstat(fd, &st);
+ stream->io.head = stream->headers_len =
+ _shttpd_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);
+ _shttpd_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
+_shttpd_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.len == 0)
+ _shttpd_get_mime_type(c->ctx, c->uri,
+ strlen(c->uri), &c->mime_type);
+ 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) _shttpd_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(&_shttpd_current_time));
+ (void) strftime(lm, sizeof(lm), fmt, localtime(&stp->st_mtime));
+ (void) _shttpd_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 = _shttpd_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"
+ "Accept-Ranges: bytes\r\n"
+ "%s\r\n",
+ status, msg, date, lm, etag,
+ c->mime_type.len, c->mime_type.ptr, cl, range);
+
+ c->status = status;
+ c->loc.content_len = cl;
+ c->loc.io_class = &_shttpd_io_file;
+ c->loc.flags |= FLAG_R | FLAG_ALWAYS_READY;
+
+ if (c->method == METHOD_HEAD)
+ _shttpd_stop_stream(&c->loc);
+}
+
+const struct io_class _shttpd_io_file = {
+ "file",
+ read_file,
+ write_file,
+ close_file
+};
Added: trunk/libzypp/vendor/shttpd/io_socket.c
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/io_socket.c?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/io_socket.c (added)
+++ trunk/libzypp/vendor/shttpd/io_socket.c Thu Oct 16 19:23:14 2008
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka
+ * 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 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 _shttpd_io_socket = {
+ "socket",
+ read_socket,
+ write_socket,
+ close_socket
+};
Added: trunk/libzypp/vendor/shttpd/io_ssi.c
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/io_ssi.c?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/io_ssi.c (added)
+++ trunk/libzypp/vendor/shttpd/io_ssi.c Thu Oct 16 19:23:14 2008
@@ -0,0 +1,488 @@
+/*
+ * Copyright (c) 2006,2007 Steven Johnson
+ * Copyright (c) 2007 Sergey Lyubka
+ * 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_SSI)
+
+#define CMDBUFSIZ 512 /* SSI command buffer size */
+#define NEST_MAX 6 /* Maximum nesting level */
+
+struct ssi_func {
+ struct llhead link;
+ void *user_data;
+ char *name;
+ shttpd_callback_t func;
+};
+
+struct ssi_inc {
+ int state; /* Buffering state */
+ int cond; /* Conditional state */
+ FILE *fp; /* Icluded file stream */
+ char buf[CMDBUFSIZ]; /* SSI command buffer */
+ size_t nbuf; /* Bytes in a command buffer */
+ FILE *pipe; /* #exec stream */
+ struct ssi_func func; /* #call function */
+};
+
+struct ssi {
+ struct conn *conn; /* Connection we belong to */
+ int nest; /* Current nesting level */
+ struct ssi_inc incs[NEST_MAX]; /* Nested includes */
+};
+
+enum { SSI_PASS, SSI_BUF, SSI_EXEC, SSI_CALL };
+enum { SSI_GO, SSI_STOP }; /* Conditional states */
+
+static const struct vec st = {"".
+ * That means that when do_command() is called, we can rely
+ * on that full command with arguments is buffered in and
+ * there is no need for streaming.
+ * Restrictions:
+ * 1. The command must fit in CMDBUFSIZ
+ * 2. HTML comments inside the command ? Not sure about this.
+ */
+ case SSI_BUF:
+ if (inc->nbuf >= sizeof(inc->buf) - 1) {
+ pass(inc, buf + n, &n);
+ } else if (ch == '>' &&
+ !memcmp(inc->buf + inc->nbuf - 2, "--", 2)) {
+ do_command(ssi, buf + n, len - n, &n);
+ inc = ssi->incs + ssi->nest;
+ } else {
+ inc->buf[inc->nbuf++] = ch;
+
+ /* If not SSI tag, pass it */
+ if (inc->nbuf <= (size_t) st.len &&
+ memcmp(inc->buf, st.ptr, inc->nbuf) != 0)
+ pass(inc, buf + n, &n);
+ }
+ break;
+
+ case SSI_EXEC:
+ case SSI_CALL:
+ break;
+
+ default:
+ /* Never happens */
+ abort();
+ break;
+ }
+
+ if (ssi->nest > 0 && n + inc->nbuf < len && ch == EOF) {
+ (void) fclose(inc->fp);
+ inc->fp = NULL;
+ ssi->nest--;
+ inc--;
+ goto again;
+ }
+
+ return (n);
+}
+
+static void
+close_ssi(struct stream *stream)
+{
+ struct ssi *ssi = stream->conn->ssi;
+ size_t i;
+
+ for (i = 0; i < NELEMS(ssi->incs); i++) {
+ if (ssi->incs[i].fp != NULL)
+ (void) fclose(ssi->incs[i].fp);
+ if (ssi->incs[i].pipe != NULL)
+ (void) pclose(ssi->incs[i].pipe);
+ }
+
+ free(ssi);
+}
+
+void
+_shttpd_do_ssi(struct conn *c)
+{
+ char date[64];
+ struct ssi *ssi;
+
+ (void) strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S GMT",
+ localtime(&_shttpd_current_time));
+
+ c->loc.io.head = c->loc.headers_len = _shttpd_snprintf(c->loc.io.buf,
+ c->loc.io.size,
+ "HTTP/1.1 200 OK\r\n"
+ "Date: %s\r\n"
+ "Content-Type: text/html\r\n"
+ "Connection: close\r\n\r\n",
+ date);
+
+ c->status = 200;
+ c->loc.io_class = &_shttpd_io_ssi;
+ c->loc.flags |= FLAG_R | FLAG_ALWAYS_READY;
+
+ if (c->method == METHOD_HEAD) {
+ _shttpd_stop_stream(&c->loc);
+ } else if ((ssi = calloc(1, sizeof(struct ssi))) == NULL) {
+ _shttpd_send_server_error(c, 500,
+ "Cannot allocate SSI descriptor");
+ } else {
+ ssi->incs[0].fp = fdopen(c->loc.chan.fd, "r");
+ ssi->conn = c;
+ c->ssi = ssi;
+ }
+}
+
+const struct io_class _shttpd_io_ssi = {
+ "ssi",
+ read_ssi,
+ NULL,
+ close_ssi
+};
+
+#endif /* !NO_SSI */
Added: trunk/libzypp/vendor/shttpd/io_ssl.c
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/io_ssl.c?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/io_ssl.c (added)
+++ trunk/libzypp/vendor/shttpd/io_ssl.c Thu Oct 16 19:23:14 2008
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka
+ * 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
+_shttpd_ssl_handshake(struct stream *stream)
+{
+ int n;
+
+ if ((n = SSL_accept(stream->chan.ssl.ssl)) == 1) {
+ DBG(("handshake: SSL accepted"));
+ stream->flags |= FLAG_SSL_ACCEPTED;
+ } else {
+ n = SSL_get_error(stream->chan.ssl.ssl, n);
+ if (n != SSL_ERROR_WANT_READ && n != SSL_ERROR_WANT_WRITE)
+ stream->flags |= FLAG_CLOSED;
+ DBG(("SSL_accept error %d", n));
+ }
+}
+
+static int
+read_ssl(struct stream *stream, void *buf, size_t len)
+{
+ int nread = -1;
+
+ assert(stream->chan.ssl.ssl != NULL);
+
+ if (!(stream->flags & FLAG_SSL_ACCEPTED))
+ _shttpd_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 _shttpd_io_ssl = {
+ "ssl",
+ read_ssl,
+ write_ssl,
+ close_ssl
+};
+#endif /* !NO_SSL */
Added: trunk/libzypp/vendor/shttpd/llist.h
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/llist.h?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/llist.h (added)
+++ trunk/libzypp/vendor/shttpd/llist.h Thu Oct 16 19:23:14 2008
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka
+ * 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 */
Added: trunk/libzypp/vendor/shttpd/log.c
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/log.c?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/log.c (added)
+++ trunk/libzypp/vendor/shttpd/log.c Thu Oct 16 19:23:14 2008
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka
+ * 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
+_shttpd_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 || !IS_TRUE(c->ctx, OPT_INETD)) {
+ 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(&_shttpd_current_time));
+
+ len = _shttpd_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 (flags & E_FATAL)
+ exit(EXIT_FAILURE);
+}
+
+void
+_shttpd_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(&c->birth_time));
+
+ (void) _shttpd_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, _shttpd_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);
+
+ if (fp != NULL) {
+ (void) fprintf(fp, "%s\n", buf);
+ (void) fflush(fp);
+ }
+}
Added: trunk/libzypp/vendor/shttpd/md5.c
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/md5.c?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/md5.c (added)
+++ trunk/libzypp/vendor/shttpd/md5.c Thu Oct 16 19:23:14 2008
@@ -0,0 +1,249 @@
+/*
+ * 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<>(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 */
Added: trunk/libzypp/vendor/shttpd/md5.h
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/md5.h?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/md5.h (added)
+++ trunk/libzypp/vendor/shttpd/md5.h Thu Oct 16 19:23:14 2008
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka
+ * 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 */
Added: trunk/libzypp/vendor/shttpd/shttpd.c
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/shttpd.c?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/shttpd.c (added)
+++ trunk/libzypp/vendor/shttpd/shttpd.c Thu Oct 16 19:23:14 2008
@@ -0,0 +1,1903 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka
+ * 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: shttpd.c,v 1.57 2008/08/23 21:00:38 drozd Exp $
+ */
+
+#include "defs.h"
+
+time_t _shttpd_current_time; /* Current UTC time */
+int _shttpd_tz_offset; /* Time zone offset from UTC */
+int _shttpd_exit_flag; /* Program exit flag */
+
+const struct vec _shttpd_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[]);
+static void process_connection(struct conn *, int, int);
+
+int
+_shttpd_is_true(const char *str)
+{
+ static const char *trues[] = {"1", "yes", "true", "jawohl", NULL};
+ const char **p;
+
+ for (p = trues; *p != NULL; p++)
+ if (str && !strcmp(str, *p))
+ return (TRUE);
+
+ return (FALSE);
+}
+
+static void
+free_list(struct llhead *head, void (*dtor)(struct llhead *))
+{
+ struct llhead *lp, *tmp;
+
+ LL_FOREACH_SAFE(head, lp, tmp) {
+ LL_DEL(lp);
+ dtor(lp);
+ }
+}
+
+static void
+listener_destructor(struct llhead *lp)
+{
+ struct listener *listener = LL_ENTRY(lp, struct listener, link);
+
+ (void) closesocket(listener->sock);
+ free(listener);
+}
+
+static void
+registered_uri_destructor(struct llhead *lp)
+{
+ struct registered_uri *ruri = LL_ENTRY(lp, struct registered_uri, link);
+
+ free((void *) ruri->uri);
+ free(ruri);
+}
+
+static void
+acl_destructor(struct llhead *lp)
+{
+ struct acl *acl = LL_ENTRY(lp, struct acl, link);
+ free(acl);
+}
+
+int
+_shttpd_url_decode(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;
+ default:
+ dst[j] = src[i];
+ break;
+ }
+
+ dst[j] = '\0'; /* Null-terminate the destination */
+
+ return (j);
+}
+
+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->options[OPT_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 || p >= s + len || p == s)
+ continue;
+
+ if (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
+_shttpd_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, (int) io_data_len(&stream->io)));
+}
+
+/*
+ * Setup listening socket on given port, return socket
+ */
+static int
+shttpd_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 (_shttpd_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);
+ _shttpd_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
+_shttpd_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
+_shttpd_send_server_error(struct conn *c, int status, const char *reason)
+{
+ 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);
+ _shttpd_setup_embedded_stream(c,
+ e->callback, e->callback_data);
+ return;
+ }
+ }
+
+ io_clear(&c->loc.io);
+ c->loc.io.head = _shttpd_snprintf(c->loc.io.buf, c->loc.io.size,
+ "HTTP/1.1 %d %s\r\n"
+ "Content-Type: text/plain\r\n"
+ "Content-Length: 12\r\n"
+ "\r\n"
+ "Error: %03d\r\n",
+ status, reason, status);
+ c->loc.content_len = 10;
+ c->status = status;
+ _shttpd_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(&_shttpd_current_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] == '/' || s[-1] == '\\')
+ while (*s == '.' || *s == '/' || *s == '\\')
+ s++;
+ }
+ *p = '\0';
+}
+
+void
+_shttpd_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 &&
+ !_shttpd_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 */
+ }
+}
+
+static const struct {
+ const char *extension;
+ int ext_len;
+ const char *mime_type;
+} builtin_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" },
+ {"swf", 3, "application/x-shockwave-flash" },
+ {"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 }
+};
+
+void
+_shttpd_get_mime_type(struct shttpd_ctx *ctx,
+ const char *uri, int len, struct vec *vec)
+{
+ const char *eq, *p = ctx->options[OPT_MIME_TYPES];
+ int i, n, ext_len;
+
+ /* Firt, loop through the custom mime types if any */
+ FOR_EACH_WORD_IN_LIST(p, n) {
+ if ((eq = memchr(p, '=', n)) == NULL || eq >= p + n || eq == p)
+ continue;
+ ext_len = eq - p;
+ if (len > ext_len && uri[len - ext_len - 1] == '.' &&
+ !_shttpd_strncasecmp(p, &uri[len - ext_len], ext_len)) {
+ vec->ptr = eq + 1;
+ vec->len = p + n - vec->ptr;
+ return;
+ }
+ }
+
+ /* If no luck, try built-in mime types */
+ for (i = 0; builtin_mime_types[i].extension != NULL; i++) {
+ ext_len = builtin_mime_types[i].ext_len;
+ if (len > ext_len && uri[len - ext_len - 1] == '.' &&
+ !_shttpd_strncasecmp(builtin_mime_types[i].extension,
+ &uri[len - ext_len], ext_len)) {
+ vec->ptr = builtin_mime_types[i].mime_type;
+ vec->len = strlen(vec->ptr);
+ return;
+ }
+ }
+
+ /* Oops. This extension is unknown to us. Fallback to text/plain */
+ vec->ptr = "text/plain";
+ vec->len = strlen(vec->ptr);
+}
+
+/*
+ * 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->options[OPT_INDEX_FILES];
+ size_t len;
+
+ FOR_EACH_WORD_IN_LIST(s, len) {
+ /* path must end with '/' character */
+ _shttpd_snprintf(buf, sizeof(buf), "%s%.*s", path, len, s);
+ if (_shttpd_stat(buf, stp) == 0) {
+ _shttpd_strlcpy(path, buf, maxpath);
+ _shttpd_get_mime_type(c->ctx, s, len, &c->mime_type);
+ 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 (_shttpd_stat(path, stp) == 0)
+ return (0);
+
+ p = path + strlen(path);
+ e = path + strlen(c->ctx->options[OPT_ROOT]) + 2;
+
+ /* Strip directory parts of the path one by one */
+ for (; p > e; p--)
+ if (*p == '/') {
+ *p = '\0';
+ if (!_shttpd_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], *root;
+ struct vec alias_uri, alias_path;
+ struct stat st;
+ int rc;
+ struct registered_uri *ruri;
+
+ DBG(("decide_what_to_do: [%s]", c->uri));
+
+ if ((c->query = strchr(c->uri, '?')) != NULL)
+ *c->query++ = '\0';
+
+ _shttpd_url_decode(c->uri, strlen(c->uri), c->uri, strlen(c->uri) + 1);
+ remove_double_dots(c->uri);
+
+ root = c->ctx->options[OPT_ROOT];
+ if (strlen(c->uri) + strlen(root) >= sizeof(path)) {
+ _shttpd_send_server_error(c, 400, "URI is too long");
+ return;
+ }
+
+ (void) _shttpd_snprintf(path, sizeof(path), "%s%s", 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) _shttpd_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 (_shttpd_check_authorization(c, path) != 1) {
+ _shttpd_send_authorization_request(c);
+ } else
+#endif /* NO_AUTH */
+ if ((ruri = _shttpd_is_registered_uri(c->ctx, c->uri)) != NULL) {
+ _shttpd_setup_embedded_stream(c,
+ ruri->callback, ruri->callback_data);
+ } else
+ if (strstr(path, HTPASSWD)) {
+ /* Do not allow to view passwords files */
+ _shttpd_send_server_error(c, 403, "Forbidden");
+ } else
+#if !defined(NO_AUTH)
+ if ((c->method == METHOD_PUT || c->method == METHOD_DELETE) &&
+ (c->ctx->options[OPT_AUTH_PUT] == NULL ||
+ !_shttpd_is_authorized_for_put(c))) {
+ _shttpd_send_authorization_request(c);
+ } else
+#endif /* NO_AUTH */
+ if (c->method == METHOD_PUT) {
+ c->status = _shttpd_stat(path, &st) == 0 ? 200 : 201;
+
+ if (c->ch.range.v_vec.len > 0) {
+ _shttpd_send_server_error(c, 501,
+ "PUT Range Not Implemented");
+ } else if ((rc = _shttpd_put_dir(path)) == 0) {
+ _shttpd_send_server_error(c, 200, "OK");
+ } else if (rc == -1) {
+ _shttpd_send_server_error(c, 500, "PUT Directory Error");
+ } else if (c->rem.content_len == 0) {
+ _shttpd_send_server_error(c, 411, "Length Required");
+ } else if ((c->loc.chan.fd = _shttpd_open(path, O_WRONLY | O_BINARY |
+ O_CREAT | O_NONBLOCK | O_TRUNC, 0644)) == -1) {
+ _shttpd_send_server_error(c, 500, "PUT Error");
+ } else {
+ DBG(("PUT file [%s]", c->uri));
+ c->loc.io_class = &_shttpd_io_file;
+ c->loc.flags |= FLAG_W | FLAG_ALWAYS_READY ;
+ }
+ } else if (c->method == METHOD_DELETE) {
+ DBG(("DELETE [%s]", c->uri));
+ if (_shttpd_remove(path) == 0)
+ _shttpd_send_server_error(c, 200, "OK");
+ else
+ _shttpd_send_server_error(c, 500, "DELETE Error");
+ } else if (get_path_info(c, path, &st) != 0) {
+ _shttpd_send_server_error(c, 404, "Not Found");
+ } else if (S_ISDIR(st.st_mode) && path[strlen(path) - 1] != '/') {
+ (void) _shttpd_snprintf(buf, sizeof(buf),
+ "Moved Permanently\r\nLocation: %s/", c->uri);
+ _shttpd_send_server_error(c, 301, buf);
+ } else if (S_ISDIR(st.st_mode) &&
+ find_index_file(c, path, sizeof(path) - 1, &st) == -1 &&
+ !IS_TRUE(c->ctx, OPT_DIR_LIST)) {
+ _shttpd_send_server_error(c, 403, "Directory Listing Denied");
+ } else if (S_ISDIR(st.st_mode) && IS_TRUE(c->ctx, OPT_DIR_LIST)) {
+ if ((c->loc.chan.dir.path = _shttpd_strdup(path)) != NULL)
+ _shttpd_get_dir(c);
+ else
+ _shttpd_send_server_error(c, 500, "GET Directory Error");
+ } else if (S_ISDIR(st.st_mode) && !IS_TRUE(c->ctx, OPT_DIR_LIST)) {
+ _shttpd_send_server_error(c, 403, "Directory listing denied");
+#if !defined(NO_CGI)
+ } else if (_shttpd_match_extension(path,
+ c->ctx->options[OPT_CGI_EXTENSIONS])) {
+ if (c->method != METHOD_POST && c->method != METHOD_GET) {
+ _shttpd_send_server_error(c, 501, "Bad method ");
+ } else if ((_shttpd_run_cgi(c, path)) == -1) {
+ _shttpd_send_server_error(c, 500, "Cannot exec CGI");
+ } else {
+ _shttpd_do_cgi(c);
+ }
+#endif /* NO_CGI */
+#if !defined(NO_SSI)
+ } else if (_shttpd_match_extension(path,
+ c->ctx->options[OPT_SSI_EXTENSIONS])) {
+ if ((c->loc.chan.fd = _shttpd_open(path,
+ O_RDONLY | O_BINARY, 0644)) == -1) {
+ _shttpd_send_server_error(c, 500, "SSI open error");
+ } else {
+ _shttpd_do_ssi(c);
+ }
+#endif /* NO_CGI */
+ } else if (c->ch.ims.v_time && st.st_mtime <= c->ch.ims.v_time) {
+ _shttpd_send_server_error(c, 304, "Not Modified");
+ } else if ((c->loc.chan.fd = _shttpd_open(path,
+ O_RDONLY | O_BINARY, 0644)) != -1) {
+ _shttpd_get_file(c, &st);
+ } else {
+ _shttpd_send_server_error(c, 500, "Internal Error");
+ }
+}
+
+static int
+set_request_method(struct conn *c)
+{
+ const struct vec *v;
+
+ /* Set the request method */
+ for (v = _shttpd_known_http_methods; v->ptr != NULL; v++)
+ if (!memcmp(c->rem.io.buf, v->ptr, v->len)) {
+ c->method = v - _shttpd_known_http_methods;
+ break;
+ }
+
+ return (v->ptr == NULL);
+}
+
+static void
+parse_http_request(struct conn *c)
+{
+ char *s, *e, *p, *start;
+ int uri_len, req_len, n;
+
+ s = io_data(&c->rem.io);;
+ req_len = c->rem.headers_len =
+ _shttpd_get_headers_len(s, io_data_len(&c->rem.io));
+
+ if (req_len == 0 && io_space_len(&c->rem.io) == 0) {
+ io_clear(&c->rem.io);
+ _shttpd_send_server_error(c, 400, "Request is too big");
+ }
+
+ if (req_len == 0) {
+ return;
+ } else if (req_len < 16) { /* Minimal: "GET / HTTP/1.0\n\n" */
+ _shttpd_send_server_error(c, 400, "Bad request");
+ } else if (set_request_method(c)) {
+ _shttpd_send_server_error(c, 501, "Method Not Implemented");
+ } else if ((c->request = _shttpd_strndup(s, req_len)) == NULL) {
+ _shttpd_send_server_error(c, 500, "Cannot allocate request");
+ }
+
+ if (c->loc.flags & FLAG_CLOSED)
+ return;
+
+ io_inc_tail(&c->rem.io, req_len);
+
+ 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 (sscanf(p, "HTTP/%lu.%lu%n",
+ &c->major_version, &c->minor_version, &n) != 2 || p[n] != '\0') {
+ _shttpd_send_server_error(c, 400, "Bad HTTP version");
+ } else if (c->major_version > 1 ||
+ (c->major_version == 1 && c->minor_version > 1)) {
+ _shttpd_send_server_error(c, 505, "HTTP version not supported");
+ } else if (uri_len <= 0) {
+ _shttpd_send_server_error(c, 400, "Bad URI");
+ } else if ((c->uri = malloc(uri_len + 1)) == NULL) {
+ _shttpd_send_server_error(c, 500, "Cannot allocate URI");
+ } else {
+ _shttpd_strlcpy(c->uri, (char *) start, uri_len + 1);
+ _shttpd_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;
+ decide_what_to_do(c);
+ }
+}
+
+static void
+add_socket(struct worker *worker, int sock, int is_ssl)
+{
+ struct shttpd_ctx *ctx = worker->ctx;
+ struct conn *c;
+ struct usa sa;
+ int l = IS_TRUE(ctx, OPT_INETD) ? E_FATAL : E_LOG;
+#if !defined(NO_SSL)
+ SSL *ssl = NULL;
+#else
+ is_ssl = is_ssl; /* supress warnings */
+#endif /* NO_SSL */
+
+ sa.len = sizeof(sa.u.sin);
+ (void) _shttpd_set_non_blocking_mode(sock);
+
+ if (getpeername(sock, &sa.u.sa, &sa.len)) {
+ _shttpd_elog(l, NULL, "add_socket: %s", strerror(errno));
+#if !defined(NO_SSL)
+ } else if (is_ssl && (ssl = SSL_new(ctx->ssl_ctx)) == NULL) {
+ _shttpd_elog(l, NULL, "add_socket: SSL_new: %s", strerror(ERRNO));
+ (void) closesocket(sock);
+ } else if (is_ssl && SSL_set_fd(ssl, sock) == 0) {
+ _shttpd_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 * URI_MAX)) == NULL) {
+#if !defined(NO_SSL)
+ if (ssl)
+ SSL_free(ssl);
+#endif /* NO_SSL */
+ (void) closesocket(sock);
+ _shttpd_elog(l, NULL, "add_socket: calloc: %s", strerror(ERRNO));
+ } else {
+ c->rem.conn = c->loc.conn = c;
+ c->ctx = ctx;
+ c->worker = worker;
+ c->sa = sa;
+ c->birth_time = _shttpd_current_time;
+ c->expire_time = _shttpd_current_time + EXPIRE_TIME;
+
+ (void) getsockname(sock, &sa.u.sa, &sa.len);
+ c->loc_port = sa.u.sin.sin_port;
+
+ _shttpd_set_close_on_exec(sock);
+
+ c->loc.io_class = NULL;
+
+ c->rem.io_class = &_shttpd_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 + URI_MAX;
+ c->loc.io.size = c->rem.io.size = URI_MAX;
+
+#if !defined(NO_SSL)
+ if (is_ssl) {
+ c->rem.io_class = &_shttpd_io_ssl;
+ c->rem.chan.ssl.sock = sock;
+ c->rem.chan.ssl.ssl = ssl;
+ _shttpd_ssl_handshake(&c->rem);
+ }
+#endif /* NO_SSL */
+
+ LL_TAIL(&worker->connections, &c->link);
+ worker->num_conns++;
+
+ 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));
+ }
+}
+
+static struct worker *
+first_worker(struct shttpd_ctx *ctx)
+{
+ return (LL_ENTRY(ctx->workers.next, struct worker, link));
+}
+
+static void
+pass_socket(struct shttpd_ctx *ctx, int sock, int is_ssl)
+{
+ struct llhead *lp;
+ struct worker *worker, *lazy;
+ int buf[3];
+
+ lazy = first_worker(ctx);
+
+ /* Find least busy worker */
+ LL_FOREACH(&ctx->workers, lp) {
+ worker = LL_ENTRY(lp, struct worker, link);
+ if (worker->num_conns < lazy->num_conns)
+ lazy = worker;
+ }
+
+ buf[0] = CTL_PASS_SOCKET;
+ buf[1] = sock;
+ buf[2] = is_ssl;
+
+ (void) send(lazy->ctl[1], (void *) buf, sizeof(buf), 0);
+}
+
+static int
+set_ports(struct shttpd_ctx *ctx, const char *p)
+{
+ int sock, len, is_ssl, port;
+ struct listener *l;
+
+
+ free_list(&ctx->listeners, &listener_destructor);
+
+ FOR_EACH_WORD_IN_LIST(p, len) {
+
+ is_ssl = p[len - 1] == 's' ? 1 : 0;
+ port = atoi(p);
+
+ if ((sock = shttpd_open_listening_port(port)) == -1) {
+ _shttpd_elog(E_LOG, NULL, "cannot open port %d", port);
+ goto fail;
+ } else if (is_ssl && ctx->ssl_ctx == NULL) {
+ (void) closesocket(sock);
+ _shttpd_elog(E_LOG, NULL, "cannot add SSL socket, "
+ "please specify certificate file");
+ goto fail;
+ } else if ((l = calloc(1, sizeof(*l))) == NULL) {
+ (void) closesocket(sock);
+ _shttpd_elog(E_LOG, NULL, "cannot allocate listener");
+ goto fail;
+ } else {
+ l->is_ssl = is_ssl;
+ l->sock = sock;
+ l->ctx = ctx;
+ LL_TAIL(&ctx->listeners, &l->link);
+ DBG(("shttpd_listen: added socket %d", sock));
+ }
+ }
+
+ return (TRUE);
+fail:
+ free_list(&ctx->listeners, &listener_destructor);
+ return (FALSE);
+}
+
+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 */
+ assert(stream->io_class != NULL);
+ n = 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))
+ _shttpd_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)
+ _shttpd_stop_stream(stream);
+ }
+
+ stream->conn->expire_time = _shttpd_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 = _shttpd_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))
+ _shttpd_stop_stream(to);
+}
+
+
+static void
+connection_desctructor(struct llhead *lp)
+{
+ struct conn *c = LL_ENTRY(lp, struct conn, link);
+ static const struct vec vec = {"close", 5};
+ int do_close;
+
+ DBG(("Disconnecting %d (%.*s)", c->rem.chan.sock,
+ c->ch.connection.v_vec.len, c->ch.connection.v_vec.ptr));
+
+ if (c->request != NULL && c->ctx->access_log != NULL)
+ _shttpd_log_access(c->ctx->access_log, c);
+
+ /* In inetd mode, exit if request is finished. */
+ if (IS_TRUE(c->ctx, OPT_INETD))
+ 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
+ */
+ do_close = (c->ch.connection.v_vec.len >= vec.len &&
+ !_shttpd_strncasecmp(vec.ptr,c->ch.connection.v_vec.ptr,vec.len)) ||
+ (c->major_version < 1 ||
+ (c->major_version >= 1 && c->minor_version < 1));
+
+ if (c->request)
+ free(c->request);
+ if (c->uri)
+ free(c->uri);
+
+ /* Keep the connection open only if we have Content-Length set */
+ if (!do_close && c->loc.content_len > 0) {
+ c->loc.io_class = NULL;
+ c->loc.flags = 0;
+ c->loc.content_len = 0;
+ c->rem.flags = FLAG_W | FLAG_R | FLAG_SSL_ACCEPTED;
+ c->query = c->request = c->uri = c->path_info = NULL;
+ c->mime_type.len = 0;
+ (void) memset(&c->ch, 0, sizeof(c->ch));
+ io_clear(&c->loc.io);
+ c->birth_time = _shttpd_current_time;
+ if (io_data_len(&c->rem.io) > 0)
+ process_connection(c, 0, 0);
+ } else {
+ if (c->rem.io_class != NULL)
+ c->rem.io_class->close(&c->rem);
+
+ LL_DEL(&c->link);
+ c->worker->num_conns--;
+ assert(c->worker->num_conns >= 0);
+
+ free(c);
+ }
+}
+
+static void
+worker_destructor(struct llhead *lp)
+{
+ struct worker *worker = LL_ENTRY(lp, struct worker, link);
+
+ free_list(&worker->connections, connection_desctructor);
+ free(worker);
+}
+
+static int
+is_allowed(const struct shttpd_ctx *ctx, const struct usa *usa)
+{
+ const struct acl *acl;
+ const struct llhead *lp;
+ int allowed = '+';
+ uint32_t ip;
+
+ LL_FOREACH(&ctx->acl, lp) {
+ acl = LL_ENTRY(lp, struct acl, link);
+ (void) memcpy(&ip, &usa->u.sin.sin_addr, sizeof(ip));
+ if (acl->ip == (ntohl(ip) & acl->mask))
+ allowed = acl->flag;
+ }
+
+ return (allowed == '+');
+}
+
+static void
+add_to_set(int fd, fd_set *set, int *max_fd)
+{
+ FD_SET(fd, set);
+ if (fd > *max_fd)
+ *max_fd = fd;
+}
+
+static void
+process_connection(struct conn *c, int remote_ready, int local_ready)
+{
+ /* Read from remote end if it is ready */
+ if (remote_ready && 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: %d [%.*s]", (int) io_data_len(&c->loc.io),
+ (int) io_data_len(&c->loc.io), io_data(&c->loc.io)));
+ DBG(("rem: %d [%.*s]", (int) io_data_len(&c->rem.io),
+ (int) io_data_len(&c->rem.io), io_data(&c->rem.io)));
+
+ /* Read from the local end if it is ready */
+ if (local_ready && io_space_len(&c->loc.io))
+ 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);
+
+ /* Check whether we should close this connection */
+ if ((_shttpd_current_time > c->expire_time) ||
+ (c->rem.flags & FLAG_CLOSED) ||
+ ((c->loc.flags & FLAG_CLOSED) && !io_data_len(&c->loc.io)))
+ connection_desctructor(&c->link);
+}
+
+static int
+num_workers(const struct shttpd_ctx *ctx)
+{
+ char *p = ctx->options[OPT_THREADS];
+ return (p ? atoi(p) : 1);
+}
+
+static void
+handle_connected_socket(struct shttpd_ctx *ctx,
+ struct usa *sap, int sock, int is_ssl)
+{
+#if !defined(_WIN32)
+ if (sock >= (int) FD_SETSIZE) {
+ _shttpd_elog(E_LOG, NULL, "ctx %p: discarding "
+ "socket %d, too busy", ctx, sock);
+ (void) closesocket(sock);
+ } else
+#endif /* !_WIN32 */
+ if (!is_allowed(ctx, sap)) {
+ _shttpd_elog(E_LOG, NULL, "%s is not allowed to connect",
+ inet_ntoa(sap->u.sin.sin_addr));
+ (void) closesocket(sock);
+ } else if (num_workers(ctx) > 1) {
+ pass_socket(ctx, sock, is_ssl);
+ } else {
+ add_socket(first_worker(ctx), sock, is_ssl);
+ }
+}
+
+static int
+do_select(int max_fd, fd_set *read_set, fd_set *write_set, int milliseconds)
+{
+ struct timeval tv;
+ int n;
+
+ tv.tv_sec = milliseconds / 1000;
+ tv.tv_usec = (milliseconds % 1000) * 1000;
+
+ /* Check IO readiness */
+ if ((n = 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 (n);
+}
+
+static int
+multiplex_worker_sockets(const struct worker *worker, int *max_fd,
+ fd_set *read_set, fd_set *write_set)
+{
+ struct llhead *lp;
+ struct conn *c;
+ int nowait = FALSE;
+
+ /* Add control socket */
+ add_to_set(worker->ctl[0], read_set, max_fd);
+
+ /* Multiplex streams */
+ LL_FOREACH(&worker->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 == &_shttpd_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 == &_shttpd_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) && !(c->loc.flags & FLAG_SUSPEND))
+ add_to_set(c->rem.chan.fd, write_set, max_fd);
+
+ /*
+ * Set select wait interval to zero if FLAG_ALWAYS_READY set
+ */
+ if (io_space_len(&c->loc.io) && (c->loc.flags & FLAG_R) &&
+ (c->loc.flags & FLAG_ALWAYS_READY))
+ nowait = TRUE;
+
+ if (io_data_len(&c->rem.io) && (c->loc.flags & FLAG_W) &&
+ (c->loc.flags & FLAG_ALWAYS_READY))
+ nowait = TRUE;
+ }
+
+ return (nowait);
+}
+
+int
+shttpd_join(struct shttpd_ctx *ctx,
+ fd_set *read_set, fd_set *write_set, int *max_fd)
+{
+ struct llhead *lp;
+ struct listener *l;
+ int nowait = FALSE;
+
+ /* Add listening sockets to the read set */
+ LL_FOREACH(&ctx->listeners, lp) {
+ l = LL_ENTRY(lp, struct listener, link);
+ add_to_set(l->sock, read_set, max_fd);
+ DBG(("FD_SET(%d) (listening)", l->sock));
+ }
+
+ if (num_workers(ctx) == 1)
+ nowait = multiplex_worker_sockets(first_worker(ctx), max_fd,
+ read_set, write_set);
+
+ return (nowait);
+}
+
+
+static void
+process_worker_sockets(struct worker *worker, fd_set *read_set)
+{
+ struct llhead *lp, *tmp;
+ int cmd, skt[2], sock = worker->ctl[0];
+ struct conn *c;
+
+ /* Check if new socket is passed to us over the control socket */
+ if (FD_ISSET(worker->ctl[0], read_set))
+ while (recv(sock, (void *) &cmd, sizeof(cmd), 0) == sizeof(cmd))
+ switch (cmd) {
+ case CTL_PASS_SOCKET:
+ (void)recv(sock, (void *) &skt, sizeof(skt), 0);
+ add_socket(worker, skt[0], skt[1]);
+ break;
+ case CTL_WAKEUP:
+ (void)recv(sock, (void *) &c, sizeof(c), 0);
+ c->loc.flags &= FLAG_SUSPEND;
+ break;
+ default:
+ _shttpd_elog(E_FATAL, NULL, "ctx %p: ctl cmd %d",
+ worker->ctx, cmd);
+ break;
+ }
+
+ /* Process all connections */
+ LL_FOREACH_SAFE(&worker->connections, lp, tmp) {
+ c = LL_ENTRY(lp, struct conn, link);
+ process_connection(c, FD_ISSET(c->rem.chan.sock, read_set),
+ c->loc.io_class != NULL &&
+ ((c->loc.flags & FLAG_ALWAYS_READY)
+#if !defined(NO_CGI)
+ || (c->loc.io_class == &_shttpd_io_cgi &&
+ FD_ISSET(c->loc.chan.fd, read_set))
+#endif /* NO_CGI */
+ ));
+ }
+}
+
+/*
+ * 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;
+ struct listener *l;
+ fd_set read_set, write_set;
+ int sock, max_fd = -1;
+ struct usa sa;
+
+ _shttpd_current_time = time(0);
+ FD_ZERO(&read_set);
+ FD_ZERO(&write_set);
+
+ if (shttpd_join(ctx, &read_set, &write_set, &max_fd))
+ milliseconds = 0;
+
+ if (do_select(max_fd, &read_set, &write_set, milliseconds) < 0)
+ return;;
+
+ /* Check for incoming connections on listener sockets */
+ LL_FOREACH(&ctx->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)
+ handle_connected_socket(ctx,&sa,sock,l->is_ssl);
+ } while (sock != -1);
+ }
+
+ if (num_workers(ctx) == 1)
+ process_worker_sockets(first_worker(ctx), &read_set);
+}
+
+/*
+ * Deallocate shttpd object, free up the resources
+ */
+void
+shttpd_fini(struct shttpd_ctx *ctx)
+{
+ size_t i;
+
+ free_list(&ctx->workers, worker_destructor);
+ free_list(&ctx->registered_uris, registered_uri_destructor);
+ free_list(&ctx->acl, acl_destructor);
+ free_list(&ctx->listeners, listener_destructor);
+#if !defined(NO_SSI)
+ free_list(&ctx->ssi_funcs, _shttpd_ssi_func_destructor);
+#endif /* !NO_SSI */
+
+ for (i = 0; i < NELEMS(ctx->options); i++)
+ if (ctx->options[i] != NULL)
+ free(ctx->options[i]);
+
+ if (ctx->access_log) (void) fclose(ctx->access_log);
+ if (ctx->error_log) (void) fclose(ctx->error_log);
+
+ /* TODO: free SSL context */
+
+ free(ctx);
+}
+
+/*
+ * UNIX socketpair() implementation. Why? Because Windows does not have it.
+ * Return 0 on success, -1 on error.
+ */
+int
+shttpd_socketpair(int sp[2])
+{
+ struct sockaddr_in sa;
+ int sock, ret = -1;
+ socklen_t len = sizeof(sa);
+
+ sp[0] = sp[1] = -1;
+
+ (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 &&
+ !bind(sock, (struct sockaddr *) &sa, len) &&
+ !listen(sock, 1) &&
+ !getsockname(sock, (struct sockaddr *) &sa, &len) &&
+ (sp[0] = socket(AF_INET, SOCK_STREAM, 6)) != -1 &&
+ !connect(sp[0], (struct sockaddr *) &sa, len) &&
+ (sp[1] = accept(sock,(struct sockaddr *) &sa, &len)) != -1) {
+
+ /* Success */
+ ret = 0;
+ } else {
+
+ /* Failure, close descriptors */
+ if (sp[0] != -1)
+ (void) closesocket(sp[0]);
+ if (sp[1] != -1)
+ (void) closesocket(sp[1]);
+ }
+
+ (void) closesocket(sock);
+ (void) _shttpd_set_non_blocking_mode(sp[0]);
+ (void) _shttpd_set_non_blocking_mode(sp[1]);
+
+#ifndef _WIN32
+ (void) fcntl(sp[0], F_SETFD, FD_CLOEXEC);
+ (void) fcntl(sp[1], F_SETFD, FD_CLOEXEC);
+#endif /* _WIN32*/
+
+ return (ret);
+}
+
+static int isbyte(int n) { return (n >= 0 && n <= 255); }
+
+static int
+set_inetd(struct shttpd_ctx *ctx, const char *flag)
+{
+ ctx = NULL; /* Unused */
+
+ if (_shttpd_is_true(flag)) {
+ shttpd_set_option(ctx, "ports", NULL);
+ (void) freopen("/dev/null", "a", stderr);
+ add_socket(first_worker(ctx), 0, 0);
+ }
+
+ return (TRUE);
+}
+
+static int
+set_uid(struct shttpd_ctx *ctx, const char *uid)
+{
+ struct passwd *pw;
+
+ ctx = NULL; /* Unused */
+
+#if !defined(_WIN32)
+ if ((pw = getpwnam(uid)) == NULL)
+ _shttpd_elog(E_FATAL, 0, "%s: unknown user [%s]", __func__, uid);
+ else if (setgid(pw->pw_gid) == -1)
+ _shttpd_elog(E_FATAL, NULL, "%s: setgid(%s): %s",
+ __func__, uid, strerror(errno));
+ else if (setuid(pw->pw_uid) == -1)
+ _shttpd_elog(E_FATAL, NULL, "%s: setuid(%s): %s",
+ __func__, uid, strerror(errno));
+#endif /* !_WIN32 */
+ return (TRUE);
+}
+
+static int
+set_acl(struct shttpd_ctx *ctx, const char *s)
+{
+ struct acl *acl = NULL;
+ char flag;
+ int len, a, b, c, d, n, mask;
+
+ /* Delete the old ACLs if any */
+ free_list(&ctx->acl, acl_destructor);
+
+ FOR_EACH_WORD_IN_LIST(s, len) {
+
+ mask = 32;
+
+ if (sscanf(s, "%c%d.%d.%d.%d%n",&flag,&a,&b,&c,&d,&n) != 5) {
+ _shttpd_elog(E_FATAL, NULL, "[%s]: subnet must be "
+ "[+|-]x.x.x.x[/x]", s);
+ } else if (flag != '+' && flag != '-') {
+ _shttpd_elog(E_FATAL, NULL, "flag must be + or -: [%s]", s);
+ } else if (!isbyte(a)||!isbyte(b)||!isbyte(c)||!isbyte(d)) {
+ _shttpd_elog(E_FATAL, NULL, "bad ip address: [%s]", s);
+ } else if ((acl = malloc(sizeof(*acl))) == NULL) {
+ _shttpd_elog(E_FATAL, NULL, "%s", "cannot malloc subnet");
+ } else if (sscanf(s + n, "/%d", &mask) == 0) {
+ /* Do nothing, no mask specified */
+ } else if (mask < 0 || mask > 32) {
+ _shttpd_elog(E_FATAL, NULL, "bad subnet mask: %d [%s]", n, s);
+ }
+
+ acl->ip = (a << 24) | (b << 16) | (c << 8) | d;
+ acl->mask = mask ? 0xffffffffU << (32 - mask) : 0;
+ acl->flag = flag;
+ LL_TAIL(&ctx->acl, &acl->link);
+ }
+
+ return (TRUE);
+}
+
+#ifndef NO_SSL
+/*
+ * Dynamically load SSL library. Set up ctx->ssl_ctx pointer.
+ */
+static int
+set_ssl(struct shttpd_ctx *ctx, const char *pem)
+{
+ SSL_CTX *CTX;
+ void *lib;
+ struct ssl_func *fp;
+ int retval = FALSE;
+
+ /* Load SSL library dynamically */
+ if ((lib = dlopen(SSL_LIB, RTLD_LAZY)) == NULL) {
+ _shttpd_elog(E_LOG, NULL, "set_ssl: cannot load %s", SSL_LIB);
+ return (FALSE);
+ }
+
+ for (fp = ssl_sw; fp->name != NULL; fp++)
+ if ((fp->ptr.v_void = dlsym(lib, fp->name)) == NULL) {
+ _shttpd_elog(E_LOG, NULL,"set_ssl: cannot find %s", fp->name);
+ return (FALSE);
+ }
+
+ /* Initialize SSL crap */
+ SSL_library_init();
+
+ if ((CTX = SSL_CTX_new(SSLv23_server_method())) == NULL)
+ _shttpd_elog(E_LOG, NULL, "SSL_CTX_new error");
+ else if (SSL_CTX_use_certificate_file(CTX, pem, SSL_FILETYPE_PEM) == 0)
+ _shttpd_elog(E_LOG, NULL, "cannot open %s", pem);
+ else if (SSL_CTX_use_PrivateKey_file(CTX, pem, SSL_FILETYPE_PEM) == 0)
+ _shttpd_elog(E_LOG, NULL, "cannot open %s", pem);
+ else
+ retval = TRUE;
+
+ ctx->ssl_ctx = CTX;
+
+ return (retval);
+}
+#endif /* NO_SSL */
+
+static int
+open_log_file(FILE **fpp, const char *path)
+{
+ int retval = TRUE;
+
+ if (*fpp != NULL)
+ (void) fclose(*fpp);
+
+ if (path == NULL) {
+ *fpp = NULL;
+ } else if ((*fpp = fopen(path, "a")) == NULL) {
+ _shttpd_elog(E_LOG, NULL, "cannot open log file %s: %s",
+ path, strerror(errno));
+ retval = FALSE;
+ }
+
+ return (retval);
+}
+
+static int set_alog(struct shttpd_ctx *ctx, const char *path) {
+ return (open_log_file(&ctx->access_log, path));
+}
+
+static int set_elog(struct shttpd_ctx *ctx, const char *path) {
+ return (open_log_file(&ctx->error_log, path));
+}
+
+static void show_cfg_page(struct shttpd_arg *arg);
+
+static int
+set_cfg_uri(struct shttpd_ctx *ctx, const char *uri)
+{
+ free_list(&ctx->registered_uris, ®istered_uri_destructor);
+
+ if (uri != NULL)
+ shttpd_register_uri(ctx, uri, &show_cfg_page, ctx);
+
+ return (TRUE);
+}
+
+static struct worker *
+add_worker(struct shttpd_ctx *ctx)
+{
+ struct worker *worker;
+
+ if ((worker = calloc(1, sizeof(*worker))) == NULL)
+ _shttpd_elog(E_FATAL, NULL, "Cannot allocate worker");
+ LL_INIT(&worker->connections);
+ worker->ctx = ctx;
+ (void) shttpd_socketpair(worker->ctl);
+ LL_TAIL(&ctx->workers, &worker->link);
+
+ return (worker);
+}
+
+#if !defined(NO_THREADS)
+static void
+poll_worker(struct worker *worker, int milliseconds)
+{
+ fd_set read_set, write_set;
+ int max_fd = -1;
+
+ FD_ZERO(&read_set);
+ FD_ZERO(&write_set);
+
+ if (multiplex_worker_sockets(worker, &max_fd, &read_set, &write_set))
+ milliseconds = 0;
+
+ if (do_select(max_fd, &read_set, &write_set, milliseconds) < 0)
+ return;;
+
+ process_worker_sockets(worker, &read_set);
+}
+
+static void
+worker_function(void *param)
+{
+ struct worker *worker = param;
+
+ while (worker->exit_flag == 0)
+ poll_worker(worker, 1000 * 10);
+
+ free_list(&worker->connections, connection_desctructor);
+ free(worker);
+}
+
+static int
+set_workers(struct shttpd_ctx *ctx, const char *value)
+{
+ int new_num, old_num;
+ struct llhead *lp, *tmp;
+ struct worker *worker;
+
+ new_num = atoi(value);
+ old_num = 0;
+ LL_FOREACH(&ctx->workers, lp)
+ old_num++;
+
+ if (new_num == 1) {
+ if (old_num > 1)
+ /* Stop old threads */
+ LL_FOREACH_SAFE(&ctx->workers, lp, tmp) {
+ worker = LL_ENTRY(lp, struct worker, link);
+ LL_DEL(&worker->link);
+ worker = LL_ENTRY(lp, struct worker, link);
+ worker->exit_flag = 1;
+ }
+ (void) add_worker(ctx);
+ } else {
+ /* FIXME: we cannot here reduce the number of threads */
+ while (new_num > 1 && new_num > old_num) {
+ worker = add_worker(ctx);
+ _beginthread(worker_function, 0, worker);
+ old_num++;
+ }
+ }
+
+ return (TRUE);
+}
+#endif /* NO_THREADS */
+
+static const struct opt {
+ int index; /* Index in shttpd_ctx */
+ const char *name; /* Option name in config file */
+ const char *description; /* Description */
+ const char *default_value; /* Default option value */
+ int (*setter)(struct shttpd_ctx *, const char *);
+} known_options[] = {
+ {OPT_ROOT, "root", "\tWeb root directory", ".", NULL},
+ {OPT_INDEX_FILES, "index_files", "Index files", INDEX_FILES, NULL},
+#ifndef NO_SSL
+ {OPT_SSL_CERTIFICATE, "ssl_cert", "SSL certificate file", NULL,set_ssl},
+#endif /* NO_SSL */
+ {OPT_PORTS, "ports", "Listening ports", LISTENING_PORTS, set_ports},
+ {OPT_DIR_LIST, "dir_list", "Directory listing", "yes", NULL},
+ {OPT_CFG_URI, "cfg_uri", "Config uri", NULL, set_cfg_uri},
+ {OPT_PROTECT, "protect", "URI to htpasswd mapping", NULL, NULL},
+#ifndef NO_CGI
+ {OPT_CGI_EXTENSIONS, "cgi_ext", "CGI extensions", CGI_EXT, NULL},
+ {OPT_CGI_INTERPRETER, "cgi_interp", "CGI interpreter", NULL, NULL},
+ {OPT_CGI_ENVIRONMENT, "cgi_env", "Additional CGI env vars", NULL, NULL},
+#endif /* NO_CGI */
+ {OPT_SSI_EXTENSIONS, "ssi_ext", "SSI extensions", SSI_EXT, NULL},
+#ifndef NO_AUTH
+ {OPT_AUTH_REALM, "auth_realm", "Authentication domain name",REALM,NULL},
+ {OPT_AUTH_GPASSWD, "auth_gpass", "Global passwords file", NULL, NULL},
+ {OPT_AUTH_PUT, "auth_PUT", "PUT,DELETE auth file", NULL, NULL},
+#endif /* !NO_AUTH */
+#ifdef _WIN32
+ {OPT_SERVICE, "service", "Manage WinNNT service (install"
+ "|uninstall)", NULL, _shttpd_set_nt_service},
+ {OPT_HIDE, "systray", "Hide console, show icon on systray",
+ "no", _shttpd_set_systray},
+#else
+ {OPT_INETD, "inetd", "Inetd mode", "no", set_inetd},
+ {OPT_UID, "uid", "\tRun as user", NULL, set_uid},
+#endif /* _WIN32 */
+ {OPT_ACCESS_LOG, "access_log", "Access log file", NULL, set_alog},
+ {OPT_ERROR_LOG, "error_log", "Error log file", NULL, set_elog},
+ {OPT_MIME_TYPES, "mime_types", "Additional mime types list", NULL,NULL},
+ {OPT_ALIASES, "aliases", "Path=URI mappings", NULL, NULL},
+ {OPT_ACL, "acl", "\tAllow/deny IP addresses/subnets", NULL, set_acl},
+#if !defined(NO_THREADS)
+ {OPT_THREADS, "threads", "Number of worker threads", "1", set_workers},
+#endif /* !NO_THREADS */
+ {-1, NULL, NULL, NULL, NULL}
+};
+
+static const struct opt *
+find_opt(const char *opt_name)
+{
+ int i;
+
+ for (i = 0; known_options[i].name != NULL; i++)
+ if (!strcmp(opt_name, known_options[i].name))
+ return (known_options + i);
+
+ _shttpd_elog(E_FATAL, NULL, "no such option: [%s]", opt_name);
+
+ /* UNREACHABLE */
+ return (NULL);
+}
+
+int
+shttpd_set_option(struct shttpd_ctx *ctx, const char *opt, const char *val)
+{
+ const struct opt *o = find_opt(opt);
+ int retval = TRUE;
+
+ /* Call option setter first, so it can use both new and old values */
+ if (o->setter != NULL)
+ retval = o->setter(ctx, val);
+
+ /* Free old value if any */
+ if (ctx->options[o->index] != NULL)
+ free(ctx->options[o->index]);
+
+ /* Set new option value */
+ ctx->options[o->index] = val ? _shttpd_strdup(val) : NULL;
+
+ return (retval);
+}
+
+static void
+show_cfg_page(struct shttpd_arg *arg)
+{
+ struct shttpd_ctx *ctx = arg->user_data;
+ char opt_name[20], value[BUFSIZ];
+ const struct opt *o;
+
+ opt_name[0] = value[0] = '\0';
+
+ if (!strcmp(shttpd_get_env(arg, "REQUEST_METHOD"), "POST")) {
+ if (arg->flags & SHTTPD_MORE_POST_DATA)
+ return;
+ (void) shttpd_get_var("o", arg->in.buf, arg->in.len,
+ opt_name, sizeof(opt_name));
+ (void) shttpd_get_var("v", arg->in.buf, arg->in.len,
+ value, sizeof(value));
+ shttpd_set_option(ctx, opt_name, value[0] ? value : NULL);
+ }
+
+ shttpd_printf(arg, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"
+ "<html><body><h1>SHTTPD v. %s</h1>", shttpd_version());
+
+ shttpd_printf(arg, "%s", "name != NULL; o++) {
+ shttpd_printf(arg,
+ "<form method=post><tr><td>%s</td><td>%s</td>"
+ "<input type=hidden name=o value='%s'>"
+ "<td><input type=text name=v value='%s'></td>"
+ "<td><input type=submit value=save></td></form></tr>",
+ o->name, o->description, o->name,
+ ctx->options[o->index] ? ctx->options[o->index] : "");
+ }
+
+ shttpd_printf(arg, "%s", "</table></body></html>");
+ arg->flags |= SHTTPD_END_OF_OUTPUT;
+}
+
+/*
+ * Show usage string and exit.
+ */
+void
+_shttpd_usage(const char *prog)
+{
+ const struct opt *o;
+
+ (void) fprintf(stderr,
+ "SHTTPD version %s (c) Sergey Lyubka\n"
+ "usage: %s [options] [config_file]\n", VERSION, prog);
+
+#if !defined(NO_AUTH)
+ fprintf(stderr, " -A <realm> <user> <passwd>\n");
+#endif /* NO_AUTH */
+
+ for (o = known_options; o->name != NULL; o++) {
+ (void) fprintf(stderr, " -%s\t%s", o->name, o->description);
+ if (o->default_value != NULL)
+ fprintf(stderr, " (default: %s)", o->default_value);
+ fputc('\n', stderr);
+ }
+
+ exit(EXIT_FAILURE);
+}
+
+static void
+set_opt(struct shttpd_ctx *ctx, const char *opt, const char *value)
+{
+ const struct opt *o;
+
+ o = find_opt(opt);
+ if (ctx->options[o->index] != NULL)
+ free(ctx->options[o->index]);
+ ctx->options[o->index] = _shttpd_strdup(value);
+}
+
+static void
+process_command_line_arguments(struct shttpd_ctx *ctx, char *argv[])
+{
+ const char *config_file = CONFIG_FILE;
+ char line[BUFSIZ], opt[BUFSIZ],
+ val[BUFSIZ], path[FILENAME_MAX], *p;
+ FILE *fp;
+ size_t i, line_no = 0;
+
+ /* First find out, which config file to open */
+ for (i = 1; argv[i] != NULL && argv[i][0] == '-'; i += 2)
+ if (argv[i + 1] == NULL)
+ _shttpd_usage(argv[0]);
+
+ if (argv[i] != NULL && argv[i + 1] != NULL) {
+ /* More than one non-option arguments are given w*/
+ _shttpd_usage(argv[0]);
+ } else if (argv[i] != NULL) {
+ /* Just one non-option argument is given, this is config file */
+ config_file = argv[i];
+ } else {
+ /* No config file specified. Look for one where shttpd lives */
+ if ((p = strrchr(argv[0], DIRSEP)) != 0) {
+ _shttpd_snprintf(path, sizeof(path), "%.*s%s",
+ p - argv[0] + 1, argv[0], config_file);
+ config_file = path;
+ }
+ }
+
+ fp = fopen(config_file, "r");
+
+ /* If config file was set in command line and open failed, exit */
+ if (fp == NULL && argv[i] != NULL)
+ _shttpd_elog(E_FATAL, NULL, "cannot open config file %s: %s",
+ config_file, strerror(errno));
+
+ if (fp != NULL) {
+
+ _shttpd_elog(E_LOG, NULL, "Loading config file %s", config_file);
+
+ /* Loop over the lines in config file */
+ while (fgets(line, sizeof(line), fp) != NULL) {
+
+ line_no++;
+
+ /* Ignore empty lines and comments */
+ if (line[0] == '#' || line[0] == '\n')
+ continue;
+
+ if (sscanf(line, "%s %[^\n#]", opt, val) != 2)
+ _shttpd_elog(E_FATAL, NULL, "line %d in %s is invalid",
+ line_no, config_file);
+
+ set_opt(ctx, opt, val);
+ }
+
+ (void) fclose(fp);
+ }
+
+ /* Now pass through the command line options */
+ for (i = 1; argv[i] != NULL && argv[i][0] == '-'; i += 2)
+ set_opt(ctx, &argv[i][1], argv[i + 1]);
+}
+
+struct shttpd_ctx *
+shttpd_init(int argc, char *argv[])
+{
+ struct shttpd_ctx *ctx;
+ struct tm *tm;
+ const struct opt *o;
+
+ if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
+ _shttpd_elog(E_FATAL, NULL, "cannot allocate shttpd context");
+
+ LL_INIT(&ctx->registered_uris);
+ LL_INIT(&ctx->error_handlers);
+ LL_INIT(&ctx->acl);
+ LL_INIT(&ctx->ssi_funcs);
+ LL_INIT(&ctx->listeners);
+ LL_INIT(&ctx->workers);
+
+ /* Initialize options. First pass: set default option values */
+ for (o = known_options; o->name != NULL; o++)
+ ctx->options[o->index] = o->default_value ?
+ _shttpd_strdup(o->default_value) : NULL;
+
+ /* Second and third passes: config file and argv */
+ if (argc > 0 && argv != NULL)
+ process_command_line_arguments(ctx, argv);
+
+ /* Call setter functions */
+ for (o = known_options; o->name != NULL; o++)
+ if (o->setter && ctx->options[o->index] != NULL)
+ if (o->setter(ctx, ctx->options[o->index]) == FALSE) {
+ shttpd_fini(ctx);
+ return (NULL);
+ }
+
+ _shttpd_current_time = time(NULL);
+ tm = localtime(&_shttpd_current_time);
+ _shttpd_tz_offset = 0;
+
+ if (num_workers(ctx) == 1)
+ (void) add_worker(ctx);
+#if 0
+ tm->tm_gmtoff - 3600 * (tm->tm_isdst > 0 ? 1 : 0);
+#endif
+
+#ifdef _WIN32
+ {WSADATA data; WSAStartup(MAKEWORD(2,2), &data);}
+#endif /* _WIN32 */
+
+ return (ctx);
+}
Added: trunk/libzypp/vendor/shttpd/shttpd.h
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/shttpd.h?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/shttpd.h (added)
+++ trunk/libzypp/vendor/shttpd/shttpd.h Thu Oct 16 19:23:14 2008
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2004-2008 Sergey Lyubka
+ * 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.
+ *
+ * $Id: shttpd.h,v 1.18 2008/08/23 08:34:50 drozd Exp $
+ */
+
+#ifndef SHTTPD_HEADER_INCLUDED
+#define SHTTPD_HEADER_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+struct ubuf {
+ char *buf; /* Buffer pointer */
+ int len; /* Size of a buffer */
+ int num_bytes; /* Bytes processed by callback */
+};
+
+/*
+ * 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; /* Data from register_uri() */
+ struct ubuf in; /* Input is here, POST data */
+ struct ubuf out; /* Output goes here */
+
+ unsigned int flags;
+#define SHTTPD_END_OF_OUTPUT 1 /* No more data do send */
+#define SHTTPD_CONNECTION_ERROR 2 /* Server closed the connection */
+#define SHTTPD_MORE_POST_DATA 4 /* arg->in has incomplete data */
+#define SHTTPD_POST_BUFFER_FULL 8 /* arg->in has max data */
+#define SHTTPD_SSI_EVAL_TRUE 16 /* SSI eval callback must set it*/
+#define SHTTPD_SUSPEND 32 /* User wants to suspend output */
+};
+
+/*
+ * 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' buffer, not more than 'out.len' bytes,
+ * and record how many bytes are copied, into 'out.num_bytes'
+ * 2. It must not call any blocking functions
+ * 3. It must set SHTTPD_END_OF_OUTPUT flag when there is no more data to send
+ * 4. For POST requests, it must process the incoming data (in.buf) of length
+ * 'in.len', and set 'in.num_bytes', which is how many bytes of POST
+ * data was processed and can be discarded by SHTTPD.
+ * 5. If callback allocates arg->state, to keep state, it must deallocate it
+ * at the end of coonection SHTTPD_CONNECTION_ERROR or SHTTPD_END_OF_OUTPUT
+ * 6. If callback function wants to suspend until some event, it must store
+ * arg->priv pointer elsewhere, set SHTTPD_SUSPEND flag and return. When
+ * the event happens, user code should call shttpd_wakeup(priv).
+ * It is safe to call shttpd_wakeup() from any thread. User code must
+ * not call shttpd_wakeup once the connection is closed.
+ */
+typedef void (*shttpd_callback_t)(struct shttpd_arg *);
+
+/*
+ * shttpd_init Initialize shttpd context
+ * shttpd_fini Dealocate the context, close all connections
+ * shttpd_set_option Set new value for option
+ * shttpd_register_uri Setup the callback function for specified URL
+ * shttpd_poll Do connections processing
+ * shttpd_version return string with SHTTPD version
+ * shttpd_get_var Fetch POST/GET variable value by name. Return value len
+ * shttpd_get_header return value of the specified HTTP header
+ * shttpd_get_env return values for the following pseudo-variables:
+ "REQUEST_METHOD", "REQUEST_URI",
+ * "REMOTE_USER" and "REMOTE_ADDR"
+ * shttpd_printf helper function to output data
+ * shttpd_handle_error register custom HTTP error handler
+ * shttpd_wakeup clear SHTTPD_SUSPEND state for the connection
+ */
+
+struct shttpd_ctx;
+
+struct shttpd_ctx *shttpd_init(int argc, char *argv[]);
+int shttpd_set_option(struct shttpd_ctx *, const char *opt, const char *val);
+void shttpd_fini(struct shttpd_ctx *);
+void shttpd_register_uri(struct shttpd_ctx *ctx, const char *uri,
+ shttpd_callback_t callback, void *const user_data);
+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 *header_name);
+const char *shttpd_get_env(struct shttpd_arg *, const char *name);
+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 *const data);
+void shttpd_register_ssi_func(struct shttpd_ctx *ctx, const char *name,
+ shttpd_callback_t func, void *const user_data);
+void shttpd_wakeup(const void *priv);
+int shttpd_join(struct shttpd_ctx *, fd_set *, fd_set *, int *max_fd);
+int shttpd_socketpair(int sp[2]);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* SHTTPD_HEADER_INCLUDED */
Added: trunk/libzypp/vendor/shttpd/ssl.h
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/ssl.h?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/ssl.h (added)
+++ trunk/libzypp/vendor/shttpd/ssl.h Thu Oct 16 19:23:14 2008
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka
+ * 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))
Added: trunk/libzypp/vendor/shttpd/standalone.c
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/standalone.c?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/standalone.c (added)
+++ trunk/libzypp/vendor/shttpd/standalone.c Thu Oct 16 19:23:14 2008
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka
+ * 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 int exit_flag; /* Program termination 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;
+
+#if !defined(NO_AUTH)
+ if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'A') {
+ if (argc != 6)
+ _shttpd_usage(argv[0]);
+ exit(_shttpd_edit_passwords(argv[2],argv[3],argv[4],argv[5]));
+ }
+#endif /* NO_AUTH */
+
+ if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")))
+ _shttpd_usage(argv[0]);
+
+#if defined(_WIN32)
+ try_to_run_as_nt_service();
+#endif /* _WIN32 */
+
+#ifndef _WIN32
+ (void) signal(SIGCHLD, signal_handler);
+ (void) signal(SIGPIPE, SIG_IGN);
+#endif /* _WIN32 */
+
+ (void) signal(SIGTERM, signal_handler);
+ (void) signal(SIGINT, signal_handler);
+
+ if ((ctx = shttpd_init(argc, argv)) == NULL)
+ _shttpd_elog(E_FATAL, NULL, "%s",
+ "Cannot initialize SHTTPD context");
+
+ _shttpd_elog(E_LOG, NULL, "shttpd %s started on port(s) %s, serving %s",
+ VERSION, ctx->options[OPT_PORTS], ctx->options[OPT_ROOT]);
+
+ while (exit_flag == 0)
+ shttpd_poll(ctx, 10 * 1000);
+
+ _shttpd_elog(E_LOG, NULL, "Exit on signal %d", exit_flag);
+ shttpd_fini(ctx);
+
+ return (EXIT_SUCCESS);
+}
Added: trunk/libzypp/vendor/shttpd/std_includes.h
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/std_includes.h?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/std_includes.h (added)
+++ trunk/libzypp/vendor/shttpd/std_includes.h Thu Oct 16 19:23:14 2008
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka
+ * 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
+#include
+#include
+#include
+#include
+#include
+#endif /* _WIN32_WCE */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#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 */
Added: trunk/libzypp/vendor/shttpd/string.c
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/vendor/shttpd/string.c?rev=11382&view=auto
==============================================================================
--- trunk/libzypp/vendor/shttpd/string.c (added)
+++ trunk/libzypp/vendor/shttpd/string.c Thu Oct 16 19:23:14 2008
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka
+ * 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
+_shttpd_strlcpy(register char *dst, register const char *src, size_t n)
+{
+ for (; *src != '\0' && n > 1; n--)
+ *dst++ = *src++;
+ *dst = '\0';
+}
+
+int
+_shttpd_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);
+}
+
+char *
+_shttpd_strndup(const char *ptr, size_t len)
+{
+ char *p;
+
+ if ((p = malloc(len + 1)) != NULL)
+ _shttpd_strlcpy(p, ptr, len + 1);
+
+ return (p);
+
+}
+
+char *
+_shttpd_strdup(const char *str)
+{
+ return (_shttpd_strndup(str, strlen(str)));
+}
+
+/*
+ * 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
+_shttpd_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);
+}
+
+/*
+ * Verify that given file has certain extension
+ */
+int
+_shttpd_match_extension(const char *path, const char *ext_list)
+{
+ size_t len, path_len;
+
+ path_len = strlen(path);
+
+ FOR_EACH_WORD_IN_LIST(ext_list, len)
+ if (len < path_len && path[path_len - len - 1] == '.' &&
+ !_shttpd_strncasecmp(path + path_len - len, ext_list, len))
+ return (TRUE);
+
+ return (FALSE);
+}
--
To unsubscribe, e-mail: zypp-commit+unsubscribe@opensuse.org
For additional commands, e-mail: zypp-commit+help@opensuse.org
|