From 7d57f6f0656a4abbfd8ad89133804e7b120ae25c Mon Sep 17 00:00:00 2001 From: Lammert Bies Date: Sun, 19 May 2019 19:40:42 +0200 Subject: [PATCH] Modified or removed unmaintained parts of the source --- Makefile | 18 - doc/Building.md | 34 +- doc/Embedding.md | 90 +- examples/embedded_cpp/Makefile | 36 - examples/embedded_cpp/embedded_cpp.cpp | 297 ---- include/LibHTTPServer.h | 588 ------- src/main.c | 2059 ------------------------ 7 files changed, 2 insertions(+), 3120 deletions(-) delete mode 100644 examples/embedded_cpp/Makefile delete mode 100644 examples/embedded_cpp/embedded_cpp.cpp delete mode 100644 include/LibHTTPServer.h delete mode 100644 src/main.c diff --git a/Makefile b/Makefile index 79121996..e432fa3e 100644 --- a/Makefile +++ b/Makefile @@ -152,16 +152,10 @@ ${TSTDIR}${OBJDIR}%${OBJEXT} : ${TSTDIR}%.c all: ${LIBDIR}libhttp${LIBEXT} testmime${EXEEXT} -# -# Temporarily removed from all: rule -# libhttpserver${EXEEXT} -# - clean: ${RM} ${OBJDIR}*${OBJEXT} ${RM} ${LIBDIR}libhttp${LIBEXT} ${RM} testmime${EXEEXT} - ${RM} libhttpserver${EXEEXT} testmime${EXEEXT} : \ ${TSTDIR}${OBJDIR}testmime${OBJEXT} \ @@ -173,18 +167,6 @@ testmime${EXEEXT} : \ ${LIBS} ${STRIP} testmime${EXEEXT} - -libhttpserver${EXEEXT} : \ - ${OBJDIR}main${OBJEXT} \ - ${LIBDIR}libhttp${LIBEXT} \ - Makefile - ${LINK} ${XFLAG}libhttpserver${EXEEXT} \ - ${OBJDIR}main${OBJEXT} \ - ${LIBDIR}libhttp${LIBEXT} \ - ${LIBS} - ${STRIP} libhttpserver${EXEEXT} - - OBJLIST = \ ${OBJDIR}extern_md5${OBJEXT} \ ${OBJDIR}extern_sha1${OBJEXT} \ diff --git a/doc/Building.md b/doc/Building.md index 6ed26194..8ed81c03 100644 --- a/doc/Building.md +++ b/doc/Building.md @@ -55,13 +55,12 @@ Clean up files generated during the build Make options can be set on the command line with the make command like so. ``` -make build WITH_LUA=1 +make build WITH_IPV6=1 ``` | Make Options | Description | | ------------------------- | ---------------------------------------- | -| WITH_LUA=1 | build with Lua support | | WITH_DEBUG=1 | build with GDB debug support | | WITH_IPV6=1 | with IPV6 support | | WITH_WEBSOCKET=1 | build with web socket support | @@ -119,34 +118,3 @@ one additional *package* rule. ``` make -f Makefile.osx package ``` - -Building on Android ---------- - -This is a small guide to help you run LibHTTP on Android. Currently it is -tested on the HTC Wildfire. If you have managed to run it on other devices -as well, please comment or drop an email in the mailing list. -Note: You do not need root access to run LibHTTP on Android. - -- Download the source from the Downloads page. -- Download the Android NDK from [http://developer.android.com/tools/sdk/ndk/index.html](http://developer.android.com/tools/sdk/ndk/index.html) -- Run `/path-to-ndk/ndk-build -C /path-to-libhttp/resources` - That should generate libhttp/lib/armeabi/libhttp -- Using the adb tool (you need to have Android SDK installed for that), - push the generated libhttp binary to `/data/local` folder on device. -- From adb shell, navigate to `/data/local` and execute `./libhttp`. -- To test if the server is running fine, visit your web-browser and - navigate to `http://127.0.0.1:8080` You should see the `Index of /` page. - -![screenshot](https://a248.e.akamai.net/camo.github.com/b88428bf009a2b6141000937ab684e04cc8586af/687474703a2f2f692e696d6775722e636f6d2f62676f6b702e706e67) - - -Notes: - -- `jni` stands for Java Native Interface. Read up on Android NDK if you want - to know how to interact with the native C functions of libhttp in Android - Java applications. -- TODO: A Java application that interacts with the native binary or a - shared library. - - diff --git a/doc/Embedding.md b/doc/Embedding.md index be61e19e..8899d75e 100644 --- a/doc/Embedding.md +++ b/doc/Embedding.md @@ -3,7 +3,7 @@ Embedding LibHTTP LibHTTP is primarily designed so applications can easily add HTTP and HTTPS server as well as WebSocket functionality. For example, an application server could use LibHTTP to enable a web service interface for automation or remote control. -However, it can also be used as a stand-alone executable. It can deliver static files and offers built-in server side Lua, JavaScript and CGI support. Some instructions how to build the stand-alone server can be found in [Building.md](Building.md). +It can deliver static files and offers built-in server side Lua, JavaScript and CGI support. Some instructions how to build the stand-alone server can be found in [Building.md](Building.md). Files ------ @@ -25,28 +25,6 @@ but all functions required to run a HTTP server. - src/libhttp.c - src/md5.inl (MD5 calculation) - src/handle_form.inl (HTML form handling functions) - - Optional: C++ wrapper - - include/LibHTTPServer.h (C++ interface) - - src/LibHTTPServer.cpp (C++ wrapper implementation) - - Optional: Third party components - - src/third_party/* (third party components, mainly used for the standalone server) - - src/mod_*.inl (modules to access third party components from LibHTTP) - -Note: The C++ wrapper uses the official C interface (libhttp.h) and does not add new features to the server. Some features available in the C interface might be missing in the C++ interface. - -#### Additional Source Files for Executables - -These files can be used to build a server executable. They contain a `main` function -starting the HTTP server. - - - Stand-alone C Server - - src/main.c - - Reference embedded C Server - - examples/embedded_c/embedded_c.c - - Reference embedded C++ Server - - examples/embedded_cpp/embedded_cpp.cpp - -Note: The "embedded" example is actively maintained, updated, extended and tested. Other examples in the examples/ folder might be outdated and remain there for reference. Quick Start ------ @@ -61,72 +39,6 @@ By default, the server will automatically serve up files like a normal HTTP serv - Use `httplib_set_request_handler()` to easily add your own request handlers. - Use `httplib_stop()` to stop the server. -### C++ - - Note that LibHTTP is Clean C, and C++ interface ```LibHTTPServer.h``` is only a wrapper layer around the C interface. - Not all LibHTTP features available in C are also available in C++. - - Create LibHTTPHandlers for each URI. - - Register the handlers with `LibHTTPServer::addHandler()` - - `LibHTTPServer` starts on contruction and stops on destruction. - - Use contructor *options* to select the port and document root among other things. - - Use constructor *callbacks* to add your own hooks. - -Lua Support ------- - -Lua is a server side include functionality. Files ending in .lua will be processed with Lua. - -##### Add the following CFLAGS - - - -DLUA_COMPAT_ALL - - -DUSE_LUA - - -DUSE_LUA_SQLITE3 - - -DUSE_LUA_FILE_SYSTEM - -##### Add the following sources - - - src/mod_lua.inl - - src/third_party/lua-5.2.4/src - + lapi.c - + lauxlib.c - + lbaselib.c - + lbitlib.c - + lcode.c - + lcorolib.c - + lctype.c - + ldblib.c - + ldebug.c - + ldo.c - + ldump.c - + lfunc.c - + lgc.c - + linit.c - + liolib.c - + llex.c - + lmathlib.c - + lmem.c - + loadlib.c - + lobject.c - + lopcodes.c - + loslib.c - + lparser.c - + lstate.c - + lstring.c - + lstrlib.c - + ltable.c - + ltablib.c - + ltm.c - + lundump.c - + lvm.c - + lzio.c - - src/third_party/sqlite3.c - - src/third_party/sqlite3.h - - src/third_party/lsqlite3.c - - src/third_party/lfs.c - - src/third_party/lfs.h - -This build is valid for Lua version Lua 5.2. It is also possible to build with Lua 5.1 (including LuaJIT) or Lua 5.3. - - JavaScript Support ------ diff --git a/examples/embedded_cpp/Makefile b/examples/embedded_cpp/Makefile deleted file mode 100644 index 65adf98b..00000000 --- a/examples/embedded_cpp/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright (c) 2013 No Face Press, LLC -# License http://opensource.org/licenses/mit-license.php MIT License -# - -#This makefile is used to test the other Makefiles - - -PROG = embedded_cpp -SRC = embedded_cpp.cpp - -TOP = ../.. -CIVETWEB_LIB = libcivetweb.a - -CFLAGS = -I$(TOP)/include $(COPT) -LIBS = -lpthread - -include $(TOP)/resources/Makefile.in-os - -ifeq ($(TARGET_OS),LINUX) - LIBS += -ldl -endif - -all: $(PROG) - -$(PROG): $(CIVETWEB_LIB) $(SRC) - $(CXX) -o $@ $(CFLAGS) $(LDFLAGS) $(SRC) $(CIVETWEB_LIB) $(LIBS) - -$(CIVETWEB_LIB): - $(MAKE) -C $(TOP) clean lib WITH_CPP=1 - cp $(TOP)/$(CIVETWEB_LIB) . - -clean: - rm -f $(CIVETWEB_LIB) $(PROG) - -.PHONY: all clean diff --git a/examples/embedded_cpp/embedded_cpp.cpp b/examples/embedded_cpp/embedded_cpp.cpp deleted file mode 100644 index 03e48c1e..00000000 --- a/examples/embedded_cpp/embedded_cpp.cpp +++ /dev/null @@ -1,297 +0,0 @@ -/* Copyright (c) 2013-2014 the Civetweb developers - * Copyright (c) 2013 No Face Press, LLC - * License http://opensource.org/licenses/mit-license.php MIT License - */ - -// Simple example program on how to use Embedded C++ interface. - -#include "CivetServer.h" - -#ifdef _WIN32 -#include -#else -#include -#endif - -#define DOCUMENT_ROOT "." -#define PORT "8081" -#define EXAMPLE_URI "/example" -#define EXIT_URI "/exit" -bool exitNow = false; - -class ExampleHandler : public CivetHandler -{ - public: - bool - handleGet(CivetServer *server, struct httplib_connection *conn) - { - httplib_printf(conn, - "HTTP/1.1 200 OK\r\nContent-Type: " - "text/html\r\nConnection: close\r\n\r\n"); - httplib_printf(conn, "\r\n"); - httplib_printf(conn, - "

This is an example text from a C++ handler

\r\n"); - httplib_printf(conn, - "

To see a page from the A handler click here

\r\n"); - httplib_printf(conn, - "

To see a page from the A handler with a parameter " - "click here

\r\n"); - httplib_printf(conn, - "

To see a page from the A/B handler click here

\r\n"); - httplib_printf(conn, - "

To see a page from the *.foo handler click here

\r\n"); - httplib_printf(conn, - "

To exit click here

\r\n", - EXIT_URI); - httplib_printf(conn, "\r\n"); - return true; - } -}; - -class ExitHandler : public CivetHandler -{ - public: - bool - handleGet(CivetServer *server, struct httplib_connection *conn) - { - httplib_printf(conn, - "HTTP/1.1 200 OK\r\nContent-Type: " - "text/plain\r\nConnection: close\r\n\r\n"); - httplib_printf(conn, "Bye!\n"); - exitNow = true; - return true; - } -}; - -class AHandler : public CivetHandler -{ - private: - bool - handleAll(const char *method, - CivetServer *server, - struct httplib_connection *conn) - { - std::string s = ""; - httplib_printf(conn, - "HTTP/1.1 200 OK\r\nContent-Type: " - "text/html\r\nConnection: close\r\n\r\n"); - httplib_printf(conn, ""); - httplib_printf(conn, "

This is the A handler for \"%s\" !

", method); - if (CivetServer::getParam(conn, "param", s)) { - httplib_printf(conn, "

param set to %s

", s.c_str()); - } else { - httplib_printf(conn, "

param not set

"); - } - httplib_printf(conn, "\n"); - return true; - } - - public: - bool - handleGet(CivetServer *server, struct httplib_connection *conn) - { - return handleAll("GET", server, conn); - } - bool - handlePost(CivetServer *server, struct httplib_connection *conn) - { - return handleAll("POST", server, conn); - } -}; - -class ABHandler : public CivetHandler -{ - public: - bool - handleGet(CivetServer *server, struct httplib_connection *conn) - { - httplib_printf(conn, - "HTTP/1.1 200 OK\r\nContent-Type: " - "text/html\r\nConnection: close\r\n\r\n"); - httplib_printf(conn, ""); - httplib_printf(conn, "

This is the AB handler!!!

"); - httplib_printf(conn, "\n"); - return true; - } -}; - -class FooHandler : public CivetHandler -{ - public: - bool - handleGet(CivetServer *server, struct httplib_connection *conn) - { - /* Handler may access the request info using httplib_get_request_info */ - const struct httplib_request_info *req_info = httplib_get_request_info(conn); - - httplib_printf(conn, - "HTTP/1.1 200 OK\r\nContent-Type: " - "text/html\r\nConnection: close\r\n\r\n"); - - httplib_printf(conn, "\n"); - httplib_printf(conn, "

This is the Foo GET handler!!!

\n"); - httplib_printf(conn, - "

The request was:

%s %s HTTP/%s

\n", - req_info->request_method, - req_info->uri, - req_info->http_version); - httplib_printf(conn, "\n"); - - return true; - } - bool - handlePost(CivetServer *server, struct httplib_connection *conn) - { - /* Handler may access the request info using httplib_get_request_info */ - const struct httplib_request_info *req_info = httplib_get_request_info(conn); - int64_t rlen; - int64_t wlen; - int64_t nlen = 0; - int64_t tlen = req_info->content_length; - char buf[1024]; - - httplib_printf(conn, - "HTTP/1.1 200 OK\r\nContent-Type: " - "text/html\r\nConnection: close\r\n\r\n"); - - httplib_printf(conn, "\n"); - httplib_printf(conn, "

This is the Foo POST handler!!!

\n"); - httplib_printf(conn, - "

The request was:

%s %s HTTP/%s

\n", - req_info->request_method, - req_info->uri, - req_info->http_version); - httplib_printf(conn, "

Content Length: %li

\n", (long)tlen); - httplib_printf(conn, "
\n");
-
-		while (nlen < tlen) {
-			rlen = tlen - nlen;
-			if (rlen > sizeof(buf)) {
-				rlen = sizeof(buf);
-			}
-			rlen = httplib_read(conn, buf, (size_t)rlen);
-			if (rlen <= 0) break;
-			wlen = httplib_write(conn, buf, (size_t)rlen);
-			if (rlen != rlen) break;
-			nlen += wlen;
-		}
-
-		httplib_printf(conn, "\n
\n"); - httplib_printf(conn, "\n"); - - return true; - } - - #define fopen_recursive fopen - - bool - handlePut(CivetServer *server, struct httplib_connection *conn) - { - /* Handler may access the request info using httplib_get_request_info */ - const struct httplib_request_info *req_info = httplib_get_request_info(conn); - int64_t rlen; - int64_t wlen; - int64_t nlen = 0; - int64_t tlen = req_info->content_length; - FILE * f; - char buf[1024]; - int fail = 0; - -#ifdef _WIN32 - _snprintf(buf, sizeof(buf), "D:\\somewhere\\%s\\%s", req_info->remote_user, req_info->local_uri); - buf[sizeof(buf)-1] = 0; /* TODO: check overflow */ - f = fopen_recursive(buf, "wb"); -#else - snprintf(buf, sizeof(buf), "~/somewhere/%s/%s", req_info->remote_user, req_info->local_uri); - buf[sizeof(buf)-1] = 0; /* TODO: check overflow */ - f = fopen_recursive(buf, "w"); -#endif - - if (!f) { - fail = 1; - } else { - while (nlen < tlen) { - rlen = tlen - nlen; - if (rlen > sizeof(buf)) { - rlen = sizeof(buf); - } - rlen = httplib_read(conn, buf, (size_t)rlen); - if (rlen <= 0) { - fail = 1; - break; - } - wlen = fwrite(buf, 1, (size_t)rlen, f); - if (rlen != rlen) { - fail = 1; - break; - } - nlen += wlen; - } - fclose(f); - } - - if (fail) { - httplib_printf(conn, - "HTTP/1.1 409 Conflict\r\n" - "Content-Type: text/plain\r\n" - "Connection: close\r\n\r\n"); - } else { - httplib_printf(conn, - "HTTP/1.1 201 Created\r\n" - "Content-Type: text/plain\r\n" - "Connection: close\r\n\r\n"); - } - - return true; - } -}; - - -int -main(int argc, char *argv[]) -{ - const char *options[] = { - "document_root", DOCUMENT_ROOT, "listening_ports", PORT, 0}; - - std::vector cpp_options; - for (int i=0; i<(sizeof(options)/sizeof(options[0])-1); i++) { - cpp_options.push_back(options[i]); - } - - // CivetServer server(options); // <-- C style start - CivetServer server(cpp_options); // <-- C++ style start - - ExampleHandler h_ex; - server.addHandler(EXAMPLE_URI, h_ex); - - ExitHandler h_exit; - server.addHandler(EXIT_URI, h_exit); - - AHandler h_a; - server.addHandler("/a", h_a); - - ABHandler h_ab; - server.addHandler("/a/b", h_ab); - - FooHandler h_foo; - server.addHandler("", h_foo); - - printf("Browse files at http://localhost:%s/\n", PORT); - printf("Run example at http://localhost:%s%s\n", PORT, EXAMPLE_URI); - printf("Exit at http://localhost:%s%s\n", PORT, EXIT_URI); - - while (!exitNow) { -#ifdef _WIN32 - Sleep(1000); -#else - sleep(1); -#endif - } - - printf("Bye!\n"); - - return 0; -} diff --git a/include/LibHTTPServer.h b/include/LibHTTPServer.h deleted file mode 100644 index 6fcc66a2..00000000 --- a/include/LibHTTPServer.h +++ /dev/null @@ -1,588 +0,0 @@ -/* - * Copyright (c) 2016 Lammert Bies - * Copyright (c) 2013-2014 the Civetweb developers - * Copyright (c) 2013 No Face Press, LLC - * - * License http://opensource.org/licenses/mit-license.php MIT License - */ - -#ifndef _CIVETWEB_SERVER_H_ -#define _CIVETWEB_SERVER_H_ -#ifdef __cplusplus - -#include "libhttp.h" -#include -#include -#include -#include - -// forward declaration -class LibHTTPServer; - -/** - * Exception class for thrown exceptions within the LibHTTPHandler object. - */ -class CIVETWEB_API LibHTTPException : public std::runtime_error -{ - public: - LibHTTPException(const std::string &msg) : std::runtime_error(msg) - { - } -}; - -/** - * Basic interface for a URI request handler. Handlers implementations - * must be reentrant. - */ -class CIVETWEB_API LibHTTPHandler -{ - public: - /** - * Destructor - */ - virtual ~LibHTTPHandler() - { - } - - /** - * Callback method for GET request. - * - * @param server - the calling server - * @param conn - the connection information - * @returns true if implemented, false otherwise - */ - virtual bool handleGet(LibHTTPServer *server, struct httplib_connection *conn); - - /** - * Callback method for POST request. - * - * @param server - the calling server - * @param conn - the connection information - * @returns true if implemented, false otherwise - */ - virtual bool handlePost(LibHTTPServer *server, struct httplib_connection *conn); - - /** - * Callback method for HEAD request. - * - * @param server - the calling server - * @param conn - the connection information - * @returns true if implemented, false otherwise - */ - virtual bool handleHead(LibHTTPServer *server, struct httplib_connection *conn); - - /** - * Callback method for PUT request. - * - * @param server - the calling server - * @param conn - the connection information - * @returns true if implemented, false otherwise - */ - virtual bool handlePut(LibHTTPServer *server, struct httplib_connection *conn); - - /** - * Callback method for DELETE request. - * - * @param server - the calling server - * @param conn - the connection information - * @returns true if implemented, false otherwise - */ - virtual bool handleDelete(LibHTTPServer *server, struct httplib_connection *conn); - - /** - * Callback method for OPTIONS request. - * - * @param server - the calling server - * @param conn - the connection information - * @returns true if implemented, false otherwise - */ - virtual bool handleOptions(LibHTTPServer *server, struct httplib_connection *conn); - - /** - * Callback method for PATCH request. - * - * @param server - the calling server - * @param conn - the connection information - * @returns true if implemented, false otherwise - */ - virtual bool handlePatch(LibHTTPServer *server, struct httplib_connection *conn); -}; - -/** - * Basic interface for a URI authorization handler. Handler implementations - * must be reentrant. - */ -class CIVETWEB_API LibHTTPAuthHandler -{ - public: - /** - * Destructor - */ - virtual ~LibHTTPAuthHandler() - { - } - - /** - * Callback method for authorization requests. It is up the this handler - * to generate 401 responses if authorization fails. - * - * @param server - the calling server - * @param conn - the connection information - * @returns true if authorization succeeded, false otherwise - */ - virtual bool authorize(LibHTTPServer *server, struct httplib_connection *conn) = 0; -}; - -/** - * Basic interface for a websocket handler. Handlers implementations - * must be reentrant. - */ -class CIVETWEB_API LibHTTPWebSocketHandler -{ - public: - /** - * Destructor - */ - virtual ~LibHTTPWebSocketHandler() - { - } - - /** - * Callback method for when the client intends to establish a websocket - *connection, before websocket handshake. - * - * @param server - the calling server - * @param conn - the connection information - * @returns true to keep socket open, false to close it - */ - virtual bool handleConnection(LibHTTPServer *server, const struct httplib_connection *conn); - - /** - * Callback method for when websocket handshake is successfully completed, - *and connection is ready for data exchange. - * - * @param server - the calling server - * @param conn - the connection information - */ - virtual void handleReadyState(LibHTTPServer *server, struct httplib_connection *conn); - - /** - * Callback method for when a data frame has been received from the client. - * - * @param server - the calling server - * @param conn - the connection information - * @bits: first byte of the websocket frame, see websocket RFC at - *http://tools.ietf.org/html/rfc6455, section 5.2 - * @data, data_len: payload, with mask (if any) already applied. - * @returns true to keep socket open, false to close it - */ - virtual bool handleData(LibHTTPServer *server, struct httplib_connection *conn, int bits, char *data, size_t data_len); - - /** - * Callback method for when the connection is closed. - * - * @param server - the calling server - * @param conn - the connection information - */ - virtual void handleClose(LibHTTPServer *server, const struct httplib_connection *conn); -}; - -/** - * LibHTTPCallbacks - * - * wrapper for httplib_callbacks - */ -struct CIVETWEB_API LibHTTPCallbacks : public httplib_callbacks { - LiBHTTPCallbacks(); -}; - -/** - * LibHTTPServer - * - * Basic class for embedded web server. This has an URL mapping built-in. - */ -class CIVETWEB_API LibHTTPServer -{ - public: - /** - * Constructor - * - * This automatically starts the sever. - * It is good practice to call getContext() after this in case there - * were errors starting the server. - * - * Note: LibHTTPServer should not be used as a static instance in a Windows - * DLL, since the constructor creates threads and the destructor joins - * them again (creating/joining threads should not be done in static - * constructors). - * - * @param options - the web server options. - * @param callbacks - optional web server callback methods. - * - * @throws LibHTTPException - */ - LibHTTPServer(const char **options, - const struct LibHTTPCallbacks *callbacks = 0); - LibHTTPServer(std::vector options, - const struct LibHTTPCallbacks *callbacks = 0); - - /** - * Destructor - */ - virtual ~LibHTTPServer(); - - /** - * close() - * - * Stops server and frees resources. - */ - void close(); - - /** - * getContext() - * - * @return the context or 0 if not running. - */ - const struct httplib_context * - getContext() const - { - return context; - } - - /** - * addHandler(const std::string &, LibHTTPHandler *) - * - * Adds a URI handler. If there is existing URI handler, it will - * be replaced with this one. - * - * URI's are ordered and prefix (REST) URI's are supported. - * - * @param uri - URI to match. - * @param handler - handler instance to use. - */ - void addHandler(const std::string &uri, LibHTTPHandler *handler); - - void - addHandler(const std::string &uri, LibHTTPHandler &handler) - { - addHandler(uri, &handler); - } - - /** - * addWebSocketHandler - * - * Adds a WebSocket handler for a specific URI. If there is existing URI - *handler, it will - * be replaced with this one. - * - * URI's are ordered and prefix (REST) URI's are supported. - * - * @param uri - URI to match. - * @param handler - handler instance to use. - */ - void addWebSocketHandler(const std::string &uri, - LibHTTPWebSocketHandler *handler); - - void - addWebSocketHandler(const std::string &uri, LibHTTPWebSocketHandler &handler) - { - addWebSocketHandler(uri, &handler); - } - - /** - * removeHandler(const std::string &) - * - * Removes a handler. - * - * @param uri - the exact URL used in addHandler(). - */ - void removeHandler(const std::string &uri); - - /** - * removeWebSocketHandler(const std::string &) - * - * Removes a web socket handler. - * - * @param uri - the exact URL used in addWebSocketHandler(). - */ - void removeWebSocketHandler(const std::string &uri); - - /** - * addAuthHandler(const std::string &, LibHTTPAuthHandler *) - * - * Adds a URI authorization handler. If there is existing URI authorization - * handler, it will be replaced with this one. - * - * URI's are ordered and prefix (REST) URI's are supported. - * - * @param uri - URI to match. - * @param handler - authorization handler instance to use. - */ - void addAuthHandler(const std::string &uri, LibHTTPAuthHandler *handler); - - void - addAuthHandler(const std::string &uri, LibHTTPAuthHandler &handler) - { - addAuthHandler(uri, &handler); - } - - /** - * removeAuthHandler(const std::string &) - * - * Removes an authorization handler. - * - * @param uri - the exact URL used in addAuthHandler(). - */ - void removeAuthHandler(const std::string &uri); - - /** - * getListeningPorts() - * - * Returns a list of ports that are listening - * - * @return A vector of ports - */ - - std::vector getListeningPorts(); - - /** - * getCookie(struct httplib_connection *conn, const std::string &cookieName, - *std::string &cookieValue) - * - * Puts the cookie value string that matches the cookie name in the - *cookieValue destinaton string. - * - * @param conn - the connection information - * @param cookieName - cookie name to get the value from - * @param cookieValue - cookie value is returned using thiis reference - * @returns the size of the cookie value string read. - */ - static int getCookie(struct httplib_connection *conn, - const std::string &cookieName, - std::string &cookieValue); - - /** - * getHeader(struct httplib_connection *conn, const std::string &headerName) - * @param conn - the connection information - * @param headerName - header name to get the value from - * @returns a char array whcih contains the header value as string - */ - static const char *getHeader(struct httplib_connection *conn, const std::string &headerName); - - /** - * getParam(struct httplib_connection *conn, const char *, std::string &, size_t) - * - * Returns a query paramter contained in the supplied buffer. The - * occurance value is a zero-based index of a particular key name. This - * should not be confused with the index over all of the keys. Note that - *this - * function assumes that parameters are sent as text in http query string - * format, which is the default for web forms. This function will work for - * html forms with method="GET" and method="POST" attributes. In other - *cases, - * you may use a getParam version that directly takes the data instead of - *the - * connection as a first argument. - * - * @param conn - parameters are read from the data sent through this - *connection - * @param name - the key to search for - * @param dst - the destination string - * @param occurrence - the occurrence of the selected name in the query (0 - *based). - * @return true if key was found - */ - static bool getParam(struct httplib_connection *conn, const char *name, std::string &dst, size_t occurrence = 0); - - /** - * getParam(const std::string &, const char *, std::string &, size_t) - * - * Returns a query paramter contained in the supplied buffer. The - * occurance value is a zero-based index of a particular key name. This - * should not be confused with the index over all of the keys. - * - * @param data - the query string (text) - * @param name - the key to search for - * @param dst - the destination string - * @param occurrence - the occurrence of the selected name in the query (0 - *based). - * @return true if key was found - */ - static bool - getParam(const std::string &data, - const char *name, - std::string &dst, - size_t occurrence = 0) - { - return getParam(data.c_str(), data.length(), name, dst, occurrence); - } - - /** - * getParam(const char *, size_t, const char *, std::string &, size_t) - * - * Returns a query paramter contained in the supplied buffer. The - * occurance value is a zero-based index of a particular key name. This - * should not be confused with the index over all of the keys. - * - * @param data the - query string (text) - * @param data_len - length of the query string - * @param name - the key to search for - * @param dst - the destination string - * @param occurrence - the occurrence of the selected name in the query (0 - *based). - * @return true if key was found - */ - static bool getParam(const char *data, - size_t data_len, - const char *name, - std::string &dst, - size_t occurrence = 0); - - /** - * urlDecode(const std::string &, std::string &, bool) - * - * @param src - string to be decoded - * @param dst - destination string - * @param is_form_url_encoded - true if form url encoded - * form-url-encoded data differs from URI encoding in a way that it - * uses '+' as character for space, see RFC 1866 section 8.2.1 - * http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt - */ - static void - urlDecode(const std::string &src, - std::string &dst, - bool is_form_url_encoded = true) - { - urlDecode(src.c_str(), src.length(), dst, is_form_url_encoded); - } - - /** - * urlDecode(const char *, size_t, std::string &, bool) - * - * @param src - buffer to be decoded - * @param src_len - length of buffer to be decoded - * @param dst - destination string - * @param is_form_url_encoded - true if form url encoded - * form-url-encoded data differs from URI encoding in a way that it - * uses '+' as character for space, see RFC 1866 section 8.2.1 - * http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt - */ - static void urlDecode(const char *src, - size_t src_len, - std::string &dst, - bool is_form_url_encoded = true); - - /** - * urlDecode(const char *, std::string &, bool) - * - * @param src - buffer to be decoded (0 terminated) - * @param dst - destination string - * @param is_form_url_encoded true - if form url encoded - * form-url-encoded data differs from URI encoding in a way that it - * uses '+' as character for space, see RFC 1866 section 8.2.1 - * http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt - */ - static void urlDecode(const char *src, - std::string &dst, - bool is_form_url_encoded = true); - - /** - * urlEncode(const std::string &, std::string &, bool) - * - * @param src - buffer to be encoded - * @param dst - destination string - * @param append - true if string should not be cleared before encoding. - */ - static void - urlEncode(const std::string &src, std::string &dst, bool append = false) - { - urlEncode(src.c_str(), src.length(), dst, append); - } - - /** - * urlEncode(const char *, size_t, std::string &, bool) - * - * @param src - buffer to be encoded (0 terminated) - * @param dst - destination string - * @param append - true if string should not be cleared before encoding. - */ - static void - urlEncode(const char *src, std::string &dst, bool append = false); - - /** - * urlEncode(const char *, size_t, std::string &, bool) - * - * @param src - buffer to be encoded - * @param src_len - length of buffer to be decoded - * @param dst - destination string - * @param append - true if string should not be cleared before encoding. - */ - static void urlEncode(const char *src, - size_t src_len, - std::string &dst, - bool append = false); - - protected: - class LibHTTPConnection - { - public: - char *postData; - unsigned long postDataLen; - - LibHTTPConnection(); - ~LibHTTPConnection(); - }; - - struct httplib_context *context; - std::map connections; - - private: - /** - * requestHandler(struct httplib_connection *, void *cbdata) - * - * Handles the incomming request. - * - * @param conn - the connection information - * @param cbdata - pointer to the LibHTTPHandler instance. - * @returns 0 if implemented, false otherwise - */ - static int requestHandler(struct httplib_connection *conn, void *cbdata); - - static int webSocketConnectionHandler(const struct httplib_connection *conn, - void *cbdata); - static void webSocketReadyHandler(struct httplib_connection *conn, void *cbdata); - static int webSocketDataHandler(struct httplib_connection *conn, - int bits, - char *data, - size_t data_len, - void *cbdata); - static void webSocketCloseHandler(const struct httplib_connection *conn, - void *cbdata); - /** - * authHandler(struct httplib_connection *, void *cbdata) - * - * Handles the authorization requests. - * - * @param conn - the connection information - * @param cbdata - pointer to the LibHTTPAuthHandler instance. - * @returns 1 if authorized, 0 otherwise - */ - static int authHandler(struct httplib_connection *conn, void *cbdata); - - /** - * closeHandler(struct httplib_connection *) - * - * Handles closing a request (internal handler) - * - * @param conn - the connection information - */ - static void closeHandler(const struct httplib_connection *conn); - - /** - * Stores the user provided close handler - */ - void (*userCloseHandler)(const struct httplib_connection *conn); -}; - -#endif /* __cplusplus */ -#endif /* _CIVETWEB_SERVER_H_ */ diff --git a/src/main.c b/src/main.c deleted file mode 100644 index 8fb3238d..00000000 --- a/src/main.c +++ /dev/null @@ -1,2059 +0,0 @@ -/* - * Copyright (c) 2016 Lammert Bies - * Copyright (c) 2013-2016 the Civetweb developers - * Copyright (c) 2004-2013 Sergey Lyubka - * - * 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. - * - * ============ - * Release: 1.8 - */ - -#if defined(_WIN32) - -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS /* Disable deprecation warning in VS2005 */ -#endif -#ifndef _CRT_SECURE_NO_DEPRECATE -#define _CRT_SECURE_NO_DEPRECATE -#endif - -#else - -#define _XOPEN_SOURCE 600 - -/* - * For PATH_MAX on linux - * - * This should also be sufficient for "realpath", according to - * http://man7.org/linux/man-pages/man3/realpath.3.html, but in - * reality it does not seem to work. - * - * In case this causes a problem, disable the warning: - * #pragma GCC diagnostic ignored "-Wimplicit-function-declaration" - * #pragma clang diagnostic ignored "-Wimplicit-function-declaration" - */ - -#endif - -#if defined(__cplusplus) && (__cplusplus >= 201103L) -#define NO_RETURN [[noreturn]] -#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) -#define NO_RETURN _Noreturn -#else -#define NO_RETURN -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "libhttp.h" - -#define printf DO_NOT_USE_THIS_FUNCTION__USE_fprintf /* Required for unit testing */ - -#if defined(_WIN32) /* WINDOWS / UNIX include block */ -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 /* for tdm-gcc so we can use getconsolewindow */ -#endif /* _WIN32_WINNT */ -#undef UNICODE -#include -#include -#include -#include - -#define getcwd(a, b) (_getcwd(a, b)) -#if !defined(__MINGW32__) -extern char *_getcwd(char *buf, size_t size); -#endif -static int guard = 0; /* test if any dialog is already open */ - -#ifndef PATH_MAX -#define PATH_MAX MAX_PATH -#endif /* PATH_MAX */ - -#ifndef S_ISDIR -#define S_ISDIR(x) ((x)&_S_IFDIR) -#endif /* S_ISDIR */ - -#define DIRSEP '\\' -#define snprintf _snprintf -#define vsnprintf _vsnprintf -#define sleep(x) (Sleep((x)*1000)) -#define WINCDECL __cdecl -#define abs_path(rel, abs, abs_size) (_fullpath((abs), (rel), (abs_size))) - -#else /* defined(_WIN32)- WINDOWS / UNIX include \ - block */ - -#include -#include -#include -#define DIRSEP '/' -#define WINCDECL -#define abs_path(rel, abs, abs_size) (realpath((rel), (abs))) - -#endif /* defined(_WIN32) - WINDOWS / UNIX include \ - block */ - -#ifndef PATH_MAX -#define PATH_MAX (1024) -#endif - -#ifndef ERROR_STRING_LEN -#define ERROR_STRING_LEN (256) -#endif - -#define MAX_OPTIONS (50) -#define MAX_CONF_FILE_LINE_SIZE (8 * 1024) - -struct tuser_data { - char *first_message; -}; - -struct httplib_option { - const char * name; - const char * value; -}; - -static int g_exit_flag = 0; /* Main loop should exit */ -static char g_server_base_name[40]; /* Set by init_server_name() */ -static const char *g_server_name; /* Set by init_server_name() */ -static const char *g_icon_name; /* Set by init_server_name() */ -static char g_config_file_name[PATH_MAX] = - ""; /* Set by process_command_line_arguments() */ -static struct lh_ctx_t *g_ctx; /* Set by start_libhttp() */ -static struct tuser_data - g_user_data; /* Passed to httplib_start() by start_libhttp() */ - -#if !defined(CONFIG_FILE) -#define CONFIG_FILE "libhttp.conf" -#endif /* !CONFIG_FILE */ - -#if !defined(PASSWORDS_FILE_NAME) -#define PASSWORDS_FILE_NAME ".htpasswd" -#endif - -/* backup config file */ -#if !defined(CONFIG_FILE2) && defined(__linux__) -#define CONFIG_FILE2 "/usr/local/etc/libhttp.conf" -#endif - -enum { OPTION_TITLE, OPTION_ICON, NUM_MAIN_OPTIONS }; - -static struct httplib_option main_config_options[] = { - { "title", NULL }, - { "icon", NULL }, - { NULL, NULL } -}; - -static void WINCDECL signal_handler(int sig_num) { - - g_exit_flag = sig_num; -} - - -static NO_RETURN void die(const char *fmt, ...) { - - va_list ap; - char msg[200] = ""; - - va_start(ap, fmt); - vsnprintf(msg, sizeof(msg) - 1, fmt, ap); - msg[sizeof(msg) - 1] = 0; - va_end(ap); - -#if defined(_WIN32) - MessageBox(NULL, msg, "Error", MB_OK); -#else /* _WIN32 */ - fprintf(stderr, "%s\n", msg); -#endif /* _WIN32 */ - - exit(EXIT_FAILURE); -} - - -#ifdef WIN32 -static int MakeConsole(void); -#endif /* WIN32 */ - - -static void -show_server_name(void) -{ -#ifdef WIN32 - (void)MakeConsole(); -#endif /* WIN32 */ - - fprintf(stderr, "LibHTTP v%s, built on %s\n", httplib_version(), __DATE__); -} - - -static NO_RETURN void show_usage_and_exit( const char *exeName ) { - - if ( exeName == NULL || *exeName == '\0' ) exeName = "libhttp"; - - show_server_name(); - - fprintf(stderr, "\nUsage:\n"); - fprintf(stderr, " Start server with a set of options:\n"); - fprintf(stderr, " %s [config_file]\n", exeName); - fprintf(stderr, " %s [-option value ...]\n", exeName); - fprintf(stderr, " Show system information:\n"); - fprintf(stderr, " %s -I\n", exeName); - fprintf(stderr, " Add user/change password:\n"); - fprintf(stderr, - " %s -A \n", - exeName); - fprintf(stderr, " Remove user:\n"); - fprintf(stderr, " %s -R \n", exeName); - fprintf(stderr, "\nOPTIONS:\n"); - - exit(EXIT_FAILURE); -} - - -#if defined(_WIN32) || defined(USE_COCOA) /* GUI */ -static const char *config_file_top_comment = - "# LibHTTP web server configuration file.\n" - "# For detailed description of every option, visit\n" - "# https://github.com/lammertb/libhttp/blob/master/doc/UserManual.md\n" - "# Lines starting with '#' and empty lines are ignored.\n" - "# To make a change, remove leading '#', modify option's value,\n" - "# save this file and then restart LibHTTP.\n\n"; - -static const char * get_url_to_first_open_port(const struct lh_ctx_t *ctx) { - - static char url[100]; - char ports_str[256]; - const char *open_ports = httplib_get_option( ctx, "listening_ports", ports_str, 256 ); - int a; - int b; - int c; - int d; - int port; - int n; - - if (sscanf(open_ports, "%d.%d.%d.%d:%d%n", &a, &b, &c, &d, &port, &n) == 5) { - snprintf(url, sizeof(url), "%s://%d.%d.%d.%d:%d", open_ports[n] == 's' ? "https" : "http", a, b, c, d, port); - } else if (sscanf(open_ports, "%d%n", &port, &n) == 1) { - snprintf(url, sizeof(url), "%s://localhost:%d", open_ports[n] == 's' ? "https" : "http", port); - } else { - snprintf(url, sizeof(url), "%s", "http://localhost:8080"); - } - - return url; -} - - -#ifdef ENABLE_CREATE_CONFIG_FILE -static void create_config_file(const struct lh_ctx_t *ctx, const char *path) { - - const struct httplib_option *options; - const char *value; - FILE *fp; - int i; - - /* Create config file if it is not present yet */ - if ((fp = fopen(path, "r")) != NULL) { - fclose(fp); - } else if ((fp = fopen(path, "a+")) != NULL) { - fprintf(fp, "%s", config_file_top_comment); - options = httplib_get_valid_options(); - for (i = 0; options[i].name != NULL; i++) { - value = httplib_get_option(ctx, options[i].name); - fprintf( fp, "# %s %s\n", options[i].name, (value) ? value : "" ); - } - fclose( fp ); - } -} -#endif /* ENABLE_CREATE_CONFIG_FILE */ -#endif /* GUI */ - - -static char * sdup(const char *str) { - - size_t len; - char *p; - - len = strlen(str) + 1; - if ((p = (char *)malloc(len)) != NULL) { - memcpy(p, str, len); - } - return p; -} - - -static const char * get_option( struct httplib_option_t *options, const char *option_name ) { - - int i; - - i = 0; - - while ( options[i].name != NULL ) { - - if ( strcmp( options[i].name, option_name ) == 0 ) return options[i].value; - i++; - } - return NULL; -} - - -static int set_option( struct httplib_option_t *options, const char *name, const char *value ) { - - int i; - - for (i = 0; main_config_options[i].name != NULL; i++) { - if (0 == strcmp(name, main_config_options[i].name)) { - /* This option is evaluated by main.c, not libhttp.c - just skip it - * and return OK */ - return 1; - } - } - - for (i = 0; i < MAX_OPTIONS; i++) { - - if ( options[i].name == NULL ) { - - options[i].name = sdup( name ); - options[i].name = sdup( value ); - options[i+1].name = NULL; - - break; - } - - if ( ! strcmp(options[i].name, name) ) { - - free( (void *)options[i].value ); - options[i].value = sdup( value ); - - break; - } - } - - if ( i == MAX_OPTIONS ) die( "Too many options specified" ); - - if ( options[i].name == NULL || options[i].value == NULL ) die( "Out of memory" ); - - /* option set correctly */ - return 1; -} - - -static int read_config_file( const char *config_file, struct httplib_option_t *options ) { - - char line[MAX_CONF_FILE_LINE_SIZE], *p; - FILE *fp = NULL; - size_t i; - size_t j; - size_t line_no = 0; - - /* Open the config file */ - fp = fopen(config_file, "r"); - if (fp == NULL) { - /* Failed to open the file. Keep errno for the caller. */ - return 0; - } - - /* Load config file settings first */ - if (fp != NULL) { - fprintf(stderr, "Loading config file %s\n", config_file); - - /* Loop over the lines in config file */ - while (fgets(line, sizeof(line), fp) != NULL) { - - if (!line_no && !memcmp(line, "\xEF\xBB\xBF", 3)) { - /* strip UTF-8 BOM */ - p = line + 3; - } else { - p = line; - } - line_no++; - - /* Ignore empty lines and comments */ - for (i = 0; isspace(*(unsigned char *)&line[i]);) - i++; - if (p[i] == '#' || p[i] == '\0') { - continue; - } - - /* Skip spaces, \r and \n at the end of the line */ - for (j = strlen(line) - 1; - isspace(*(unsigned char *)&line[j]) - || iscntrl(*(unsigned char *)&line[j]);) - line[j--] = 0; - - /* Find the space character between option name and value */ - for (j = i; !isspace(*(unsigned char *)&line[j]) && (line[j] != 0);) - j++; - - /* Terminate the string - then the string at (line+i) contains the - * option name */ - line[j] = 0; - j++; - - /* Trim additional spaces between option name and value - then - * (line+j) contains the option value */ - while (isspace(line[j])) - j++; - - /* Set option */ - if (!set_option(options, line + i, line + j)) { - fprintf(stderr, "%s: line %d is invalid, ignoring it:\n %s", config_file, (int)line_no, p); - } - } - - fclose( fp ); - } - return 1; -} - - -static void process_command_line_arguments( int argc, char *argv[], struct httplib_option_t *options ) { - - char *p; - char error_string[ERROR_STRING_LEN]; - size_t i, cmd_line_opts_start = 1; -#ifdef CONFIG_FILE2 - FILE *fp = NULL; -#endif /* CONFIG_FILE2 */ - - /* Should we use a config file ? */ - if ((argc > 1) && (argv[1] != NULL) && (argv[1][0] != '-') - && (argv[1][0] != 0)) { - /* The first command line parameter is a config file name. */ - snprintf(g_config_file_name, - sizeof(g_config_file_name) - 1, - "%s", - argv[1]); - cmd_line_opts_start = 2; - } else if ((p = strrchr(argv[0], DIRSEP)) == NULL) { - /* No config file set. No path in arg[0] found. - * Use default file name in the current path. */ - snprintf( g_config_file_name, sizeof(g_config_file_name) - 1, "%s", CONFIG_FILE ); - } else { - /* No config file set. Path to exe found in arg[0]. - * Use default file name next to the executable. */ - snprintf(g_config_file_name, sizeof(g_config_file_name) - 1, "%.*s%c%s", (int)(p - argv[0]), argv[0], DIRSEP, CONFIG_FILE); - } - g_config_file_name[sizeof(g_config_file_name) - 1] = 0; - -#ifdef CONFIG_FILE2 - fp = fopen(g_config_file_name, "r"); - - /* try alternate config file */ - if (fp == NULL) { - fp = fopen(CONFIG_FILE2, "r"); - if (fp != NULL) { - strcpy(g_config_file_name, CONFIG_FILE2); - } - } - if ( fp != NULL ) fclose(fp); - -#endif /* CONFIG_FILE2 */ - - /* read all configurations from a config file */ - if (0 == read_config_file(g_config_file_name, options)) { - if (cmd_line_opts_start == 2) { - /* If config file was set in command line and open failed, die. */ - /* Errno will still hold the error from fopen. */ - die( "Cannot open config file %s: %s", g_config_file_name, httplib_error_string( errno, error_string, ERROR_STRING_LEN ) ); - } - /* Otherwise: LibHTTP can work without a config file */ - } - - /* If we're under MacOS and started by launchd, then the second - argument is process serial number, -psn_..... - In this case, don't process arguments at all. */ - if (argv[1] == NULL || memcmp(argv[1], "-psn_", 5) != 0) { - /* Handle command line flags. - They override config file and default settings. */ - for (i = cmd_line_opts_start; argv[i] != NULL; i += 2) { - if (argv[i][0] != '-' || argv[i + 1] == NULL) { - show_usage_and_exit(argv[0]); - } - if (!set_option(options, &argv[i][1], argv[i + 1])) { - fprintf( - stderr, - "command line option is invalid, ignoring it:\n %s %s\n", - argv[i], - argv[i + 1]); - } - } - } -} - - -static void init_server_name(int argc, const char *argv[]) { - - int i; - assert(sizeof(main_config_options) / sizeof(main_config_options[0]) - == NUM_MAIN_OPTIONS + 1); - assert((strlen(httplib_version()) + 12) < sizeof(g_server_base_name)); - snprintf(g_server_base_name, - sizeof(g_server_base_name), - "LibHTTP V%s", - httplib_version()); - - g_server_name = g_server_base_name; - for (i = 0; i < argc - 1; i++) { - if ((argv[i][0] == '-') - && (0 == strcmp(argv[i] + 1, - main_config_options[OPTION_TITLE].name))) { - g_server_name = (const char *)(argv[i + 1]); - } - } - g_icon_name = NULL; - for (i = 0; i < argc - 1; i++) { - if ((argv[i][0] == '-') - && (0 == strcmp(argv[i] + 1, - main_config_options[OPTION_ICON].name))) { - g_icon_name = (const char *)(argv[i + 1]); - } - } -} - - -static int log_message( const struct lh_ctx_t *ctx, const struct lh_con_t *conn, const char *message ) { - - struct tuser_data *ud; - - UNUSED_PARAMETER(conn); - - fprintf( stderr, "%s\n", message ); - - ud = httplib_get_user_data( ctx ); - if ( ud != NULL && ud->first_message == NULL ) ud->first_message = sdup( message ); - - return 0; - -} /* log_message */ - - -static int is_path_absolute(const char *path) { - -#ifdef _WIN32 - return path != NULL - && ((path[0] == '\\' && path[1] == '\\') || /* UNC path, e.g. - \\server\dir */ - (isalpha(path[0]) && path[1] == ':' - && path[2] == '\\')); /* E.g. X:\dir */ -#else /* _WIN32 */ - return path != NULL && path[0] == '/'; -#endif /* _WIN32 */ -} - - -static void verify_existence( struct httplib_option_t *options, const char *option_name, int must_be_dir) { - - struct stat st; - char error_string[ERROR_STRING_LEN]; - const char *path = get_option(options, option_name); - -#ifdef _WIN32 - wchar_t wbuf[1024]; - char mbbuf[1024]; - int len; - - if (path) { - memset( wbuf, 0, sizeof(wbuf) ); - memset( mbbuf, 0, sizeof(mbbuf) ); - len = MultiByteToWideChar(CP_UTF8, 0, path, -1, wbuf, (int)sizeof(wbuf) / sizeof(wbuf[0]) - 1); - wcstombs(mbbuf, wbuf, sizeof(mbbuf) - 1); - path = mbbuf; - (void)len; - } -#endif /* _WIN32 */ - - if (path != NULL && (stat(path, &st) != 0 - || ((S_ISDIR(st.st_mode) ? 1 : 0) != must_be_dir))) { - die("Invalid path for %s: [%s]: (%s). Make sure that path is either " - "absolute, or it is relative to libhttp executable.", - option_name, - path, - httplib_error_string( errno, error_string, ERROR_STRING_LEN ) ); - } -} - - -static void set_absolute_path( struct httplib_option_t *options, const char *option_name, const char *path_to_libhttp_exe ) { - - char path[PATH_MAX] = ""; - char absolute[PATH_MAX] = ""; - const char *option_value; - const char *p; - - /* Check whether option is already set */ - option_value = get_option(options, option_name); - - /* If option is already set and it is an absolute path, - leave it as it is -- it's already absolute. */ - if (option_value != NULL && !is_path_absolute(option_value)) { - /* Not absolute. Use the directory where libhttp executable lives - be the relative directory for everything. - Extract libhttp executable directory into path. */ - if ((p = strrchr(path_to_libhttp_exe, DIRSEP)) == NULL) { - getcwd(path, sizeof(path)); - } else { - snprintf(path, sizeof(path) - 1, "%.*s", (int)(p - path_to_libhttp_exe), path_to_libhttp_exe); - path[sizeof(path) - 1] = 0; - } - - strncat(path, "/", sizeof(path) - strlen(path) - 1); - strncat(path, option_value, sizeof(path) - strlen(path) - 1); - - /* Absolutize the path, and set the option */ - abs_path(path, absolute, sizeof(absolute)); - set_option(options, option_name, absolute); - } -} - - - -#if defined(__MINGW32__) || defined(__MINGW64__) -/* For __MINGW32/64_MAJOR/MINOR_VERSION define */ -#include <_mingw.h> -#endif /* __MINGW32__ || __MINGW64__ */ - - -static void start_libhttp( int argc, char *argv[] ) { - - struct httplib_callbacks callbacks; - struct httplib_option_t options[MAX_OPTIONS+1] = { { NULL, NULL } }; - int i; - - /* Start option -I: - * Show system information and exit - * This is very useful for diagnosis. */ - if (argc > 1 && !strcmp(argv[1], "-I")) { - const char *version = httplib_version(); -#if defined(_WIN32) - DWORD dwVersion = 0; - DWORD dwMajorVersion = 0; - DWORD dwMinorVersion = 0; - SYSTEM_INFO si; - - GetSystemInfo(&si); - -#ifdef _MSC_VER -#pragma warning(push) -// GetVersion was declared deprecated -#pragma warning(disable : 4996) -#endif /* _MSC_VER */ - dwVersion = GetVersion(); -#ifdef _MSC_VER -#pragma warning(pop) -#endif /* _MSC_VER */ - - dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion))); - dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion))); - - (void)MakeConsole(); - fprintf( stdout, "\n%s\n", g_server_name ); - fprintf( stdout, "%s - Windows %u.%u\n", g_server_base_name, (unsigned)dwMajorVersion, (unsigned)dwMinorVersion ); - - fprintf(stdout, - "CPU: type %u, cores %u, mask %x\n", - (unsigned)si.wProcessorArchitecture, - (unsigned)si.dwNumberOfProcessors, - (unsigned)si.dwActiveProcessorMask); - -#else /* _WIN32 */ - fprintf(stdout, "\n%s\n", g_server_name); - fprintf(stdout, "%s - Symbian\n", g_server_base_name); -#endif /* _WIN32 */ -/* - struct utsname name; - memset( &name, 0, sizeof(name) ); - uname( &name ); - fprintf( stdout, "\n%s\n", g_server_name ); - fprintf( stdout, "%s - %s %s (%s) - %s\n", g_server_base_name, name.sysname, name.version, name.release, name.machine ); -*/ - - fprintf( stdout, "Features:" ); - if ( httplib_check_feature( 1 ) ) fprintf( stdout, " Files" ); - if ( httplib_check_feature( 2 ) ) fprintf( stdout, " HTTPS" ); - if ( httplib_check_feature( 4 ) ) fprintf( stdout, " CGI" ); - if ( httplib_check_feature( 8 ) ) fprintf( stdout, " IPv6" ); - if ( httplib_check_feature( 16 ) ) fprintf( stdout, " WebSockets" ); - if ( httplib_check_feature( 32 ) ) fprintf( stdout, " Lua" ); - fprintf( stdout, "\n" ); - - fprintf(stdout, "Version: %s\n", version); - fprintf(stdout, "Build: %s\n", __DATE__); - -/* http://sourceforge.net/p/predef/wiki/Compilers/ */ -#if defined(_MSC_VER) - fprintf(stdout, "MSC: %u (%u)\n", (unsigned)_MSC_VER, (unsigned)_MSC_FULL_VER); -#elif defined(__MINGW64__) - fprintf(stdout, "MinGW64: %u.%u\n", (unsigned)__MINGW64_VERSION_MAJOR, (unsigned)__MINGW64_VERSION_MINOR); - fprintf(stdout, "MinGW32: %u.%u\n", (unsigned)__MINGW32_MAJOR_VERSION, (unsigned)__MINGW32_MINOR_VERSION); -#elif defined(__MINGW32__) - fprintf(stdout, "MinGW32: %u.%u\n", (unsigned)__MINGW32_MAJOR_VERSION, (unsigned)__MINGW32_MINOR_VERSION); -#elif defined(__clang__) - fprintf(stdout, "clang: %u.%u.%u (%s)\n", __clang_major__, __clang_minor__, __clang_patchlevel__, __clang_version__); -#elif defined(__GNUC__) - fprintf(stdout, "gcc: %u.%u.%u\n", (unsigned)__GNUC__, (unsigned)__GNUC_MINOR__, (unsigned)__GNUC_PATCHLEVEL__); -#elif defined(__INTEL_COMPILER) - fprintf(stdout, "Intel C/C++: %u\n", (unsigned)__INTEL_COMPILER); -#elif defined(__BORLANDC__) - fprintf(stdout, "Borland C: 0x%x\n", (unsigned)__BORLANDC__); -#elif defined(__SUNPRO_C) - fprintf(stdout, "Solaris: 0x%x\n", (unsigned)__SUNPRO_C); -#else - fprintf(stdout, "Other\n"); -#endif /* Compiler version */ - /* Determine 32/64 bit data mode. - * see https://en.wikipedia.org/wiki/64-bit_computing */ - fprintf(stdout, - "Data model: i:%u/%u/%u/%u, f:%u/%u/%u, c:%u/%u, " - "p:%u, s:%u, t:%u\n", - (unsigned)sizeof(short), - (unsigned)sizeof(int), - (unsigned)sizeof(long), - (unsigned)sizeof(long long), - (unsigned)sizeof(float), - (unsigned)sizeof(double), - (unsigned)sizeof(long double), - (unsigned)sizeof(char), - (unsigned)sizeof(wchar_t), - (unsigned)sizeof(void *), - (unsigned)sizeof(size_t), - (unsigned)sizeof(time_t)); - - exit(EXIT_SUCCESS); - } - - /* Edit passwords file: Add user or change password, if -A option is - * specified */ - if (argc > 1 && !strcmp(argv[1], "-A")) { - if (argc != 6) { - show_usage_and_exit(argv[0]); - } - exit(httplib_modify_passwords_file(argv[2], argv[3], argv[4], argv[5]) ? EXIT_SUCCESS : EXIT_FAILURE); - } - - /* Edit passwords file: Remove user, if -R option is specified */ - if (argc > 1 && !strcmp(argv[1], "-R")) { - if (argc != 5) { - show_usage_and_exit(argv[0]); - } - exit(httplib_modify_passwords_file(argv[2], argv[3], argv[4], NULL) ? EXIT_SUCCESS : EXIT_FAILURE); - } - - /* Show usage if -h or --help options are specified */ - if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "-H") - || !strcmp(argv[1], "--help"))) { - show_usage_and_exit(argv[0]); - } - - options[0].name = NULL; - set_option( options, "document_root", "." ); - - /* Update config based on command line arguments */ - process_command_line_arguments( argc, argv, options ); - - /* Make sure we have absolute paths for files and directories */ - set_absolute_path( options, "document_root", argv[0] ); - set_absolute_path( options, "put_delete_auth_file", argv[0] ); - set_absolute_path( options, "cgi_interpreter", argv[0] ); - set_absolute_path( options, "access_log_file", argv[0] ); - set_absolute_path( options, "error_log_file", argv[0] ); - set_absolute_path( options, "global_auth_file", argv[0] ); - set_absolute_path( options, "ssl_certificate", argv[0] ); - - /* Make extra verification for certain options */ - verify_existence( options, "document_root", 1 ); - verify_existence( options, "cgi_interpreter", 0 ); - verify_existence( options, "ssl_certificate", 0 ); - verify_existence( options, "ssl_ca_path", 1 ); - verify_existence( options, "ssl_ca_file", 0 ); - - /* Setup signal handler: quit on Ctrl-C */ - signal( SIGTERM, signal_handler ); - signal( SIGINT, signal_handler ); - - /* Initialize user data */ - memset( &g_user_data, 0, sizeof(g_user_data) ); - - /* Start LibHTTP */ - memset(&callbacks, 0, sizeof(callbacks)); - callbacks.log_message = &log_message; - g_ctx = httplib_start( &callbacks, &g_user_data, options ); - - /* httplib_start copies all options to an internal buffer. - * The options data field here is not required anymore. */ - for (i=0; options[i].name != NULL; i++) { - - if ( options[i].name != NULL ) free( (void *)options[i].name ); - if ( options[i].value != NULL ) free( (void *)options[i].value ); - - options[i].name = NULL; - options[i].value = NULL; - } - - /* If httplib_start fails, it returns NULL */ - if ( g_ctx == NULL ) die("Failed to start %s:\n%s", g_server_name, ((g_user_data.first_message == NULL) ? "unknown reason" : g_user_data.first_message)); -} - - -static void stop_libhttp(void) { - - httplib_stop(g_ctx); - free(g_user_data.first_message); - g_user_data.first_message = NULL; -} - - -#ifdef _WIN32 -/* Win32 has a small GUI. - * Define some GUI elements and Windows message handlers. */ - -enum { - ID_ICON = 100, - ID_QUIT, - ID_SETTINGS, - ID_SEPARATOR, - ID_INSTALL_SERVICE, - ID_REMOVE_SERVICE, - ID_STATIC, - ID_GROUP, - ID_PASSWORD, - ID_SAVE, - ID_RESET_DEFAULTS, - ID_RESET_FILE, - ID_RESET_ACTIVE, - ID_STATUS, - ID_CONNECT, - ID_ADD_USER, - ID_ADD_USER_NAME, - ID_ADD_USER_REALM, - ID_INPUT_LINE, - - /* All dynamically created text boxes for options have IDs starting from - ID_CONTROLS, incremented by one. */ - ID_CONTROLS = 200, - - /* Text boxes for files have "..." buttons to open file browser. These - buttons have IDs that are ID_FILE_BUTTONS_DELTA higher than associated - text box ID. */ - ID_FILE_BUTTONS_DELTA = 1000 -}; - - -static HICON hIcon; -static SERVICE_STATUS ss; -static SERVICE_STATUS_HANDLE hStatus; -static const char *service_magic_argument = "--"; -static NOTIFYICONDATA TrayIcon; - - -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(void) { - - ss.dwServiceType = SERVICE_WIN32; - ss.dwCurrentState = SERVICE_RUNNING; - ss.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; - - hStatus = RegisterServiceCtrlHandler(g_server_name, ControlHandler); - SetServiceStatus(hStatus, &ss); - - while (ss.dwCurrentState == SERVICE_RUNNING) { - Sleep(1000); - } - stop_libhttp(); - - ss.dwCurrentState = SERVICE_STOPPED; - ss.dwWin32ExitCode = (DWORD)-1; - SetServiceStatus(hStatus, &ss); -} - - -static void show_error(void) { - - char buf[256]; - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - buf, - sizeof(buf), - NULL); - MessageBox(NULL, buf, "Error", MB_OK); -} - - -static void * align(void *ptr, uintptr_t alig) { - - uintptr_t ul = (uintptr_t)ptr; - ul += alig; - ul &= ~alig; - return ((void *)ul); -} - - -static void save_config(HWND hDlg, FILE *fp) { - - UNUSED_PARAMETER(hDlg); - UNUSED_PARAMETER(fp); - - /* - * No options currently saved - */ - -// char value[2000] = ""; -// const char *default_value; -// const struct httplib_option *options; -// int i; -// int id; - -// fprintf(fp, "%s", config_file_top_comment); -// options = httplib_get_valid_options(); -// for (i = 0; options[i].name != NULL; i++) { -// id = ID_CONTROLS + i; -// if (options[i].type == CONFIG_TYPE_BOOLEAN) { -// snprintf(value, sizeof(value) - 1, "%s", IsDlgButtonChecked(hDlg, id) ? "yes" : "no"); -// value[sizeof(value) - 1] = 0; -// } else { -// GetDlgItemText(hDlg, id, value, sizeof(value)); -// } -// default_value = -// options[i].default_value == NULL ? "" : options[i].default_value; -// /* If value is the same as default, skip it */ -// if (strcmp(value, default_value) != 0) { -// fprintf(fp, "%s %s\n", options[i].name, value); -// } -// } - -} /* save_config */ - - -static INT_PTR CALLBACK SettingsDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { - - FILE *fp; - int i, j; - const char *name; - const char *value; - char *file_options[MAX_OPTIONS * 2 + 1] = {0}; - char *title; - (void)lParam; - - switch (msg) { - - case WM_CLOSE: - DestroyWindow(hDlg); - break; - - case WM_COMMAND: - switch (LOWORD(wParam)) { - - case ID_SAVE: - EnableWindow(GetDlgItem(hDlg, ID_SAVE), FALSE); - if ((fp = fopen(g_config_file_name, "w+")) != NULL) { - save_config(hDlg, fp); - fclose(fp); - stop_libhttp(); - start_libhttp(__argc, __argv); - } - EnableWindow(GetDlgItem(hDlg, ID_SAVE), TRUE); - break; - - case ID_RESET_DEFAULTS: - for (i = 0; default_options[i].name != NULL; i++) { - name = default_options[i].name; - value = default_options[i].default_value == NULL - ? "" - : default_options[i].default_value; - if (default_options[i].type == CONFIG_TYPE_BOOLEAN) { - CheckDlgButton(hDlg, ID_CONTROLS + i, !strcmp(value, "yes") ? BST_CHECKED : BST_UNCHECKED); - } else { - SetWindowText(GetDlgItem(hDlg, ID_CONTROLS + i), value); - } - } - break; - - case ID_RESET_FILE: - read_config_file(g_config_file_name, file_options); - for (i = 0; default_options[i].name != NULL; i++) { - name = default_options[i].name; - value = default_options[i].default_value; - for (j = 0; file_options[j * 2] != NULL; j++) { - if (!strcmp(name, file_options[j * 2])) { - value = file_options[j * 2 + 1]; - } - } - if (value == NULL) { - value = ""; - } - if (default_options[i].type == CONFIG_TYPE_BOOLEAN) { - CheckDlgButton(hDlg, ID_CONTROLS + i, !strcmp(value, "yes") ? BST_CHECKED : BST_UNCHECKED); - } else { - SetWindowText(GetDlgItem(hDlg, ID_CONTROLS + i), value); - } - } - for (i = 0; i < MAX_OPTIONS; i++) { - free(file_options[2 * i]); - free(file_options[2 * i + 1]); - } - break; - - case ID_RESET_ACTIVE: - for (i = 0; default_options[i].name != NULL; i++) { - name = default_options[i].name; - value = httplib_get_option(g_ctx, name); - if (default_options[i].type == CONFIG_TYPE_BOOLEAN) { - CheckDlgButton(hDlg, ID_CONTROLS + i, !strcmp(value, "yes") ? BST_CHECKED : BST_UNCHECKED); - } else { - SetDlgItemText(hDlg, ID_CONTROLS + i, value == NULL ? "" : value); - } - } - break; - } - - for (i = 0; default_options[i].name != NULL; i++) { - name = default_options[i].name; - if (((default_options[i].type == CONFIG_TYPE_FILE) - || (default_options[i].type == CONFIG_TYPE_DIRECTORY)) - && LOWORD(wParam) == ID_CONTROLS + i + ID_FILE_BUTTONS_DELTA) { - OPENFILENAME of; - BROWSEINFO bi; - char path[PATH_MAX] = ""; - - memset(&of, 0, sizeof(of)); - of.lStructSize = sizeof(of); - of.hwndOwner = (HWND)hDlg; - of.lpstrFile = path; - of.nMaxFile = sizeof(path); - of.lpstrInitialDir = httplib_get_option(g_ctx, "document_root"); - of.Flags = OFN_CREATEPROMPT | OFN_NOCHANGEDIR | OFN_HIDEREADONLY; - - memset(&bi, 0, sizeof(bi)); - bi.hwndOwner = (HWND)hDlg; - bi.lpszTitle = "Choose WWW root directory:"; - bi.ulFlags = BIF_RETURNONLYFSDIRS; - - if (default_options[i].type == CONFIG_TYPE_DIRECTORY) { - SHGetPathFromIDList(SHBrowseForFolder(&bi), path); - } else { - GetOpenFileName(&of); - } - - if (path[0] != '\0') { - SetWindowText(GetDlgItem(hDlg, ID_CONTROLS + i), path); - } - } - } - break; - - case WM_INITDIALOG: - SendMessage(hDlg, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon); - SendMessage(hDlg, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)hIcon); - title = malloc(strlen(g_server_name) + 16); - if (title) { - strcpy(title, g_server_name); - strcat(title, " settings"); - SetWindowText(hDlg, title); - free(title); - } - SetFocus(GetDlgItem(hDlg, ID_SAVE)); - - /* Init dialog with active settings */ - SendMessage(hDlg, WM_COMMAND, ID_RESET_ACTIVE, 0); - /* alternative: SendMessage(hDlg, WM_COMMAND, ID_RESET_FILE, 0); */ - break; - - default: - break; - } - - return FALSE; -} - - -struct tstring_input_buf { - unsigned buflen; - char *buffer; -}; - - -static INT_PTR CALLBACK -InputDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP) -{ - static struct tstring_input_buf *inBuf = 0; - WORD ctrlId; - - switch (msg) { - case WM_CLOSE: - inBuf = 0; - DestroyWindow(hDlg); - break; - - case WM_COMMAND: - ctrlId = LOWORD(wParam); - if (ctrlId == IDOK) { - /* Add user */ - GetWindowText(GetDlgItem(hDlg, ID_INPUT_LINE), - inBuf->buffer, - (int)inBuf->buflen); - if (strlen(inBuf->buffer) > 0) { - EndDialog(hDlg, IDOK); - } - } else if (ctrlId == IDCANCEL) { - EndDialog(hDlg, IDCANCEL); - } - break; - - case WM_INITDIALOG: - inBuf = (struct tstring_input_buf *)lP; - assert(inBuf != NULL); - assert((inBuf->buffer != NULL) && (inBuf->buflen != 0)); - assert(strlen(inBuf->buffer) < inBuf->buflen); - SendMessage(hDlg, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon); - SendMessage(hDlg, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)hIcon); - SendDlgItemMessage( - hDlg, ID_INPUT_LINE, EM_LIMITTEXT, inBuf->buflen - 1, 0); - SetWindowText(GetDlgItem(hDlg, ID_INPUT_LINE), inBuf->buffer); - SetWindowText(hDlg, "Modify password"); - SetFocus(GetDlgItem(hDlg, ID_INPUT_LINE)); - break; - - default: - break; - } - - return FALSE; -} - - -static void suggest_passwd(char *passwd) { - - unsigned u; - char *p; - union { - FILETIME ft; - LARGE_INTEGER li; - } num; - - /* valid characters are 32 to 126 */ - GetSystemTimeAsFileTime(&num.ft); - num.li.HighPart |= (LONG)GetCurrentProcessId(); - p = passwd; - while (num.li.QuadPart) { - u = (unsigned)(num.li.QuadPart % 95); - num.li.QuadPart -= u; - num.li.QuadPart /= 95; - *p = (char)(u + 32); - p++; - } -} - - -static void add_control(unsigned char **mem, - DLGTEMPLATE *dia, - WORD type, - WORD id, - DWORD style, - short x, - short y, - short cx, - short cy, - const char *caption); - - -static int get_password(const char *user, const char *realm, char *passwd, unsigned passwd_len) { - -#define HEIGHT (15) -#define WIDTH (280) -#define LABEL_WIDTH (90) - - unsigned char mem[4096], *p; - DLGTEMPLATE *dia = (DLGTEMPLATE *)mem; - int ok; - short y; - struct tstring_input_buf dlgprms; - - static struct { - DLGTEMPLATE template; /* 18 bytes */ - WORD menu, class; - wchar_t caption[1]; - WORD fontsiz; - wchar_t fontface[7]; - } dialog_header = {{WS_CAPTION | WS_POPUP | WS_SYSMENU | WS_VISIBLE | DS_SETFONT | WS_DLGFRAME, - WS_EX_TOOLWINDOW, - 0, - 200, - 200, - WIDTH, - 0}, - 0, - 0, - L"", - 8, - L"Tahoma"}; - - dlgprms.buffer = passwd; - dlgprms.buflen = passwd_len; - - assert((user != NULL) && (realm != NULL) && (passwd != NULL)); - - if (guard < 100) { - guard += 100; - } else { - return 0; - } - - /* Create a password suggestion */ - memset(passwd, 0, passwd_len); - suggest_passwd(passwd); - - /* Create the dialog */ - (void)memset(mem, 0, sizeof(mem)); - (void)memcpy(mem, &dialog_header, sizeof(dialog_header)); - p = mem + sizeof(dialog_header); - - y = HEIGHT; - add_control(&p, dia, 0x82, ID_STATIC, WS_VISIBLE | WS_CHILD, 10, y, LABEL_WIDTH, HEIGHT, "User:"); - add_control(&p, dia, 0x81, ID_CONTROLS + 1, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL | WS_DISABLED, 15 + LABEL_WIDTH, y, WIDTH - LABEL_WIDTH - 25, HEIGHT, user); - - y += HEIGHT; - add_control(&p, dia, 0x82, ID_STATIC, WS_VISIBLE | WS_CHILD, 10, y, LABEL_WIDTH, HEIGHT, "Realm:"); - add_control(&p, dia, 0x81, ID_CONTROLS + 2, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL | WS_DISABLED, 15 + LABEL_WIDTH, y, WIDTH - LABEL_WIDTH - 25, HEIGHT, realm); - - y += HEIGHT; - add_control(&p, dia, 0x82, ID_STATIC, WS_VISIBLE | WS_CHILD, 10, y, LABEL_WIDTH, HEIGHT, "Password:"); - add_control(&p, dia, 0x81, ID_INPUT_LINE, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL | WS_TABSTOP, 15 + LABEL_WIDTH, y, WIDTH - LABEL_WIDTH - 25, HEIGHT, ""); - - y += (WORD)(HEIGHT * 2); - add_control(&p, dia, 0x80, IDOK, WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP, 80, y, 55, 12, "Ok"); - add_control(&p, dia, 0x80, IDCANCEL, WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP, 140, y, 55, 12, "Cancel"); - - assert((intptr_t)p - (intptr_t)mem < (intptr_t)sizeof(mem)); - - dia->cy = y + (WORD)(HEIGHT * 1.5); - - ok = (IDOK == DialogBoxIndirectParam( - NULL, dia, NULL, InputDlgProc, (LPARAM)&dlgprms)); - - guard -= 100; - - return ok; - -#undef HEIGHT -#undef WIDTH -#undef LABEL_WIDTH -} - - -static INT_PTR CALLBACK -PasswordDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP) -{ - static const char *passfile = 0; - char domain[256], user[256], password[256]; - WORD ctrlId; - - switch (msg) { - case WM_CLOSE: - passfile = 0; - DestroyWindow(hDlg); - break; - - case WM_COMMAND: - ctrlId = LOWORD(wParam); - if (ctrlId == ID_ADD_USER) { - /* Add user */ - GetWindowText(GetDlgItem(hDlg, ID_ADD_USER_NAME), - user, - sizeof(user)); - GetWindowText(GetDlgItem(hDlg, ID_ADD_USER_REALM), - domain, - sizeof(domain)); - if (get_password(user, domain, password, sizeof(password))) { - httplib_modify_passwords_file(passfile, domain, user, password); - EndDialog(hDlg, IDOK); - } - } else if ((ctrlId >= (ID_CONTROLS + ID_FILE_BUTTONS_DELTA * 3)) - && (ctrlId < (ID_CONTROLS + ID_FILE_BUTTONS_DELTA * 4))) { - /* Modify password */ - GetWindowText(GetDlgItem(hDlg, ctrlId - ID_FILE_BUTTONS_DELTA * 3), - user, - sizeof(user)); - GetWindowText(GetDlgItem(hDlg, ctrlId - ID_FILE_BUTTONS_DELTA * 2), - domain, - sizeof(domain)); - if (get_password(user, domain, password, sizeof(password))) { - httplib_modify_passwords_file(passfile, domain, user, password); - EndDialog(hDlg, IDOK); - } - } else if ((ctrlId >= (ID_CONTROLS + ID_FILE_BUTTONS_DELTA * 2)) - && (ctrlId < (ID_CONTROLS + ID_FILE_BUTTONS_DELTA * 3))) { - /* Remove user */ - GetWindowText(GetDlgItem(hDlg, ctrlId - ID_FILE_BUTTONS_DELTA * 2), - user, - sizeof(user)); - GetWindowText(GetDlgItem(hDlg, ctrlId - ID_FILE_BUTTONS_DELTA), - domain, - sizeof(domain)); - httplib_modify_passwords_file(passfile, domain, user, NULL); - EndDialog(hDlg, IDOK); - } - break; - - case WM_INITDIALOG: - passfile = (const char *)lP; - SendMessage(hDlg, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon); - SendMessage(hDlg, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)hIcon); - SetWindowText(hDlg, passfile); - SetFocus(GetDlgItem(hDlg, ID_ADD_USER_NAME)); - break; - - default: - break; - } - - return FALSE; -} - - -static void -add_control(unsigned char **mem, - DLGTEMPLATE *dia, - WORD type, - WORD id, - DWORD style, - short x, - short y, - short cx, - short cy, - const char *caption) -{ - DLGITEMTEMPLATE *tp; - LPWORD p; - - dia->cdit++; - - *mem = align(*mem, 3); - tp = (DLGITEMTEMPLATE *)*mem; - - tp->id = id; - tp->style = style; - tp->dwExtendedStyle = 0; - tp->x = x; - tp->y = y; - tp->cx = cx; - tp->cy = cy; - - p = align(*mem + sizeof(*tp), 1); - *p++ = 0xffff; - *p++ = type; - - while (*caption != '\0') { - *p++ = (WCHAR)*caption++; - } - *p++ = 0; - p = align(p, 1); - - *p++ = 0; - *mem = (unsigned char *)p; -} - - -static void show_settings_dialog( void ) { -#define HEIGHT (15) -#define WIDTH (460) -#define LABEL_WIDTH (90) - - unsigned char mem[16 * 1024], *p; - const struct httplib_option *options; - DWORD style; - DLGTEMPLATE *dia = (DLGTEMPLATE *)mem; - WORD i, cl, nelems = 0; - short width, x, y; - - static struct { - DLGTEMPLATE template; /* 18 bytes */ - WORD menu, class; - wchar_t caption[1]; - WORD fontsiz; - wchar_t fontface[7]; - } dialog_header = {{WS_CAPTION | WS_POPUP | WS_SYSMENU | WS_VISIBLE | DS_SETFONT | WS_DLGFRAME, - WS_EX_TOOLWINDOW, - 0, - 200, - 200, - WIDTH, - 0}, - 0, - 0, - L"", - 8, - L"Tahoma"}; - - if (guard == 0) { - guard++; - } else { - return; - } - - (void)memset(mem, 0, sizeof(mem)); - (void)memcpy(mem, &dialog_header, sizeof(dialog_header)); - p = mem + sizeof(dialog_header); - - options = httplib_get_valid_options(); - for (i = 0; options[i].name != NULL; i++) { - style = WS_CHILD | WS_VISIBLE | WS_TABSTOP; - x = 10 + (WIDTH / 2) * (nelems % 2); - y = (nelems / 2 + 1) * HEIGHT + 5; - width = WIDTH / 2 - 20 - LABEL_WIDTH; - if (options[i].type == CONFIG_TYPE_NUMBER) { - style |= ES_NUMBER; - cl = 0x81; - style |= WS_BORDER | ES_AUTOHSCROLL; - } else if (options[i].type == CONFIG_TYPE_BOOLEAN) { - cl = 0x80; - style |= BS_AUTOCHECKBOX; - } else if ((options[i].type == CONFIG_TYPE_FILE) - || (options[i].type == CONFIG_TYPE_DIRECTORY)) { - style |= WS_BORDER | ES_AUTOHSCROLL; - width -= 20; - cl = 0x81; - add_control(&p, dia, 0x80, ID_CONTROLS + i + ID_FILE_BUTTONS_DELTA, WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, x + width + LABEL_WIDTH + 5, y, 15, 12, "..."); - } else { - cl = 0x81; - style |= WS_BORDER | ES_AUTOHSCROLL; - } - add_control(&p, dia, 0x82, ID_STATIC, WS_VISIBLE | WS_CHILD, x, y, LABEL_WIDTH, HEIGHT, options[i].name); - add_control(&p, dia, cl, ID_CONTROLS + i, style, x + LABEL_WIDTH, y, width, 12, ""); - nelems++; - - assert(((intptr_t)p - (intptr_t)mem) < (intptr_t)sizeof(mem)); - } - - y = (((nelems + 1) / 2 + 1) * HEIGHT + 5); - add_control(&p, dia, 0x80, ID_GROUP, WS_CHILD | WS_VISIBLE | BS_GROUPBOX, 5, 5, WIDTH - 10, y, " Settings "); - y += 10; - add_control(&p, dia, 0x80, ID_SAVE, WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP, WIDTH - 70, y, 65, 12, "Save Settings"); - add_control(&p, dia, 0x80, ID_RESET_DEFAULTS, WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP, WIDTH - 140, y, 65, 12, "Reset to defaults"); - add_control(&p, dia, 0x80, ID_RESET_FILE, WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP, WIDTH - 210, y, 65, 12, "Reload from file"); - add_control(&p, dia, 0x80, ID_RESET_ACTIVE, WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP, WIDTH - 280, y, 65, 12, "Reload active"); - add_control(&p, dia, 0x82, ID_STATIC, WS_CHILD | WS_VISIBLE | WS_DISABLED, 5, y, 100, 12, g_server_base_name); - - assert(((intptr_t)p - (intptr_t)mem) < (intptr_t)sizeof(mem)); - - dia->cy = ((nelems + 1) / 2 + 1) * HEIGHT + 30; - DialogBoxIndirectParam(NULL, dia, NULL, SettingsDlgProc, (LPARAM)NULL); - guard--; - -#undef HEIGHT -#undef WIDTH -#undef LABEL_WIDTH -} - - -static void change_password_file( void ) { - -#define HEIGHT (15) -#define WIDTH (320) -#define LABEL_WIDTH (90) - - OPENFILENAME of; - char path[PATH_MAX] = PASSWORDS_FILE_NAME; - char strbuf[256]; - char u[256]; - char d[256]; - HWND hDlg = NULL; - FILE *f; - short y; - short nelems; - unsigned char mem[4096]; - unsigned char *p; - DLGTEMPLATE *dia = (DLGTEMPLATE *)mem; - char domain_str[256]; - const char *domain = httplib_get_option( g_ctx, "authentication_domain", domain_str, 256 ); - - static struct { - DLGTEMPLATE template; /* 18 bytes */ - WORD menu, class; - wchar_t caption[1]; - WORD fontsiz; - wchar_t fontface[7]; - } dialog_header = {{WS_CAPTION | WS_POPUP | WS_SYSMENU | WS_VISIBLE | DS_SETFONT | WS_DLGFRAME, WS_EX_TOOLWINDOW, - 0, - 200, - 200, - WIDTH, - 0}, - 0, - 0, - L"", - 8, - L"Tahoma"}; - - if (guard == 0) { - guard++; - } else { - return; - } - - memset(&of, 0, sizeof(of)); - of.lStructSize = sizeof(of); - of.hwndOwner = (HWND)hDlg; - of.lpstrFile = path; - of.nMaxFile = sizeof(path); - of.lpstrInitialDir = httplib_get_option(g_ctx, "document_root"); - of.Flags = OFN_CREATEPROMPT | OFN_NOCHANGEDIR | OFN_HIDEREADONLY; - - if (IDOK != GetSaveFileName(&of)) { - guard--; - return; - } - - f = fopen(path, "a+"); - if (f) { - fclose(f); - } else { - MessageBox(NULL, path, "Can not open file", MB_ICONERROR); - guard--; - return; - } - - do { - (void)memset(mem, 0, sizeof(mem)); - (void)memcpy(mem, &dialog_header, sizeof(dialog_header)); - p = mem + sizeof(dialog_header); - - f = fopen(path, "r+"); - if (!f) { - MessageBox(NULL, path, "Can not open file", MB_ICONERROR); - guard--; - return; - } - - nelems = 0; - while (fgets(strbuf, sizeof(strbuf), f)) { - if (sscanf(strbuf, "%255[^:]:%255[^:]:%*s", u, d) != 2) { - continue; - } - u[255] = 0; - d[255] = 0; - y = (nelems + 1) * HEIGHT + 5; - add_control(&p, dia, 0x80, ID_CONTROLS + nelems + ID_FILE_BUTTONS_DELTA * 3, WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP, 10, y, 65, 12, "Modify password"); - add_control(&p, dia, 0x80, ID_CONTROLS + nelems + ID_FILE_BUTTONS_DELTA * 2, WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP, 80, y, 55, 12, "Remove user"); - add_control(&p, dia, 0x81, ID_CONTROLS + nelems + ID_FILE_BUTTONS_DELTA, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL | WS_DISABLED, 245, y, 60, 12, d); - add_control(&p, dia, 0x81, ID_CONTROLS + nelems, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL | WS_DISABLED, 140, y, 100, 12, u); - - nelems++; - assert(((intptr_t)p - (intptr_t)mem) < (intptr_t)sizeof(mem)); - } - fclose(f); - - y = (nelems + 1) * HEIGHT + 10; - add_control(&p, dia, 0x80, ID_ADD_USER, WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP, 80, y, 55, 12, "Add user"); - add_control(&p, dia, 0x81, ID_ADD_USER_NAME, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL | WS_TABSTOP, 140, y, 100, 12, ""); - add_control(&p, dia, 0x81, ID_ADD_USER_REALM, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL | WS_TABSTOP, 245, y, 60, 12, domain); - - y = (nelems + 2) * HEIGHT + 10; - add_control(&p, dia, 0x80, ID_GROUP, WS_CHILD | WS_VISIBLE | BS_GROUPBOX, 5, 5, WIDTH - 10, y, " Users "); - - y += HEIGHT; - add_control(&p, dia, 0x82, ID_STATIC, WS_CHILD | WS_VISIBLE | WS_DISABLED, 5, y, 100, 12, g_server_base_name); - - assert(((intptr_t)p - (intptr_t)mem) < (intptr_t)sizeof(mem)); - - dia->cy = y + 20; - } while ((IDOK == DialogBoxIndirectParam( - NULL, dia, NULL, PasswordDlgProc, (LPARAM)path)) - && (!g_exit_flag)); - - guard--; - -#undef HEIGHT -#undef WIDTH -#undef LABEL_WIDTH -} - - -static int -manage_service(int action) -{ - const char *service_name = g_server_name; - SC_HANDLE hSCM = NULL, hService = NULL; - SERVICE_DESCRIPTION descr; - char path[PATH_MAX + 20] = ""; /* Path to executable plus magic argument */ - int success = 1; - - descr.lpDescription = (LPSTR)g_server_name; - - if ((hSCM = OpenSCManager(NULL, NULL, action == ID_INSTALL_SERVICE ? GENERIC_WRITE : GENERIC_READ)) == NULL) { - success = 0; - show_error(); - } else if (action == ID_INSTALL_SERVICE) { - path[sizeof(path) - 1] = 0; - GetModuleFileName(NULL, path, sizeof(path) - 1); - strncat(path, " ", sizeof(path) - 1); - strncat(path, service_magic_argument, sizeof(path) - 1); - 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) { - ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &descr); - } else { - show_error(); - } - } else if (action == ID_REMOVE_SERVICE) { - if ((hService = OpenService(hSCM, service_name, DELETE)) == NULL || !DeleteService(hService)) { - show_error(); - } - } else if ((hService = OpenService(hSCM, service_name, SERVICE_QUERY_STATUS)) == NULL) { - success = 0; - } - - if (hService) - CloseServiceHandle(hService); - if (hSCM) - CloseServiceHandle(hSCM); - - return success; -} - - -static LRESULT CALLBACK -WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - static SERVICE_TABLE_ENTRY service_table[2]; - int service_installed; - char buf[200], *service_argv[2]; - POINT pt; - HMENU hMenu; - static UINT s_uTaskbarRestart; /* for taskbar creation */ - - service_argv[0] = __argv[0]; - service_argv[1] = NULL; - - memset(service_table, 0, sizeof(service_table)); - service_table[0].lpServiceName = (LPSTR)g_server_name; - service_table[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain; - - switch (msg) { - - case WM_CREATE: - if (__argv[1] != NULL && !strcmp(__argv[1], service_magic_argument)) { - start_libhttp(1, service_argv); - StartServiceCtrlDispatcher(service_table); - exit(EXIT_SUCCESS); - } else { - start_libhttp(__argc, __argv); - s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated")); - } - break; - - case WM_COMMAND: - switch (LOWORD(wParam)) { - case ID_QUIT: - stop_libhttp(); - Shell_NotifyIcon(NIM_DELETE, &TrayIcon); - g_exit_flag = 1; - PostQuitMessage(0); - return 0; - case ID_SETTINGS: - show_settings_dialog(); - break; - case ID_PASSWORD: - change_password_file(); - break; - case ID_INSTALL_SERVICE: - case ID_REMOVE_SERVICE: - manage_service(LOWORD(wParam)); - break; - case ID_CONNECT: - fprintf(stdout, "[%s]\n", get_url_to_first_open_port(g_ctx)); - ShellExecute(NULL, "open", get_url_to_first_open_port(g_ctx), NULL, NULL, SW_SHOW); - break; - } - break; - - case WM_USER: - switch (lParam) { - case WM_RBUTTONUP: - case WM_LBUTTONUP: - case WM_LBUTTONDBLCLK: - hMenu = CreatePopupMenu(); - AppendMenu(hMenu, - MF_STRING | MF_GRAYED, - ID_SEPARATOR, - g_server_name); - AppendMenu(hMenu, MF_SEPARATOR, ID_SEPARATOR, ""); - service_installed = manage_service(0); - snprintf(buf, - sizeof(buf) - 1, - "NT service: %s installed", - service_installed ? "" : "not"); - buf[sizeof(buf) - 1] = 0; - AppendMenu(hMenu, MF_STRING | MF_GRAYED, ID_SEPARATOR, buf); - AppendMenu(hMenu, MF_STRING | (service_installed ? MF_GRAYED : 0), ID_INSTALL_SERVICE, "Install service"); - AppendMenu(hMenu, MF_STRING | (!service_installed ? MF_GRAYED : 0), ID_REMOVE_SERVICE, "Deinstall service"); - AppendMenu(hMenu, MF_SEPARATOR, ID_SEPARATOR, ""); - AppendMenu(hMenu, MF_STRING, ID_CONNECT, "Start browser"); - AppendMenu(hMenu, MF_STRING, ID_SETTINGS, "Edit settings"); - AppendMenu(hMenu, MF_STRING, ID_PASSWORD, "Modify password file"); - AppendMenu(hMenu, MF_SEPARATOR, ID_SEPARATOR, ""); - AppendMenu(hMenu, MF_STRING, ID_QUIT, "Exit"); - GetCursorPos(&pt); - SetForegroundWindow(hWnd); - TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, hWnd, NULL); - PostMessage(hWnd, WM_NULL, 0, 0); - DestroyMenu(hMenu); - break; - } - break; - - case WM_CLOSE: - stop_libhttp(); - Shell_NotifyIcon(NIM_DELETE, &TrayIcon); - g_exit_flag = 1; - PostQuitMessage(0); - return 0; /* We've just sent our own quit message, with proper hwnd. */ - - default: - if (msg == s_uTaskbarRestart) - Shell_NotifyIcon(NIM_ADD, &TrayIcon); - } - - return DefWindowProc(hWnd, msg, wParam, lParam); -} - - -static int -MakeConsole(void) -{ - DWORD err; - int ok = (GetConsoleWindow() != NULL); - if (!ok) { - if (!AttachConsole(ATTACH_PARENT_PROCESS)) { - FreeConsole(); - if (!AllocConsole()) { - err = GetLastError(); - if (err == ERROR_ACCESS_DENIED) { - MessageBox(NULL, "Insufficient rights to create a console window", "Error", MB_ICONERROR); - } - } - AttachConsole(GetCurrentProcessId()); - } - - ok = (GetConsoleWindow() != NULL); - if (ok) { - freopen("CONIN$", "r", stdin); - freopen("CONOUT$", "w", stdout); - freopen("CONOUT$", "w", stderr); - } - } - - if (ok) { - SetConsoleTitle(g_server_name); - } - - return ok; -} - - -int WINAPI -WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR cmdline, int show) -{ - WNDCLASS cls; - HWND hWnd; - MSG msg; - - int i; - int dataLen = 4; - char data[256] = {0}; - char masked_data[256] = {0}; - uint32_t masking_key = 0x01020304; - - for (i = 0; i < dataLen - 3; i += 4) { - *(uint32_t *)(void *)(masked_data + i) = - *(uint32_t *)(void *)(data + i) ^ masking_key; - } - if (i != dataLen) { - /* convert 1-3 remaining bytes */ - i -= 4; - while (i < dataLen) { - *(uint8_t *)(void *)(masked_data + i) = - *(uint8_t *)(void *)(data + i) - ^ *(((uint8_t *)&masking_key) + (i % 4)); - i++; - } - } - -#if 0 - /* http://lomont.org/Math/Papers/2008/Lomont_PRNG_2008.pdf */ - /* initialize state to random bits - */ - static unsigned long state[16]; - /* init should also reset this to 0 */ - static unsigned int index = 0; - /* return 32 bit random number - */ - unsigned long WELLRN G512(void) - { - unsigned long a, b, c, d; - a = state[index]; - c = state[(index + 13) & 15]; - b = a ^ c ^ (a << 16) ^ (c << 15); - c = state[(index + 9) & 15]; - c ^= (c >> 11); - a = state[index] = b ^ c; - d = a ^ ((a << 5) & 0xDA442D24 UL); - index = (index + 15) & 15; - a = state[index]; - state[index] = a ^ b ^ d ^ (a << 2) ^ (b << 18) ^ (c << 28); - return state[index]; - } - - uint32_t x, y, z, w; - - uint32_t xorshift128(void) - { - uint32_t t = x ^ (x << 11); - x = y; - y = z; - z = w; - return w = w ^ (w >> 19) ^ t ^ (t >> 8); - } - - static uint64_t lfsr = 1; - static uint64_t lcg = 0; - uint64_t r = 0; - - do { - lfsr = (lfsr >> 1) - | ((((lfsr >> 0) ^ (lfsr >> 1) ^ (lfsr >> 3) ^ (lfsr >> 4)) & 1) - << 63); - lcg = lcg * 6364136223846793005 + 1442695040888963407; - ++r; - } while (lcg != 0); - - fprintf(stdout, "lfsr = %I64u, lcg = %i64u, r = %i64u\n", lfsr, lcg, r); -#endif - - (void)hInst; - (void)hPrev; - (void)cmdline; - (void)show; - - init_server_name((int)__argc, (const char **)__argv); - memset(&cls, 0, sizeof(cls)); - cls.lpfnWndProc = (WNDPROC)WindowProc; - cls.hIcon = LoadIcon(NULL, IDI_APPLICATION); - cls.lpszClassName = g_server_base_name; - - RegisterClass(&cls); - hWnd = CreateWindow(cls.lpszClassName, g_server_name, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL, NULL, NULL); - ShowWindow(hWnd, SW_HIDE); - - if (g_icon_name) { - hIcon = - LoadImage(NULL, g_icon_name, IMAGE_ICON, 16, 16, LR_LOADFROMFILE); - } else { - hIcon = LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(ID_ICON), IMAGE_ICON, 16, 16, 0); - } - - TrayIcon.cbSize = sizeof(TrayIcon); - TrayIcon.uID = ID_ICON; - TrayIcon.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; - TrayIcon.hIcon = hIcon; - TrayIcon.hWnd = hWnd; - snprintf(TrayIcon.szTip, sizeof(TrayIcon.szTip), "%s", g_server_name); - TrayIcon.uCallbackMessage = WM_USER; - Shell_NotifyIcon(NIM_ADD, &TrayIcon); - - while (GetMessage(&msg, hWnd, 0, 0) > 0) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - /* Return the WM_QUIT value. */ - return (int)msg.wParam; -} - - -int -main(int argc, char *argv[]) -{ - (void)argc; - (void)argv; - - return WinMain(0, 0, 0, 0); -} - - -#elif defined(USE_COCOA) /* GUI */ -#import - -@interface LibHTTP : NSObject -- (void)openBrowser; -- (void)shutDown; -@end - -@implementation LibHTTP -- (void)openBrowser -{ - [[NSWorkspace sharedWorkspace] - openURL:[NSURL URLWithString:[NSString stringWithUTF8String: - get_url_to_first_open_port( - g_ctx)]]]; -} -- (void)editConfig -{ - create_config_file(g_ctx, g_config_file_name); - NSString *path = [NSString stringWithUTF8String:g_config_file_name]; - if (![[NSWorkspace sharedWorkspace] openFile:path - withApplication:@"TextEdit"]) { - NSAlert *alert = [[[NSAlert alloc] init] autorelease]; - [alert setAlertStyle:NSWarningAlertStyle]; - [alert setMessageText:NSLocalizedString(@"Unable to open config file.", - "")]; - [alert setInformativeText:path]; - (void)[alert runModal]; - } -} -- (void)shutDown -{ - [NSApp terminate:nil]; -} -@end - -int -main(int argc, char *argv[]) -{ - init_server_name(argc, (const char **)argv); - start_libhttp(argc, argv); - - [NSAutoreleasePool new]; - [NSApplication sharedApplication]; - - /* Add delegate to process menu item actions */ - LibHTTP *myDelegate = [[LibHTTP alloc] autorelease]; - [NSApp setDelegate:myDelegate]; - - /* Run this app as agent */ - ProcessSerialNumber psn = {0, kCurrentProcess}; - TransformProcessType(&psn, kProcessTransformToBackgroundApplication); - SetFrontProcess(&psn); - - /* Add status bar menu */ - id menu = [[NSMenu new] autorelease]; - - /* Add version menu item */ - [menu - addItem: - [[[NSMenuItem alloc] - /*initWithTitle:[NSString stringWithFormat:@"%s", server_name]*/ - initWithTitle:[NSString stringWithUTF8String:g_server_name] - action:@selector(noexist) - keyEquivalent:@""] autorelease]]; - - /* Add configuration menu item */ - [menu addItem:[[[NSMenuItem alloc] initWithTitle:@"Edit configuration" - action:@selector(editConfig) - keyEquivalent:@""] autorelease]]; - - /* Add connect menu item */ - [menu - addItem:[[[NSMenuItem alloc] initWithTitle:@"Open web root in a browser" - action:@selector(openBrowser) - keyEquivalent:@""] autorelease]]; - - /* Separator */ - [menu addItem:[NSMenuItem separatorItem]]; - - /* Add quit menu item */ - [menu addItem:[[[NSMenuItem alloc] initWithTitle:@"Quit" - action:@selector(shutDown) - keyEquivalent:@"q"] autorelease]]; - - /* Attach menu to the status bar */ - id item = [[[NSStatusBar systemStatusBar] - statusItemWithLength:NSVariableStatusItemLength] retain]; - [item setHighlightMode:YES]; - [item setImage:[NSImage imageNamed:@"civetweb_22x22.png"]]; - [item setMenu:menu]; - - /* Run the app */ - [NSApp activateIgnoringOtherApps:YES]; - [NSApp run]; - - stop_libhttp(); - - return EXIT_SUCCESS; -} - -#else /* GUI */ - -int main( int argc, char *argv[] ) { - - char buf1[1024]; - char buf2[1024]; - - init_server_name( argc, (const char **)argv ); - start_libhttp(argc, argv); - fprintf(stdout, - "%s started on port(s) %s with web root [%s]\n", - g_server_name, - httplib_get_option( g_ctx, "listening_ports", buf1, sizeof(buf1) ), - httplib_get_option( g_ctx, "document_root", buf2, sizeof(buf2) ) ); - while (g_exit_flag == 0) { - sleep(1); - } - fprintf(stdout, - "Exiting on signal %d, waiting for all threads to finish...", - g_exit_flag); - fflush(stdout); - stop_libhttp(); - fprintf(stdout, "%s", " done.\n"); - - return EXIT_SUCCESS; -} -#endif /* GUI / _WIN32 */