Browse Source

Merge pull request #3 from duong2179/patch-3

Added some example code to mg_read.md
duong2179 6 years ago
parent
commit
09f309c0cc

+ 1 - 0
CMakeLists.txt

@@ -35,6 +35,7 @@ set(CIVETWEB_VERSION_MAJOR "${CMAKE_MATCH_1}")
 set(CIVETWEB_VERSION_MINOR "${CMAKE_MATCH_2}")
 set(CIVETWEB_VERSION_PATCH "${CMAKE_MATCH_3}")
 determine_target_architecture(CIVETWEB_ARCHITECTURE)
+include(GNUInstallDirs)
 
 # Detect the platform reliably
 if(NOT MACOSX AND ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")

+ 10 - 1
Makefile

@@ -22,10 +22,11 @@ EXEC_PREFIX = $(PREFIX)
 BINDIR = $(EXEC_PREFIX)/bin
 DATAROOTDIR = $(PREFIX)/share
 DOCDIR = $(DATAROOTDIR)/doc/$(CPROG)
-SYSCONFDIR = $(PREFIX)/etc
+SYSCONFDIR ?= $(PREFIX)/etc
 HTMLDIR = $(DOCDIR)
 INCLUDEDIR = $(DESTDIR)$(PREFIX)/include
 LIBDIR = $(DESTDIR)$(EXEC_PREFIX)/lib
+PID_FILE ?= /var/run/$(CPROG).pid
 
 # build tools
 MKDIR = mkdir -p
@@ -162,6 +163,10 @@ ifdef WITH_SERVER_STATS
   CFLAGS += -DUSE_SERVER_STATS
 endif
 
+ifdef WITH_DAEMONIZE
+  CFLAGS += -DDAEMONIZE -DPID_FILE=\"$(PID_FILE)\"
+endif
+
 # File names
 ifdef CONFIG_FILE
   CFLAGS += -DCONFIG_FILE=\"$(CONFIG_FILE)\"
@@ -239,6 +244,8 @@ help:
 	@echo "   WITH_ZLIB=1           build includes support for on-the-fly compression using zlib"
 	@echo "   WITH_CPP=1            build library with c++ classes"
 	@echo "   WITH_EXPERIMENTAL=1   build with experimental features"
+	@echo "   WITH_DAEMONIZE=1      build with daemonize."
+	@echo "   PID_FILE=/path        PID file path of daemon."
 	@echo "   CONFIG_FILE=file      use 'file' as the config file"
 	@echo "   CONFIG_FILE2=file     use 'file' as the backup config file"
 	@echo "   DOCUMENT_ROOT=/path   document root override when installing"
@@ -332,6 +339,8 @@ distclean: clean
 	$(RMF) $(CPROG) lib$(CPROG).so lib$(CPROG).a *.dmg *.msi *.exe lib$(CPROG).dll lib$(CPROG).dll.a
 	$(RMF) $(UNIT_TEST_PROG)
 
+$(LIB_OBJECTS): CFLAGS += -fPIC
+
 lib$(CPROG).a: CFLAGS += -fPIC
 lib$(CPROG).a: $(LIB_OBJECTS)
 	@$(RMF) $@

+ 0 - 208
Makefile.deprecated

@@ -1,208 +0,0 @@
-# This Makefile is part of Civetweb web server project,
-# https://github.com/valenok/civetweb
-#
-# Example custom build:
-# COPT="-g -O0 -DNO_SSL_DL -DUSE_LUA -llua -lcrypto -lssl" make linux
-#
-# Flags are:
-# -DHAVE_MD5              - use system md5 library (-2kb)
-# -DNDEBUG                - strip off all debug code (-5kb)
-# -DDEBUG                 - build debug version (very noisy) (+7kb)
-# -DNO_CGI                - disable CGI support (-5kb)
-# -DNO_SSL                - disable SSL functionality (-2kb)
-# -DNO_SSL_DL             - link against system libssl library (-1kb)
-# -DCONFIG_FILE=\"file\"  - use `file' as the default config file
-# -DSSL_LIB=\"libssl.so.<version>\"   - use system versioned SSL shared object
-# -DCRYPTO_LIB=\"libcrypto.so.<version>\" - use system versioned CRYPTO so
-# -DUSE_LUA               - embed Lua in Civetweb (+100kb)
-
-PROG        = civetweb
-CFLAGS      = -std=c99 -O2 -W -Wall -pedantic -pthread -pipe -Iinclude $(COPT)
-
-# To build with Lua, download and unzip Lua 5.2.3 source code into the
-# civetweb directory, and then add $(LUA_SOURCES) to CFLAGS
-LUA         = src/third_party/lua-5.2.3/src
-LUA_FLAGS   = -I$(LUA) -DLUA_COMPAT_ALL
-LUA_SOURCES = $(LUA)/lapi.c $(LUA)/lcode.c $(LUA)/lctype.c \
-              $(LUA)/ldebug.c $(LUA)/ldo.c $(LUA)/ldump.c \
-              $(LUA)/lfunc.c $(LUA)/lgc.c $(LUA)/llex.c \
-              $(LUA)/lmem.c $(LUA)/lobject.c $(LUA)/lopcodes.c \
-              $(LUA)/lparser.c $(LUA)/lstate.c $(LUA)/lstring.c \
-              $(LUA)/ltable.c $(LUA)/ltm.c $(LUA)/lundump.c \
-              $(LUA)/lvm.c $(LUA)/lzio.c $(LUA)/lauxlib.c \
-              $(LUA)/lbaselib.c $(LUA)/lbitlib.c $(LUA)/lcorolib.c \
-              $(LUA)/ldblib.c $(LUA)/liolib.c $(LUA)/lmathlib.c \
-              $(LUA)/loslib.c $(LUA)/lstrlib.c $(LUA)/ltablib.c \
-              $(LUA)/loadlib.c $(LUA)/linit.c
-LUA_WINOBJS = $(LUA_SOURCES:%.c=%.obj)
-
-ifneq ($(OS), Windows_NT)
-  LUA_FLAGS += -DLUA_USE_DLOPEN
-endif
-
-LIB_SOURCES = src/civetweb.c
-
-ALL_SOURCES = src/main.c $(LIB_SOURCES) src/third_party/sqlite3.c src/third_party/lsqlite3.c src/third_party/lfs.c \
-              $(LUA_SOURCES) $(YASSL_SOURCES)
-
-SQLITE_FLAGS = -DTHREADSAFE=1 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS
-CIVETWEB_FLAGS = -DUSE_LUA -DUSE_LUA_SQLITE3 -DUSE_LUA_FILE_SYSTEM $(COPT)
-FLAGS = $(CIVETWEB_FLAGS) $(SQLITE_FLAGS) $(LUA_FLAGS)
-
-
-# Stock windows binary builds with Lua. 
-# Yassl has a GPL license, so we will leave it out by default.
-
-ifeq ($(WITH_YASSL), 1)
-YASSL       = ../cyassl-2.4.6
-YASSL_FLAGS = -I $(YASSL) -I $(YASSL)/cyassl \
-              -D _LIB -D OPENSSL_EXTRA -D HAVE_ERRNO_H \
-              -D HAVE_GETHOSTBYNAME -D HAVE_INET_NTOA -D HAVE_LIMITS_H \
-              -D HAVE_MEMSET -D HAVE_SOCKET -D HAVE_STDDEF_H -D HAVE_STDLIB_H \
-              -D HAVE_STRING_H -D HAVE_SYS_STAT_H -D HAVE_SYS_TYPES_H
-YASSL_SOURCES = \
-  $(YASSL)/src/internal.c $(YASSL)/src/io.c $(YASSL)/src/keys.c \
-  $(YASSL)/src/ssl.c $(YASSL)/src/tls.c $(YASSL)/ctaocrypt/src/hmac.c \
-  $(YASSL)/ctaocrypt/src/random.c $(YASSL)/ctaocrypt/src/sha.c \
-  $(YASSL)/ctaocrypt/src/sha256.c $(YASSL)/ctaocrypt/src/logging.c \
-  $(YASSL)/ctaocrypt/src/error.c $(YASSL)/ctaocrypt/src/rsa.c \
-  $(YASSL)/ctaocrypt/src/des3.c $(YASSL)/ctaocrypt/src/asn.c \
-  $(YASSL)/ctaocrypt/src/coding.c $(YASSL)/ctaocrypt/src/arc4.c \
-  $(YASSL)/ctaocrypt/src/md4.c $(YASSL)/ctaocrypt/src/md5.c \
-  $(YASSL)/ctaocrypt/src/dh.c $(YASSL)/ctaocrypt/src/dsa.c \
-  $(YASSL)/ctaocrypt/src/pwdbased.c $(YASSL)/ctaocrypt/src/aes.c \
-  $(YASSL)/ctaocrypt/src/md2.c $(YASSL)/ctaocrypt/src/ripemd.c \
-  $(YASSL)/ctaocrypt/src/sha512.c $(YASSL)/src/sniffer.c \
-  $(YASSL)/ctaocrypt/src/rabbit.c $(YASSL)/ctaocrypt/src/misc.c \
-  $(YASSL)/ctaocrypt/src/tfm.c $(YASSL)/ctaocrypt/src/integer.c \
-  $(YASSL)/ctaocrypt/src/ecc.c $(YASSL)/src/ocsp.c $(YASSL)/src/crl.c \
-  $(YASSL)/ctaocrypt/src/hc128.c $(YASSL)/ctaocrypt/src/memory.c
-  
-  ALL_SOURCES += $(YASSL_SOURCES)
-  FLAGS += $(YASSL_FLAGS) -DNO_SSL_DL
-  CIVETWEB_FLAGS += -DNO_SSL_DL 
-
-else
-#  FLAGS += -DNO_SSL
-#  CIVETWEB_FLAGS += -DNO_SSL 
-endif
-
-ALL_OBJECTS = $(ALL_SOURCES:%.c=%.o)
-ALL_WINOBJS = $(ALL_SOURCES:%.c=%.obj)
-
-
-# Using Visual Studio 6.0. To build Civetweb:
-#  Set MSVC variable below to where VS 6.0 is installed on your system
-#  Run "PATH_TO_VC6\bin\nmake windows"
-MSVC = ../vc6
-#DBG = /Zi /Od
-DBG  = /DNDEBUG /O1
-CL   = $(MSVC)/bin/cl /MD /TC /nologo $(DBG) /W3 /GA /I$(MSVC)/include
-LINK = $(MSVC)/bin/link /incremental:no /libpath:$(MSVC)/lib /machine:IX86 \
-       user32.lib shell32.lib comdlg32.lib ws2_32.lib advapi32.lib
-
-all:
-	@echo "make (linux|bsd|solaris|mac|windows|mingw|cygwin)"
-
-%.obj: %.c
-	$(CL) /c $(FLAGS) /Fo$@ $<
-
-%.o: %.c
-	$(CC) -o $@ $< -c $(FLAGS) $(CFLAGS)
-
-# Lua library for Windows
-lua.lib: $(LUA_WINOBJS)
-	$(MSVC)/bin/lib /out:$@ $(LUA_WINOBJS)
-
-# To build with Lua, make sure you have Lua unpacked into src/third_party/lua-5.2.3 directory
-linux_lua: $(ALL_OBJECTS)
-	$(CC) $(ALL_OBJECTS) -o $(PROG) -ldl
-
-civetweb.o: src/mod_lua.inl
-
-# Make sure that the compiler flags come last in the compilation string.
-# If not so, this can break some on some Linux distros which use
-# "-Wl,--as-needed" turned on by default  in cc command.
-# Also, this is turned in many other distros in static linkage builds.
-linux:
-	$(CC) $(LIB_SOURCES) src/main.c -o $(PROG) -ldl $(CFLAGS)
-
-mac: bsd
-bsd:
-	$(CC) $(LIB_SOURCES) src/main.c -o $(PROG) $(CFLAGS)
-
-bsd_lua: $(ALL_OBJECTS)
-	$(CC) $(ALL_OBJECTS) -o $@
-
-solaris:
-	$(CC) $(LIB_SOURCES) src/main.c -lnsl -lsocket -o $(PROG) $(CFLAGS)
-
-lib$(PROG).a: $(ALL_OBJECTS)
-	ar cr $@ $(ALL_OBJECTS)
-
-$(PROG).lib: $(ALL_WINOBJS)
-	$(MSVC)/bin/lib /out:$@ $(ALL_WINOBJS)
-
-# For codesign to work in non-interactive mode, unlock login keychain:
-# security unlock ~/Library/Keychains/login.keychain
-# See e.g. http://lists.apple.com/archives/apple-cdsa/2008/Jan/msg00027.html
-Civetweb: $(LIB_SOURCES) src/main.c
-	$(CC) $(LIB_SOURCES) src/main.c src/third_party/lsqlite3.c src/third_party/sqlite3.c src/third_party/lfs.c \
-          -DUSE_COCOA $(CFLAGS) $(FLAGS) -mmacosx-version-min=10.4 \
-          $(YASSL_SOURCES) $(LUA_SOURCES) \
-          -framework Cocoa -ObjC -arch i386 -arch x86_64 -o Civetweb
-
-cocoa: Civetweb
-	V=`perl -lne '/define\s+CIVETWEB_VERSION\s+"(\S+)"/ and print $$1' include/civetweb.h`; DIR=dmg/Civetweb.app && rm -rf $$DIR && mkdir -p $$DIR/Contents/{MacOS,Resources} && install -m 644 resources/civetweb_*.png resources/civetweb.icns $$DIR/Contents/Resources/ && install -m 644 resources/Info.plist $$DIR/Contents/ && install -m 755 Civetweb $$DIR/Contents/MacOS/ && ln -fs /Applications dmg/ ; hdiutil create Civetweb_$$V.dmg -volname "Civetweb $$V" -srcfolder dmg -ov #; rm -rf dmg
-
-un:
-	$(CC) test/unit_test.c -o unit_test -I. -I$(LUA) $(LUA_SOURCES) \
-          $(CFLAGS) -g -O0
-	./unit_test
-
-wi:
-	$(CL) test/unit_test.c $(LUA_SOURCES) $(LUA_FLAGS) \
-          $(YASSL_SOURCES) $(YASSL_FLAGS) /I. /DNO_SSL_DL \
-          /link /libpath:$(MSVC)/lib advapi32.lib /out:unit_test.exe
-	./unit_test.exe
-
-windows: $(ALL_WINOBJS)
-	$(MSVC)/bin/rc resources/res.rc
-	$(LINK) /nologo $(ALL_WINOBJS) resources/res.res /out:$(PROG).exe
-
-# Build for Windows under MinGW
-#MINGWDBG= -DDEBUG -O0 -ggdb
-MINGWDBG= -DNDEBUG -Os
-MINGWOPT=  -W -Wall -mthreads -Wl,--subsystem,console $(MINGWDBG) -DHAVE_STDINT $(GCC_WARNINGS) $(COPT)
-mingw:
-	windres resources\res.rc resources\res.o
-	$(CC) $(MINGWOPT) $(LIB_SOURCES) -lws2_32 \
-		-shared -Wl,--out-implib=$(PROG).lib -o $(PROG).dll
-	$(CC) $(MINGWOPT) $(LIB_SOURCES) src/main.c resources\res.o \
-	-lws2_32 -ladvapi32 -lcomdlg32 -o $(PROG).exe
-
-# Build for Windows under Cygwin
-#CYGWINDBG= -DDEBUG -O0 -ggdb
-CYGWINDBG= -DNDEBUG -Os
-CYGWINOPT=  -W -Wall -mthreads -Wl,--subsystem,console $(CYGWINDBG) -DHAVE_STDINT $(GCC_WARNINGS) $(COPT)
-cygwin:
-	windres ./resources/res.rc ./resources/res.o
-	$(CC) $(CYGWINOPT) $(LIB_SOURCES) -lws2_32 \
-		-shared -Wl,--out-implib=$(PROG).lib -o $(PROG).dll
-	$(CC) $(CYGWINOPT) -Iinclude $(LIB_SOURCES) src/main.c ./resources/res.o \
-	-lws2_32 -ladvapi32 -o $(PROG).exe
-
-tests:
-	perl test/test.pl $(TEST)
-
-tarball: clean
-	F=civetweb-`perl -lne '/define\s+CIVETWEB_VERSION\s+"(\S+)"/ and print $$1' include/civetweb.h`.tgz ; cd .. && tar -czf x civetweb/{LICENSE.md,Makefile,examples,test,resources,*.[ch],*.md} && mv x civetweb/$$F
-
-release: tarball cocoa
-	wine make windows
-	V=`perl -lne '/define\s+CIVETWEB_VERSION\s+"(\S+)"/ and print $$1' include/civetweb.h`; upx civetweb.exe; cp civetweb.exe civetweb-$$V.exe; cp civetweb.exe civetweb_php_bundle/; zip -r civetweb_php_bundle_$$V.zip civetweb_php_bundle/
-
-clean:
-	rm -rf *.o *.core $(PROG) *.obj *.so $(PROG).txt *.dSYM *.tgz \
-	$(PROG).exe *.dll *.lib resources/res.o resources/res.RES *.dSYM *.zip *.pdb \
-	*.exe *.dmg $(ALL_OBJECTS) $(ALL_WINOBJS)

+ 24 - 22
docs/UserManual.md

@@ -2,7 +2,7 @@
 Overview
 =====
 
-CivetWeb is small and easy to use web server.
+CivetWeb is a small and easy to use web server.
 It may be embedded into C/C++ host applications or used as a stand-alone
 server. See `Embedding.md` for information on embedding CivetWeb into
 host applications.
@@ -24,26 +24,26 @@ For UNIX and Mac, CivetWeb does not detach from the terminal.
 Pressing `Ctrl-C` keys will stop the server.
 
 On Windows, CivetWeb iconifies itself to the system tray icon when started.
-Right-click on the icon pops up a menu, where it is possible to stop
-CivetWeb, or configure it, or install it as Windows service.
+Right-clicking on the icon pops up a menu, where it is possible to stop
+CivetWeb, configure it, or install it as Windows service.
 
 When started without options, the server exposes the local directory at
 [http](http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol) port 8080.
 Thus, the easiest way to share a folder on Windows is to copy `CivetWeb.exe`
 to this folder, double-click the exe, and launch a browser at
 [http://localhost:8080](http://localhost:8080). Note that 'localhost' should
-be changed to a machine's name if a folder is accessed from other computer.
+be changed to a machine's name if a folder is accessed from another computer.
 
 When started, CivetWeb first searches for the configuration file.
-If configuration file is specified explicitly in the command line, i.e.
-`CivetWeb path_to_config_file`, then specified configuration file is used.
-Otherwise, CivetWeb would search for file `CivetWeb.conf` in the same directory
+If a configuration file is specified explicitly in the command line, i.e.
+`CivetWeb path_to_config_file`, then the specified configuration file is used.
+Otherwise, CivetWeb will search for the file `CivetWeb.conf` in the same directory that
 the executable is located, and use it. This configuration file is optional.
 
 The configuration file is a sequence of lines, each line containing one
 command line argument name and the corresponding value.
 Empty lines, and lines beginning with `#`, are ignored.
-Here is the example of `CivetWeb.conf` file:
+Here is the example of a `CivetWeb.conf` file:
 
     document_root c:\www
     listening_ports 80,443s
@@ -57,7 +57,7 @@ For example: The above `CivetWeb.conf` file is used, and CivetWeb started as
 `CivetWeb -document_root D:\web`. Then the `D:\web` directory will be served
 as document root, because command line options take priority over the
 configuration file. The configuration options section below provides a good
-overview of the CivetWeb features.
+overview of CivetWeb features.
 
 Note that configuration options on the command line must start with `-`,
 but their names are the same as in the config file. All option names are
@@ -109,9 +109,9 @@ The following options are supported in `civetweb.c`. They can be used for
 the stand-alone executable as well as for applications embedding CivetWeb.
 
 ### cgi\_pattern `**.cgi$|**.pl$|**.php$`
-All files that match `cgi_pattern` are treated as CGI files. Default pattern
+All files that match `cgi_pattern` are treated as CGI files. The default pattern
 allows CGI files be anywhere. To restrict CGIs to a certain directory,
-use `/path/to/cgi-bin/**.cgi` as pattern. Note that the full file path is
+use `/path/to/cgi-bin/**.cgi` as the pattern. Note that the full file path is
 matched against the pattern, not the URI.
 
 ### cgi\_environment
@@ -120,8 +120,8 @@ addition to standard ones. The list must be comma-separated list
 of name=value pairs, like this: `VARIABLE1=VALUE1,VARIABLE2=VALUE2`.
 
 ### put\_delete\_auth\_file
-Passwords file for PUT and DELETE requests. Without password file, it will not
-be possible to, PUT new files to the server or DELETE existing ones. PUT and
+Passwords file for PUT and DELETE requests. Without a password file, it will not
+be possible to PUT new files to the server or DELETE existing ones. PUT and
 DELETE requests might still be handled by Lua scripts and CGI paged.
 
 ### cgi\_interpreter
@@ -140,7 +140,7 @@ working directory is the directory where the CivetWeb executable is located.
 
 If all CGIs use the same interpreter, for example they are all PHP, it is
 more efficient to set `cgi_interpreter` to the path to `php-cgi.exe`.
-The  shebang line in the CGI scripts can be omitted in this case.
+The shebang line in the CGI scripts can be omitted in this case.
 Note that PHP scripts must use `php-cgi.exe` as executable, not `php.exe`.
 
 ### protect\_uri
@@ -162,7 +162,7 @@ will be accepted.
 All files that match `ssi_pattern` are treated as Server Side Includes (SSI).
 
 SSI is a simple interpreted server-side scripting language which is most
-commonly used to include the contents of another file into a web page.
+commonly used to include the contents of another file in a web page.
 It can be useful when it is desirable to include a common piece
 of code throughout a website, for example, headers and footers.
 
@@ -279,7 +279,7 @@ To learn more about subnet masks, see the
 [Wikipedia page on Subnetwork](http://en.wikipedia.org/wiki/Subnetwork).
 
 ### extra\_mime\_types
-Extra mime types, in tha form `extension1=type1,exten-sion2=type2,...`.
+Extra mime types, in the form `extension1=type1,exten-sion2=type2,...`.
 See the [Wikipedia page on Internet media types](http://en.wikipedia.org/wiki/Internet_media_type).
 Extension must include a leading dot. Example:
 `.cpp=plain/text,.java=plain/text`
@@ -307,7 +307,7 @@ e.g. `[::1]:8080` for the IPv6 loopback interface.
 all interfaces, both IPv4 and IPv6, use either the configuration
 `80,[::]:80` (create one socket for IPv4 and one for IPv6 only),
 or `+80` (create one socket for both, IPv4 and IPv6). 
-The `+`-notation to use IPv4 and IPv6 will only work in no network
+The `+` notation to use IPv4 and IPv6 will only work if no network
 interface is specified. Depending on your operating system version
 and IPv6 network environment, some configurations might not work
 as expected, so you have to test to find the configuration most 
@@ -484,7 +484,7 @@ script on changes of the server state. See example lua script :
 [background.lua](https://github.com/civetweb/civetweb/blob/master/test/background.lua).
 
 Additional functions available in background script :
-sleep, root path, script name, isterminated
+sleep, root path, script name, is terminated
 
 ### lua\_background\_script\_params `param1=1,param2=2`
 Can add dynamic parameters to background script.
@@ -531,6 +531,8 @@ If set in any other way, the result is unspecified.
 
 ### error\_pages
 This option may be used to specify a directory for user defined error pages.
+To specify a directory, make sure the name ends with a backslash (Windows) 
+or slash (Linux, MacOS, ...).
 The error pages may be specified for an individual http status code (e.g.,
 404 - page requested by the client not found), a group of http status codes
 (e.g., 4xx - all client errors) or all errors. The corresponding error pages
@@ -553,12 +555,12 @@ Set the maximum time (in seconds) a cache may store a static files.
 
 This option will set the `Cache-Control: max-age` value for static files.
 Dynamically generated content, i.e., content created by a script or callback,
-must send cache control headers by themselfes.
+must send cache control headers by themselves.
 
 A value >0 corresponds to a maximum allowed caching time in seconds.
 This value should not exceed one year (RFC 2616, Section 14.21).
 A value of 0 will send "do not cache" headers for all static files.
-For values <0 and values >31622400, the behavior is undefined.
+For values <0 and values >31622400, the behaviour is undefined.
 
 ### strict\_transport\_security\_max\_age
 
@@ -570,7 +572,7 @@ send HTTP headers on their own.
 
 The time is specified in seconds. If this configuration is not set, 
 or set to -1, no `Strict-Transport-Security` header will be sent.
-For values <-1 and values >31622400, the behavior is undefined.
+For values <-1 and values >31622400, the behaviour is undefined.
 
 ### decode\_url `yes`
 URL encoded request strings are decoded in the server, unless it is disabled
@@ -887,7 +889,7 @@ All function are called with one argument of type table with at least one field
 "client" to identify the client. When "open" is called, the argument table additionally
 contains the "request_info" table as defined above. For the "data" handler, an
 additional field "data" is available. The functions "open", "ready" and "data"
-must return true in order to keep the connetion open.
+must return true in order to keep the connection open.
 
 Lua websocket pages do support single shot (timeout) and interval timers.
 

+ 3 - 3
docs/api/mg_init_library.md

@@ -28,7 +28,7 @@ The following parameter values can be used:
 | Value | Compilation option | Description |
 | :---: | :---: | :--- |
 | **1** | NO_FILES | *Able to serve files*.  If this feature is available, the webserver is able to serve files directly from a directory tree. |
-| **2** | NO_SSL | *Support for HTTPS*. If this feature is available, the webserver van use encryption in the client-server connection. SSLv2, SSLv3, TLSv1.0, TLSv1.1 and TLSv1.2 are supported depending on the SSL library CivetWeb has been compiled with, but which protocols are used effectively when the server is running is dependent on the options used when the server is started. |
+| **2** | NO_SSL | *Support for HTTPS*. If this feature is available, the webserver can use encryption in the client-server connection. SSLv2, SSLv3, TLSv1.0, TLSv1.1 and TLSv1.2 are supported depending on the SSL library CivetWeb has been compiled with, but which protocols are used effectively when the server is running is dependent on the options used when the server is started. |
 | **4** | NO_CGI | *Support for CGI*. If this feature is available, external CGI scripts can be called by the webserver. |
 | **8** | USE_IPV6 | *Support IPv6*. The CivetWeb library is capable of communicating over both IPv4 and IPv6, but IPv6 support is only available if it has been enabled at compile time. |
 | **16** | USE_WEBSOCKET | Support for web sockets. WebSockets support is available in the CivetWeb library if the proper options has been used during cimpile time. |
@@ -40,5 +40,5 @@ The parameters can added using bitwise or. Values above 255 are reserved, the be
 
 ### See Also
 
-* [`mg_check_feature( feature );`](api/mg_check_feature.md)
-* [`mg_exit_library( feature );`](api/mg_exit_library.md)
+* [`mg_check_feature( feature );`](mg_check_feature.md)
+* [`mg_exit_library( feature );`](mg_exit_library.md)

+ 27 - 0
docs/api/mg_read.md

@@ -20,6 +20,33 @@
 
 The function `mg_read()` receives data over an existing connection. The data is handled as binary and is stored in a buffer whose address has been provided as a parameter. The function returns the number of read bytes when successful, the value **0** when the connection has been closed by peer and a negative value when no more data could be read from the connection.
 
+### Example
+
+```
+#define RECV_BUF_SIZE 1 << 20
+
+size_t read_data(struct mg_connection* conn,
+                        uint8_t* buff,
+                        size_t buff_len) {
+  size_t read_len = 0;
+  while (read_len < buff_len) {
+    size_t sz_to_read = std::min<size_t>(RECV_BUF_SIZE, buff_len - read_len);
+    int this_read = mg_read(conn, buff + read_len, sz_to_read);
+    if (this_read < 0) {
+      std::cerr << "[error] Failed to read data" << std::endl;
+      break;
+    } else {
+      read_len += size_t(this_read);
+      if (this_read > 0) {
+        std::cout << "[debug] Received " << this_read << " more bytes" << std::endl;
+      }
+    }
+  }
+
+  return read_len;
+}
+```
+
 ### See Also
 
 * [`mg_printf();`](mg_printf.md)

+ 1 - 1
docs/api/mg_send_file_body.md

@@ -16,7 +16,7 @@
 
 ### Description
 
-The function `mg_send_file_file()` sends the contents of a file over a connection to the remote peer without adding any HTTP headers. The code must send all required HTTP response headers before using this function.
+The function `mg_send_file_body()` sends the contents of a file over a connection to the remote peer without adding any HTTP headers. The code must send all required HTTP response headers before using this function.
 
 ### See Also
 

+ 22 - 6
include/CivetServer.h

@@ -14,13 +14,29 @@
 #include <string>
 #include <vector>
 
+#ifndef CIVETWEB_CXX_API
+#if defined(_WIN32)
+#if defined(CIVETWEB_CXX_DLL_EXPORTS)
+#define CIVETWEB_CXX_API __declspec(dllexport)
+#elif defined(CIVETWEB_CXX_DLL_IMPORTS)
+#define CIVETWEB_CXX_API __declspec(dllimport)
+#else
+#define CIVETWEB_CXX_API
+#endif
+#elif __GNUC__ >= 4
+#define CIVETWEB_CXX_API __attribute__((visibility("default")))
+#else
+#define CIVETWEB_CXX_API
+#endif
+#endif
+
 // forward declaration
 class CivetServer;
 
 /**
  * Exception class for thrown exceptions within the CivetHandler object.
  */
-class CIVETWEB_API CivetException : public std::runtime_error
+class CIVETWEB_CXX_API CivetException : public std::runtime_error
 {
   public:
 	CivetException(const std::string &msg) : std::runtime_error(msg)
@@ -32,7 +48,7 @@ class CIVETWEB_API CivetException : public std::runtime_error
  * Basic interface for a URI request handler.  Handlers implementations
  * must be reentrant.
  */
-class CIVETWEB_API CivetHandler
+class CIVETWEB_CXX_API CivetHandler
 {
   public:
 	/**
@@ -110,7 +126,7 @@ class CIVETWEB_API CivetHandler
  * Basic interface for a URI authorization handler.  Handler implementations
  * must be reentrant.
  */
-class CIVETWEB_API CivetAuthHandler
+class CIVETWEB_CXX_API CivetAuthHandler
 {
   public:
 	/**
@@ -135,7 +151,7 @@ class CIVETWEB_API CivetAuthHandler
  * Basic interface for a websocket handler.  Handlers implementations
  * must be reentrant.
  */
-class CIVETWEB_API CivetWebSocketHandler
+class CIVETWEB_CXX_API CivetWebSocketHandler
 {
   public:
 	/**
@@ -197,7 +213,7 @@ class CIVETWEB_API CivetWebSocketHandler
  *
  * wrapper for mg_callbacks
  */
-struct CIVETWEB_API CivetCallbacks : public mg_callbacks {
+struct CIVETWEB_CXX_API CivetCallbacks : public mg_callbacks {
 	CivetCallbacks();
 };
 
@@ -206,7 +222,7 @@ struct CIVETWEB_API CivetCallbacks : public mg_callbacks {
  *
  * Basic class for embedded web server.  This has an URL mapping built-in.
  */
-class CIVETWEB_API CivetServer
+class CIVETWEB_CXX_API CivetServer
 {
   public:
 	/**

+ 19 - 19
src/CMakeLists.txt

@@ -10,20 +10,20 @@ set_target_properties(civetweb-c-library PROPERTIES
   SOVERSION ${CIVETWEB_VERSION}
 )
 if (BUILD_SHARED_LIBS)
-  target_compile_definitions(civetweb-c-library PRIVATE CIVETWEB_DLL_EXPORTS)
+  target_compile_definitions(civetweb-c-library PRIVATE CIVETWEB_DLL_EXPORTS INTERFACE CIVETWEB_DLL_IMPORTS)
 endif()
 target_include_directories(
   civetweb-c-library PUBLIC
   ${PROJECT_SOURCE_DIR}/include)
 install(
   TARGETS civetweb-c-library
-  ARCHIVE DESTINATION lib
-  LIBRARY DESTINATION lib
-  RUNTIME DESTINATION bin
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
   COMPONENT civetweb-c-library)
 install(FILES
   ${PROJECT_SOURCE_DIR}/include/civetweb.h
-  DESTINATION include
+  DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
   COMPONENT civetweb-c-library)
 
 # Need Windows sockets if available
@@ -252,14 +252,11 @@ if (CIVETWEB_ENABLE_SERVER_EXECUTABLE)
     if (CIVETWEB_INSTALL_EXECUTABLE)
         install(
             TARGETS civetweb-c-executable
-            ARCHIVE DESTINATION lib
-            LIBRARY DESTINATION lib
-            RUNTIME DESTINATION bin
+            ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+            LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+            RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
             COMPONENT server)
     endif()
-    if (BUILD_SHARED_LIBS)
-        target_compile_definitions(civetweb-c-executable PRIVATE CIVETWEB_DLL_IMPORTS)
-    endif()
     target_include_directories(
         civetweb-c-executable PUBLIC
         ${PROJECT_SOURCE_DIR}/include)
@@ -281,9 +278,9 @@ if (CIVETWEB_ENABLE_LUA)
     ${PROJECT_SOURCE_DIR}/src/third_party/lua-5.2.4)
   install(
     TARGETS lua-library
-    ARCHIVE DESTINATION lib
-    LIBRARY DESTINATION lib
-    RUNTIME DESTINATION bin
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
     COMPONENT lua-library)
 endif()
 
@@ -296,19 +293,22 @@ if (CIVETWEB_ENABLE_CXX)
     SOVERSION ${CIVETWEB_VERSION}
   )
   if (BUILD_SHARED_LIBS)
-    target_compile_definitions(civetweb-cpp PRIVATE CIVETWEB_DLL_EXPORTS)
+    target_compile_definitions(civetweb-cpp PRIVATE CIVETWEB_CXX_DLL_EXPORTS INTERFACE CIVETWEB_CXX_DLL_IMPORTS)
   endif()
+  target_link_libraries(
+    civetweb-cpp PUBLIC
+	civetweb-c-library)
   target_include_directories(
     civetweb-cpp PUBLIC
     ${PROJECT_SOURCE_DIR}/include)
   install(
     TARGETS civetweb-cpp
-    ARCHIVE DESTINATION lib
-    LIBRARY DESTINATION lib
-    RUNTIME DESTINATION bin
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
     COMPONENT civetweb-cpp)
   install(FILES
     ${PROJECT_SOURCE_DIR}/include/CivetServer.h
-    DESTINATION include
+    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
     COMPONENT civetweb-cpp)
 endif()

+ 1 - 3
src/CivetServer.cpp

@@ -582,9 +582,7 @@ CivetServer::getPostData(struct mg_connection *conn)
 	char buf[2048];
 	int r = mg_read(conn, buf, sizeof(buf));
 	while (r > 0) {
-		std::string p = std::string(buf);
-		p.resize(r);
-		postdata += p;
+		postdata += std::string(buf, r);
 		r = mg_read(conn, buf, sizeof(buf));
 	}
 	mg_unlock_connection(conn);

+ 51 - 31
src/civetweb.c

@@ -740,15 +740,15 @@ typedef struct DIR {
 	struct dirent result;
 } DIR;
 
-#if defined(_WIN32)
-#if !defined(HAVE_POLL)
-struct pollfd {
+#if defined(HAVE_POLL)
+#define mg_pollfd pollfd
+#else
+struct mg_pollfd {
 	SOCKET fd;
 	short events;
 	short revents;
 };
 #endif
-#endif
 
 /* Mark required libraries */
 #if defined(_MSC_VER)
@@ -829,6 +829,8 @@ typedef int SOCKET;
 #define socklen_t int
 #endif /* hpux */
 
+#define mg_pollfd pollfd
+
 #endif /* defined(_WIN32) - WINDOWS vs UNIX include block */
 
 /* Maximum queue length for pending connections. This value is passed as
@@ -2398,6 +2400,9 @@ enum {
 #endif
 	ADDITIONAL_HEADER,
 	ALLOW_INDEX_SCRIPT_SUB_RES,
+#if defined(DAEMONIZE)
+	ENABLE_DAEMONIZE,
+#endif
 
 	NUM_OPTIONS
 };
@@ -2510,6 +2515,9 @@ static const struct mg_option config_options[] = {
 #endif
     {"additional_header", MG_CONFIG_TYPE_STRING_MULTILINE, NULL},
     {"allow_index_script_resource", MG_CONFIG_TYPE_BOOLEAN, "no"},
+#if defined(DAEMONIZE)
+    {"daemonize", MG_CONFIG_TYPE_BOOLEAN, "no"},
+#endif
 
     {NULL, MG_CONFIG_TYPE_UNKNOWN, NULL}};
 
@@ -2598,7 +2606,7 @@ struct mg_context {
 	int context_type; /* See CONTEXT_* above */
 
 	struct socket *listening_sockets;
-	struct pollfd *listening_socket_fds;
+	struct mg_pollfd *listening_socket_fds;
 	unsigned int num_listening_sockets;
 
 	struct mg_connection *worker_connections; /* The connection struct, pre-
@@ -5387,13 +5395,16 @@ mg_readdir(DIR *dir)
 
 
 #if !defined(HAVE_POLL)
+#undef POLLIN
+#undef POLLPRI
+#undef POLLOUT
 #define POLLIN (1)  /* Data ready - read will not block. */
 #define POLLPRI (2) /* Priority data ready. */
 #define POLLOUT (4) /* Send queue not full - write will not block. */
 
 FUNCTION_MAY_BE_UNUSED
 static int
-poll(struct pollfd *pfd, unsigned int n, int milliseconds)
+poll(struct mg_pollfd *pfd, unsigned int n, int milliseconds)
 {
 	struct timeval tv;
 	fd_set rset;
@@ -6062,7 +6073,7 @@ get_random(void)
 
 
 static int
-mg_poll(struct pollfd *pfd,
+mg_poll(struct mg_pollfd *pfd,
         unsigned int n,
         int milliseconds,
         volatile int *stop_server)
@@ -6226,7 +6237,7 @@ push_inner(struct mg_context *ctx,
 			mg_sleep(5);
 		} else {
 			/* For sockets, wait for the socket using poll */
-			struct pollfd pfd[1];
+			struct mg_pollfd pfd[1];
 			int pollres;
 
 			pfd[0].fd = sock;
@@ -6367,7 +6378,7 @@ pull_inner(FILE *fp,
 
 	} else if (conn->ssl != NULL) {
 
-		struct pollfd pfd[1];
+		struct mg_pollfd pfd[1];
 		int pollres;
 
 		pfd[0].fd = conn->client.sock;
@@ -6406,7 +6417,7 @@ pull_inner(FILE *fp,
 #endif
 
 	} else {
-		struct pollfd pfd[1];
+		struct mg_pollfd pfd[1];
 		int pollres;
 
 		pfd[0].fd = conn->client.sock;
@@ -8916,7 +8927,7 @@ connect_socket(struct mg_context *ctx /* may be NULL */,
 #endif
 
 		/* Data for poll */
-		struct pollfd pfd[1];
+		struct mg_pollfd pfd[1];
 		int pollres;
 		int ms_wait = 10000; /* 10 second timeout */
 
@@ -9072,15 +9083,14 @@ print_dir_entry(struct de *de)
 	}
 	mg_url_encode(de->file_name, href, hrefsize);
 	mg_printf(de->conn,
-	          "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
-	          "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
-	          de->conn->request_info.local_uri,
-	          href,
-	          de->file.is_directory ? "/" : "",
-	          de->file_name,
-	          de->file.is_directory ? "/" : "",
-	          mod,
-	          size);
+              "<tr><td><a href=\"%s%s\">%s%s</a></td>"
+              "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
+              href,
+              de->file.is_directory ? "/" : "",
+              de->file_name,
+              de->file.is_directory ? "/" : "",
+              mod,
+              size);
 	mg_free(href);
 	return 0;
 }
@@ -9362,13 +9372,12 @@ handle_directory_request(struct mg_connection *conn, const char *dir)
 
 	/* Print first entry - link to a parent directory */
 	mg_printf(conn,
-	          "<tr><td><a href=\"%s%s\">%s</a></td>"
-	          "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
-	          conn->request_info.local_uri,
-	          "..",
-	          "Parent directory",
-	          "-",
-	          "-");
+              "<tr><td><a href=\"%s\">%s</a></td>"
+              "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
+              "..",
+              "Parent directory",
+              "-",
+              "-");
 
 	/* Sort and print directory entries */
 	if (data.entries != NULL) {
@@ -14466,7 +14475,7 @@ set_ports_option(struct mg_context *phys_ctx)
 	struct vec vec;
 	struct socket so, *ptr;
 
-	struct pollfd *pfd;
+	struct mg_pollfd *pfd;
 	union usa usa;
 	socklen_t len;
 	int ip_version;
@@ -14690,7 +14699,7 @@ set_ports_option(struct mg_context *phys_ctx)
 			continue;
 		}
 
-		if ((pfd = (struct pollfd *)
+		if ((pfd = (struct mg_pollfd *)
 		         mg_realloc_ctx(phys_ctx->listening_socket_fds,
 		                        (phys_ctx->num_listening_sockets + 1)
 		                            * sizeof(phys_ctx->listening_socket_fds[0]),
@@ -15048,6 +15057,7 @@ sslize(struct mg_connection *conn,
 {
 	int ret, err;
 	int short_trust;
+	unsigned timeout = 1024;
 	unsigned i;
 
 	if (!conn) {
@@ -15087,10 +15097,17 @@ sslize(struct mg_connection *conn,
 		}
 	}
 
+	/* Reuse the request timeout for the SSL_Accept/SSL_connect timeout  */
+	if (conn->dom_ctx->config[REQUEST_TIMEOUT]) {
+		/* NOTE: The loop below acts as a back-off, so we can end
+		 * up sleeping for more (or less) than the REQUEST_TIMEOUT. */
+		timeout = atoi(conn->dom_ctx->config[REQUEST_TIMEOUT]);
+	}
+
 	/* SSL functions may fail and require to be called again:
 	 * see https://www.openssl.org/docs/manmaster/ssl/SSL_get_error.html
 	 * Here "func" could be SSL_connect or SSL_accept. */
-	for (i = 16; i <= 1024; i *= 2) {
+	for (i = 16; i <= timeout; i *= 2) {
 		ret = func(conn->ssl);
 		if (ret != 1) {
 			err = SSL_get_error(conn->ssl, ret);
@@ -16928,6 +16945,9 @@ get_request(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
 	/* Message is a valid request */
 
 	/* Is there a "host" ? */
+	if (conn->host != NULL) {
+		mg_free((void *)conn->host);
+	}
 	conn->host = alloc_get_host(conn);
 	if (!conn->host) {
 		mg_snprintf(conn,
@@ -18047,7 +18067,7 @@ master_thread_run(void *thread_func_param)
 {
 	struct mg_context *ctx = (struct mg_context *)thread_func_param;
 	struct mg_workerTLS tls;
-	struct pollfd *pfd;
+	struct mg_pollfd *pfd;
 	unsigned int i;
 	unsigned int workerthreadcount;
 

+ 21 - 21
src/handle_form.inl

@@ -19,7 +19,6 @@
  * THE SOFTWARE.
  */
 
-
 static int
 url_encoded_field_found(const struct mg_connection *conn,
                         const char *key,
@@ -83,7 +82,6 @@ url_encoded_field_found(const struct mg_connection *conn,
 	return ret;
 }
 
-
 static int
 url_encoded_field_get(const struct mg_connection *conn,
                       const char *key,
@@ -121,7 +119,6 @@ url_encoded_field_get(const struct mg_connection *conn,
 	return ret;
 }
 
-
 static int
 unencoded_field_get(const struct mg_connection *conn,
                     const char *key,
@@ -138,7 +135,6 @@ unencoded_field_get(const struct mg_connection *conn,
 	return fdh->field_get(key_dec, value, value_len, fdh->user_data);
 }
 
-
 static int
 field_stored(const struct mg_connection *conn,
              const char *path,
@@ -152,7 +148,6 @@ field_stored(const struct mg_connection *conn,
 	return fdh->field_store(path, file_size, fdh->user_data);
 }
 
-
 static const char *
 search_boundary(const char *buf,
                 size_t buf_len,
@@ -174,7 +169,6 @@ search_boundary(const char *buf,
 	return NULL;
 }
 
-
 int
 mg_handle_form_request(struct mg_connection *conn,
                        struct mg_form_data_handler *fdh)
@@ -384,17 +378,17 @@ mg_handle_form_request(struct mg_connection *conn,
 
 				size_t to_read = sizeof(buf) - 1 - (size_t)buf_fill;
 				r = mg_read(conn, buf + (size_t)buf_fill, to_read);
-				if (r < 0) {
+				if ((r < 0) || ((r == 0) && all_data_read)) {
 					/* read error */
 					return -1;
 				}
-				if (r != (int)to_read) {
+				if (r == 0) {
 					/* TODO: Create a function to get "all_data_read" from
 					 * the conn object. All data is read if the Content-Length
 					 * has been reached, or if chunked encoding is used and
 					 * the end marker has been read, or if the connection has
 					 * been closed. */
-					all_data_read = 1;
+					all_data_read = (buf_fill == 0);
 				}
 				buf_fill += r;
 				buf[buf_fill] = 0;
@@ -507,7 +501,7 @@ mg_handle_form_request(struct mg_connection *conn,
 
 						size_t to_read = sizeof(buf) - 1 - (size_t)buf_fill;
 						r = mg_read(conn, buf + (size_t)buf_fill, to_read);
-						if (r < 0) {
+						if ((r < 0) || ((r == 0) && all_data_read)) {
 							/* read error */
 							if (fstore.access.fp) {
 								mg_fclose(&fstore.access);
@@ -515,13 +509,13 @@ mg_handle_form_request(struct mg_connection *conn,
 							}
 							return -1;
 						}
-						if (r != (int)to_read) {
+						if (r == 0) {
 							/* TODO: Create a function to get "all_data_read"
 							 * from the conn object. All data is read if the
 							 * Content-Length has been reached, or if chunked
 							 * encoding is used and the end marker has been
 							 * read, or if the connection has been closed. */
-							all_data_read = 1;
+							all_data_read = (buf_fill == 0);
 						}
 						buf_fill += r;
 						buf[buf_fill] = 0;
@@ -579,6 +573,7 @@ mg_handle_form_request(struct mg_connection *conn,
 		const char *content_disp, *hend, *fbeg, *fend, *nbeg, *nend;
 		const char *next;
 		unsigned part_no;
+		int all_data_read = 0;
 
 		memset(&part_header, 0, sizeof(part_header));
 
@@ -649,15 +644,18 @@ mg_handle_form_request(struct mg_connection *conn,
 		for (part_no = 0;; part_no++) {
 			size_t towrite, fnlen, n;
 			int get_block;
+			size_t to_read = sizeof(buf) - 1 - (size_t)buf_fill;
 
-			r = mg_read(conn,
-			            buf + (size_t)buf_fill,
-			            sizeof(buf) - 1 - (size_t)buf_fill);
-			if (r < 0) {
+			r = mg_read(conn, buf + (size_t)buf_fill, to_read);
+			if ((r < 0) || ((r == 0) && all_data_read)) {
 				/* read error */
 				mg_free(boundary);
 				return -1;
 			}
+			if (r == 0) {
+				all_data_read = (buf_fill == 0);
+			}
+
 			buf_fill += r;
 			buf[buf_fill] = 0;
 			if (buf_fill < 1) {
@@ -922,10 +920,9 @@ mg_handle_form_request(struct mg_connection *conn,
 				hend = buf;
 
 				/* Read new data */
-				r = mg_read(conn,
-				            buf + (size_t)buf_fill,
-				            sizeof(buf) - 1 - (size_t)buf_fill);
-				if (r < 0) {
+				to_read = sizeof(buf) - 1 - (size_t)buf_fill;
+				r = mg_read(conn, buf + (size_t)buf_fill, to_read);
+				if ((r < 0) || ((r == 0) && all_data_read)) {
 					/* read error */
 					if (fstore.access.fp) {
 						mg_fclose(&fstore.access);
@@ -934,6 +931,10 @@ mg_handle_form_request(struct mg_connection *conn,
 					mg_free(boundary);
 					return -1;
 				}
+				if (r == 0) {
+					all_data_read = (buf_fill == 0);
+				}
+
 				buf_fill += r;
 				buf[buf_fill] = 0;
 				/* buf_fill is at least 8 here */
@@ -1018,5 +1019,4 @@ mg_handle_form_request(struct mg_connection *conn,
 	return -1;
 }
 
-
 /* End of handle_form.inl */

+ 28 - 6
src/main.c

@@ -1327,6 +1327,31 @@ start_civetweb(int argc, char *argv[])
 	signal(SIGTERM, signal_handler);
 	signal(SIGINT, signal_handler);
 
+#if defined(DAEMONIZE)
+	/* Daemonize */
+	for (i = 0; options[i] != NULL; i++) {
+		if (strcmp(options[i], "daemonize") == 0) {
+			if (options[i + 1] != NULL) {
+				if (mg_strcasecmp(options[i + 1], "yes") == 0) {
+					fprintf(stdout, "daemonize.\n");
+					if (daemon(0, 0) != 0) {
+						fprintf(stdout, "Faild to daemonize main process.\n");
+						exit(EXIT_FAILURE);
+					}
+					FILE *fp;
+					if ((fp = fopen(PID_FILE, "w")) == 0) {
+						fprintf(stdout, "Can not open %s.\n", PID_FILE);
+						exit(EXIT_FAILURE);
+					}
+					fprintf(fp, "%d", getpid());
+					fclose(fp);
+				}
+			}
+			break;
+		}
+	}
+#endif
+
 	/* Initialize user data */
 	memset(&g_user_data, 0, sizeof(g_user_data));
 
@@ -2955,15 +2980,13 @@ main(int argc, char *argv[])
 @end
 
 @implementation Civetweb
-- (void)openBrowser
-{
+- (void)openBrowser {
 	[[NSWorkspace sharedWorkspace]
 	    openURL:[NSURL URLWithString:[NSString stringWithUTF8String:
 	                                               get_url_to_first_open_port(
 	                                                   g_ctx)]]];
 }
-- (void)editConfig
-{
+- (void)editConfig {
 	create_config_file(g_ctx, g_config_file_name);
 	NSString *path = [NSString stringWithUTF8String:g_config_file_name];
 	if (![[NSWorkspace sharedWorkspace] openFile:path
@@ -2976,8 +2999,7 @@ main(int argc, char *argv[])
 		(void)[alert runModal];
 	}
 }
-- (void)shutDown
-{
+- (void)shutDown {
 	[NSApp terminate:nil];
 }
 @end

+ 2 - 2
src/mod_lua.inl

@@ -390,7 +390,7 @@ lsp_var_reader(lua_State *L, void *ud, size_t *sz)
 	case 1:
 		/* Second call: forward variable name */
 		ret = reader->begin;
-		*sz = reader->len;
+		*sz = (size_t)reader->len;
 		reader->consumed += reader->len;
 		break;
 	case 2:
@@ -2163,11 +2163,11 @@ prepare_lua_environment(struct mg_context *ctx,
 		reg_conn_function(L, "keep_alive", lsp_keep_alive, conn);
 		reg_conn_function(L, "send_file", lsp_send_file, conn);
 		reg_conn_function(L, "send_file_body", lsp_send_file_body, conn);
+		reg_conn_function(L, "redirect", lsp_redirect, conn);
 	}
 
 	if (lua_env_type == LUA_ENV_TYPE_LUA_SERVER_PAGE) {
 		reg_conn_function(L, "include", lsp_include, conn);
-		reg_conn_function(L, "redirect", lsp_redirect, conn);
 	}
 
 	if (lua_env_type == LUA_ENV_TYPE_LUA_WEBSOCKET) {