Browse Source

# revisions: 32067

git-svn-id: branches/fixes_3_0@33795 -
marco 9 years ago
parent
commit
2077cadc51
33 changed files with 8098 additions and 0 deletions
  1. 30 0
      .gitattributes
  2. 1 0
      packages/fpmake_add.inc
  3. 5 0
      packages/fpmake_proc.inc
  4. 1873 0
      packages/libmicrohttpd/Makefile
  5. 102 0
      packages/libmicrohttpd/Makefile.fpc
  6. 70 0
      packages/libmicrohttpd/examples/basicauthentication.pp
  7. 131 0
      packages/libmicrohttpd/examples/benchmark.pp
  8. 182 0
      packages/libmicrohttpd/examples/benchmark_https.pp
  9. 81 0
      packages/libmicrohttpd/examples/chunked_example.pp
  10. 225 0
      packages/libmicrohttpd/examples/cutils.pas
  11. 811 0
      packages/libmicrohttpd/examples/demo.pp
  12. 865 0
      packages/libmicrohttpd/examples/demo_https.pp
  13. 127 0
      packages/libmicrohttpd/examples/digest_auth_example.pp
  14. 78 0
      packages/libmicrohttpd/examples/dual_stack_example.pp
  15. 115 0
      packages/libmicrohttpd/examples/fileserver_example.pp
  16. 167 0
      packages/libmicrohttpd/examples/fileserver_example_dirs.pp
  17. 146 0
      packages/libmicrohttpd/examples/fileserver_example_external_select.pp
  18. 42 0
      packages/libmicrohttpd/examples/hellobrowser.pp
  19. 194 0
      packages/libmicrohttpd/examples/https_fileserver_example.pp
  20. 187 0
      packages/libmicrohttpd/examples/largepost.pp
  21. 43 0
      packages/libmicrohttpd/examples/logging.pp
  22. 15 0
      packages/libmicrohttpd/examples/magic.inc
  23. 82 0
      packages/libmicrohttpd/examples/minimal_example.pp
  24. 81 0
      packages/libmicrohttpd/examples/minimal_example_comet.pp
  25. 640 0
      packages/libmicrohttpd/examples/post_example.pp
  26. 89 0
      packages/libmicrohttpd/examples/querystring_example.pp
  27. 94 0
      packages/libmicrohttpd/examples/refuse_post_example.pp
  28. 66 0
      packages/libmicrohttpd/examples/responseheaders.pp
  29. 623 0
      packages/libmicrohttpd/examples/sessions.pp
  30. 155 0
      packages/libmicrohttpd/examples/simplepost.pp
  31. 234 0
      packages/libmicrohttpd/examples/tlsauthentication.pp
  32. 59 0
      packages/libmicrohttpd/fpmake.pp
  33. 485 0
      packages/libmicrohttpd/src/libmicrohttpd.pp

+ 30 - 0
.gitattributes

@@ -4996,6 +4996,36 @@ packages/libgd/examples/gdtest.pp svneol=native#text/plain
 packages/libgd/examples/gdtestcgi.pp svneol=native#text/plain
 packages/libgd/examples/gdtestcgi.pp svneol=native#text/plain
 packages/libgd/fpmake.pp svneol=native#text/plain
 packages/libgd/fpmake.pp svneol=native#text/plain
 packages/libgd/src/gd.pas svneol=native#text/plain
 packages/libgd/src/gd.pas svneol=native#text/plain
+packages/libmicrohttpd/Makefile svneol=native#text/plain
+packages/libmicrohttpd/Makefile.fpc svneol=native#text/plain
+packages/libmicrohttpd/examples/basicauthentication.pp svneol=native#text/plain
+packages/libmicrohttpd/examples/benchmark.pp svneol=native#text/plain
+packages/libmicrohttpd/examples/benchmark_https.pp svneol=native#text/plain
+packages/libmicrohttpd/examples/chunked_example.pp svneol=native#text/plain
+packages/libmicrohttpd/examples/cutils.pas svneol=native#text/plain
+packages/libmicrohttpd/examples/demo.pp svneol=native#text/plain
+packages/libmicrohttpd/examples/demo_https.pp svneol=native#text/plain
+packages/libmicrohttpd/examples/digest_auth_example.pp svneol=native#text/plain
+packages/libmicrohttpd/examples/dual_stack_example.pp svneol=native#text/plain
+packages/libmicrohttpd/examples/fileserver_example.pp svneol=native#text/plain
+packages/libmicrohttpd/examples/fileserver_example_dirs.pp svneol=native#text/plain
+packages/libmicrohttpd/examples/fileserver_example_external_select.pp svneol=native#text/plain
+packages/libmicrohttpd/examples/hellobrowser.pp svneol=native#text/plain
+packages/libmicrohttpd/examples/https_fileserver_example.pp svneol=native#text/plain
+packages/libmicrohttpd/examples/largepost.pp svneol=native#text/plain
+packages/libmicrohttpd/examples/logging.pp svneol=native#text/plain
+packages/libmicrohttpd/examples/magic.inc svneol=native#text/plain
+packages/libmicrohttpd/examples/minimal_example.pp svneol=native#text/plain
+packages/libmicrohttpd/examples/minimal_example_comet.pp svneol=native#text/plain
+packages/libmicrohttpd/examples/post_example.pp svneol=native#text/plain
+packages/libmicrohttpd/examples/querystring_example.pp svneol=native#text/plain
+packages/libmicrohttpd/examples/refuse_post_example.pp svneol=native#text/plain
+packages/libmicrohttpd/examples/responseheaders.pp svneol=native#text/plain
+packages/libmicrohttpd/examples/sessions.pp svneol=native#text/plain
+packages/libmicrohttpd/examples/simplepost.pp svneol=native#text/plain
+packages/libmicrohttpd/examples/tlsauthentication.pp svneol=native#text/plain
+packages/libmicrohttpd/fpmake.pp svneol=native#text/plain
+packages/libmicrohttpd/src/libmicrohttpd.pp svneol=native#text/plain
 packages/libndsfpc/Makefile svneol=native#text/plain
 packages/libndsfpc/Makefile svneol=native#text/plain
 packages/libndsfpc/Makefile.fpc svneol=native#text/plain
 packages/libndsfpc/Makefile.fpc svneol=native#text/plain
 packages/libndsfpc/Makefile.fpc.fpcmake svneol=native#text/plain
 packages/libndsfpc/Makefile.fpc.fpcmake svneol=native#text/plain

+ 1 - 0
packages/fpmake_add.inc

@@ -60,6 +60,7 @@
   add_ldap(ADirectory+IncludeTrailingPathDelimiter('ldap'));
   add_ldap(ADirectory+IncludeTrailingPathDelimiter('ldap'));
   add_libc(ADirectory+IncludeTrailingPathDelimiter('libc'));
   add_libc(ADirectory+IncludeTrailingPathDelimiter('libc'));
   add_libcurl(ADirectory+IncludeTrailingPathDelimiter('libcurl'));
   add_libcurl(ADirectory+IncludeTrailingPathDelimiter('libcurl'));
+  add_libmicrohttpd(ADirectory+IncludeTrailingPathDelimiter('libmicrohttpd'));
   add_libgbafpc(ADirectory+IncludeTrailingPathDelimiter('libgbafpc'));
   add_libgbafpc(ADirectory+IncludeTrailingPathDelimiter('libgbafpc'));
   add_libgd(ADirectory+IncludeTrailingPathDelimiter('libgd'));
   add_libgd(ADirectory+IncludeTrailingPathDelimiter('libgd'));
   add_libndsfpc(ADirectory+IncludeTrailingPathDelimiter('libndsfpc'));
   add_libndsfpc(ADirectory+IncludeTrailingPathDelimiter('libndsfpc'));

+ 5 - 0
packages/fpmake_proc.inc

@@ -403,6 +403,11 @@ begin
   with Installer do
   with Installer do
 {$include libvlc/fpmake.pp}
 {$include libvlc/fpmake.pp}
 end;
 end;
+procedure add_libmicrohttpd(const ADirectory: string);
+begin
+  with Installer do
+{$include libmicrohttpd/fpmake.pp}
+end;
 
 
 procedure add_libxml(const ADirectory: string);
 procedure add_libxml(const ADirectory: string);
 begin
 begin

+ 1873 - 0
packages/libmicrohttpd/Makefile

@@ -0,0 +1,1873 @@
+#
+# Don't edit, this file is generated by FPCMake Version 2.0.0 [2015-09-05 rev 31523]
+#
+default: all
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-qnx i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-freebsd m68k-netbsd m68k-amiga m68k-atari m68k-openbsd m68k-palmos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-aros x86_64-dragonfly arm-linux arm-palmos arm-darwin arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android jvm-java jvm-android i8086-msdos i8086-win16 aarch64-linux aarch64-darwin
+BSDs = freebsd netbsd openbsd darwin dragonfly
+UNIXs = linux $(BSDs) solaris qnx haiku aix
+LIMIT83fs = go32v2 os2 emx watcom msdos win16
+OSNeedsComspecToRunBatch = go32v2 watcom
+FORCE:
+.PHONY: FORCE
+override PATH:=$(patsubst %/,%,$(subst \,/,$(PATH)))
+ifneq ($(findstring darwin,$(OSTYPE)),)
+inUnix=1 #darwin
+SEARCHPATH:=$(filter-out .,$(subst :, ,$(PATH)))
+else
+ifeq ($(findstring ;,$(PATH)),)
+inUnix=1
+SEARCHPATH:=$(filter-out .,$(subst :, ,$(PATH)))
+else
+SEARCHPATH:=$(subst ;, ,$(PATH))
+endif
+endif
+SEARCHPATH+=$(patsubst %/,%,$(subst \,/,$(dir $(MAKE))))
+PWD:=$(strip $(wildcard $(addsuffix /pwd.exe,$(SEARCHPATH))))
+ifeq ($(PWD),)
+PWD:=$(strip $(wildcard $(addsuffix /pwd,$(SEARCHPATH))))
+ifeq ($(PWD),)
+$(error You need the GNU utils package to use this Makefile)
+else
+PWD:=$(firstword $(PWD))
+SRCEXEEXT=
+endif
+else
+PWD:=$(firstword $(PWD))
+SRCEXEEXT=.exe
+endif
+ifndef inUnix
+ifeq ($(OS),Windows_NT)
+inWinNT=1
+else
+ifdef OS2_SHELL
+inOS2=1
+endif
+endif
+else
+ifneq ($(findstring cygdrive,$(PATH)),)
+inCygWin=1
+endif
+endif
+ifdef inUnix
+SRCBATCHEXT=.sh
+else
+ifdef inOS2
+SRCBATCHEXT=.cmd
+else
+SRCBATCHEXT=.bat
+endif
+endif
+ifdef COMSPEC
+ifneq ($(findstring $(OS_SOURCE),$(OSNeedsComspecToRunBatch)),)
+ifndef RUNBATCH
+RUNBATCH=$(COMSPEC) /C
+endif
+endif
+endif
+ifdef inUnix
+PATHSEP=/
+else
+PATHSEP:=$(subst /,\,/)
+ifdef inCygWin
+PATHSEP=/
+endif
+endif
+ifdef PWD
+BASEDIR:=$(subst \,/,$(shell $(PWD)))
+ifdef inCygWin
+ifneq ($(findstring /cygdrive/,$(BASEDIR)),)
+BASENODIR:=$(patsubst /cygdrive%,%,$(BASEDIR))
+BASEDRIVE:=$(firstword $(subst /, ,$(BASENODIR)))
+BASEDIR:=$(subst /cygdrive/$(BASEDRIVE)/,$(BASEDRIVE):/,$(BASEDIR))
+endif
+endif
+else
+BASEDIR=.
+endif
+ifdef inOS2
+ifndef ECHO
+ECHO:=$(strip $(wildcard $(addsuffix /gecho$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO:=$(strip $(wildcard $(addsuffix /echo$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO=echo
+else
+ECHO:=$(firstword $(ECHO))
+endif
+else
+ECHO:=$(firstword $(ECHO))
+endif
+endif
+export ECHO
+endif
+override DEFAULT_FPCDIR=../..
+ifndef FPC
+ifdef PP
+FPC=$(PP)
+endif
+endif
+ifndef FPC
+FPCPROG:=$(strip $(wildcard $(addsuffix /fpc$(SRCEXEEXT),$(SEARCHPATH))))
+ifneq ($(FPCPROG),)
+FPCPROG:=$(firstword $(FPCPROG))
+ifneq ($(CPU_TARGET),)
+FPC:=$(shell $(FPCPROG) -P$(CPU_TARGET) -PB)
+else
+FPC:=$(shell $(FPCPROG) -PB)
+endif
+ifneq ($(findstring Error,$(FPC)),)
+override FPC=$(firstword $(strip $(wildcard $(addsuffix /ppc386$(SRCEXEEXT),$(SEARCHPATH)))))
+else
+ifeq ($(strip $(wildcard $(FPC))),)
+FPC:=$(firstword $(FPCPROG))
+endif
+endif
+else
+override FPC=$(firstword $(strip $(wildcard $(addsuffix /ppc386$(SRCEXEEXT),$(SEARCHPATH)))))
+endif
+endif
+override FPC:=$(subst $(SRCEXEEXT),,$(FPC))
+override FPC:=$(subst \,/,$(FPC))$(SRCEXEEXT)
+FOUNDFPC:=$(strip $(wildcard $(FPC)))
+ifeq ($(FOUNDFPC),)
+FOUNDFPC=$(strip $(wildcard $(addsuffix /$(FPC),$(SEARCHPATH))))
+ifeq ($(FOUNDFPC),)
+$(error Compiler $(FPC) not found)
+endif
+endif
+ifndef FPC_COMPILERINFO
+FPC_COMPILERINFO:=$(shell $(FPC) -iVSPTPSOTO)
+endif
+ifndef FPC_VERSION
+FPC_VERSION:=$(word 1,$(FPC_COMPILERINFO))
+endif
+export FPC FPC_VERSION FPC_COMPILERINFO
+unexport CHECKDEPEND ALLDEPENDENCIES
+ifndef CPU_TARGET
+ifdef CPU_TARGET_DEFAULT
+CPU_TARGET=$(CPU_TARGET_DEFAULT)
+endif
+endif
+ifndef OS_TARGET
+ifdef OS_TARGET_DEFAULT
+OS_TARGET=$(OS_TARGET_DEFAULT)
+endif
+endif
+ifndef CPU_SOURCE
+CPU_SOURCE:=$(word 2,$(FPC_COMPILERINFO))
+endif
+ifndef CPU_TARGET
+CPU_TARGET:=$(word 3,$(FPC_COMPILERINFO))
+endif
+ifndef OS_SOURCE
+OS_SOURCE:=$(word 4,$(FPC_COMPILERINFO))
+endif
+ifndef OS_TARGET
+OS_TARGET:=$(word 5,$(FPC_COMPILERINFO))
+endif
+FULL_TARGET=$(CPU_TARGET)-$(OS_TARGET)
+FULL_SOURCE=$(CPU_SOURCE)-$(OS_SOURCE)
+ifeq ($(CPU_TARGET),armeb)
+ARCH=arm
+override FPCOPT+=-Cb
+else
+ifeq ($(CPU_TARGET),armel)
+ARCH=arm
+override FPCOPT+=-CaEABI
+else
+ARCH=$(CPU_TARGET)
+endif
+endif
+ifeq ($(FULL_TARGET),arm-embedded)
+ifeq ($(SUBARCH),)
+$(error When compiling for arm-embedded, a sub-architecture (e.g. SUBARCH=armv4t or SUBARCH=armv7m) must be defined)
+endif
+override FPCOPT+=-Cp$(SUBARCH)
+endif
+ifeq ($(FULL_TARGET),avr-embedded)
+ifeq ($(SUBARCH),)
+$(error When compiling for avr-embedded, a sub-architecture (e.g. SUBARCH=avr25 or SUBARCH=avr35) must be defined)
+endif
+override FPCOPT+=-Cp$(SUBARCH)
+endif
+ifeq ($(FULL_TARGET),mipsel-embedded)
+ifeq ($(SUBARCH),)
+$(error When compiling for mipsel-embedded, a sub-architecture (e.g. SUBARCH=pic32mx) must be defined)
+endif
+override FPCOPT+=-Cp$(SUBARCH)
+endif
+ifneq ($(findstring $(OS_SOURCE),$(LIMIT83fs)),)
+TARGETSUFFIX=$(OS_TARGET)
+SOURCESUFFIX=$(OS_SOURCE)
+else
+ifneq ($(findstring $(OS_TARGET),$(LIMIT83fs)),)
+TARGETSUFFIX=$(OS_TARGET)
+else
+TARGETSUFFIX=$(FULL_TARGET)
+endif
+SOURCESUFFIX=$(FULL_SOURCE)
+endif
+ifneq ($(FULL_TARGET),$(FULL_SOURCE))
+CROSSCOMPILE=1
+endif
+ifeq ($(findstring makefile,$(MAKECMDGOALS)),)
+ifeq ($(findstring $(FULL_TARGET),$(MAKEFILETARGETS)),)
+$(error The Makefile doesn't support target $(FULL_TARGET), please run fpcmake first)
+endif
+endif
+ifneq ($(findstring $(OS_TARGET),$(BSDs)),)
+BSDhier=1
+endif
+ifeq ($(OS_TARGET),linux)
+linuxHier=1
+endif
+ifndef CROSSCOMPILE
+BUILDFULLNATIVE=1
+export BUILDFULLNATIVE
+endif
+ifdef BUILDFULLNATIVE
+BUILDNATIVE=1
+export BUILDNATIVE
+endif
+export OS_TARGET OS_SOURCE ARCH CPU_TARGET CPU_SOURCE FULL_TARGET FULL_SOURCE TARGETSUFFIX SOURCESUFFIX CROSSCOMPILE
+ifdef FPCDIR
+override FPCDIR:=$(subst \,/,$(FPCDIR))
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),)
+override FPCDIR=wrong
+endif
+else
+override FPCDIR=wrong
+endif
+ifdef DEFAULT_FPCDIR
+ifeq ($(FPCDIR),wrong)
+override FPCDIR:=$(subst \,/,$(DEFAULT_FPCDIR))
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),)
+override FPCDIR=wrong
+endif
+endif
+endif
+ifeq ($(FPCDIR),wrong)
+ifdef inUnix
+override FPCDIR=/usr/local/lib/fpc/$(FPC_VERSION)
+ifeq ($(wildcard $(FPCDIR)/units),)
+override FPCDIR=/usr/lib/fpc/$(FPC_VERSION)
+endif
+else
+override FPCDIR:=$(subst /$(FPC),,$(firstword $(strip $(wildcard $(addsuffix /$(FPC),$(SEARCHPATH))))))
+override FPCDIR:=$(FPCDIR)/..
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),)
+override FPCDIR:=$(FPCDIR)/..
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),)
+override FPCDIR:=$(BASEDIR)
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),)
+override FPCDIR=c:/pp
+endif
+endif
+endif
+endif
+endif
+ifndef CROSSBINDIR
+CROSSBINDIR:=$(wildcard $(FPCDIR)/bin/$(TARGETSUFFIX))
+endif
+ifneq ($(findstring $(OS_TARGET),darwin iphonesim),)
+ifeq ($(OS_SOURCE),darwin)
+DARWIN2DARWIN=1
+endif
+endif
+ifndef BINUTILSPREFIX
+ifndef CROSSBINDIR
+ifdef CROSSCOMPILE
+ifneq ($(OS_TARGET),msdos)
+ifndef DARWIN2DARWIN
+ifneq ($(CPU_TARGET),jvm)
+BINUTILSPREFIX=$(CPU_TARGET)-$(OS_TARGET)-
+ifeq ($(OS_TARGET),android)
+ifeq ($(CPU_TARGET),arm)
+BINUTILSPREFIX=arm-linux-androideabi-
+else
+ifeq ($(CPU_TARGET),i386)
+BINUTILSPREFIX=i686-linux-android-
+else
+ifeq ($(CPU_TARGET),mipsel)
+BINUTILSPREFIX=mipsel-linux-android-
+endif
+endif
+endif
+endif
+endif
+endif
+else
+BINUTILSPREFIX=$(OS_TARGET)-
+endif
+endif
+endif
+endif
+UNITSDIR:=$(wildcard $(FPCDIR)/units/$(TARGETSUFFIX))
+ifeq ($(UNITSDIR),)
+UNITSDIR:=$(wildcard $(FPCDIR)/units/$(OS_TARGET))
+endif
+PACKAGESDIR:=$(wildcard $(FPCDIR) $(FPCDIR)/packages $(FPCDIR)/packages/base $(FPCDIR)/packages/extra)
+ifndef FPCFPMAKE
+ifdef CROSSCOMPILE
+ifeq ($(strip $(wildcard $(addsuffix /compiler/ppc$(SRCEXEEXT),$(FPCDIR)))),)
+FPCPROG:=$(strip $(wildcard $(addsuffix /fpc$(SRCEXEEXT),$(SEARCHPATH))))
+ifneq ($(FPCPROG),)
+FPCPROG:=$(firstword $(FPCPROG))
+FPCFPMAKE:=$(shell $(FPCPROG) -PB)
+ifeq ($(strip $(wildcard $(FPCFPMAKE))),)
+FPCFPMAKE:=$(firstword $(FPCPROG))
+endif
+else
+override FPCFPMAKE=$(firstword $(strip $(wildcard $(addsuffix /ppc386$(SRCEXEEXT),$(SEARCHPATH)))))
+endif
+else
+FPCFPMAKE=$(strip $(wildcard $(addsuffix /compiler/ppc$(SRCEXEEXT),$(FPCDIR))))
+FPMAKE_SKIP_CONFIG=-n
+export FPCFPMAKE
+export FPMAKE_SKIP_CONFIG
+endif
+else
+FPMAKE_SKIP_CONFIG=-n
+FPCFPMAKE=$(FPC)
+endif
+endif
+override PACKAGE_NAME=libmicrohttpd
+override PACKAGE_VERSION=3.1.1
+FPMAKE_BIN_CLEAN=$(wildcard ./fpmake$(SRCEXEEXT))
+ifdef OS_TARGET
+FPC_TARGETOPT+=--os=$(OS_TARGET)
+endif
+ifdef CPU_TARGET
+FPC_TARGETOPT+=--cpu=$(CPU_TARGET)
+endif
+LOCALFPMAKE=./fpmake$(SRCEXEEXT)
+override INSTALL_FPCPACKAGE=y
+ifdef REQUIRE_UNITSDIR
+override UNITSDIR+=$(REQUIRE_UNITSDIR)
+endif
+ifdef REQUIRE_PACKAGESDIR
+override PACKAGESDIR+=$(REQUIRE_PACKAGESDIR)
+endif
+ifdef ZIPINSTALL
+ifneq ($(findstring $(OS_TARGET),$(UNIXs)),)
+UNIXHier=1
+endif
+else
+ifneq ($(findstring $(OS_SOURCE),$(UNIXs)),)
+UNIXHier=1
+endif
+endif
+ifndef INSTALL_PREFIX
+ifdef PREFIX
+INSTALL_PREFIX=$(PREFIX)
+endif
+endif
+ifndef INSTALL_PREFIX
+ifdef UNIXHier
+INSTALL_PREFIX=/usr/local
+else
+ifdef INSTALL_FPCPACKAGE
+INSTALL_BASEDIR:=/pp
+else
+INSTALL_BASEDIR:=/$(PACKAGE_NAME)
+endif
+endif
+endif
+export INSTALL_PREFIX
+ifdef INSTALL_FPCSUBDIR
+export INSTALL_FPCSUBDIR
+endif
+ifndef DIST_DESTDIR
+DIST_DESTDIR:=$(BASEDIR)
+endif
+export DIST_DESTDIR
+ifndef COMPILER_UNITTARGETDIR
+ifdef PACKAGEDIR_MAIN
+COMPILER_UNITTARGETDIR=$(PACKAGEDIR_MAIN)/units/$(TARGETSUFFIX)
+else
+COMPILER_UNITTARGETDIR=units/$(TARGETSUFFIX)
+endif
+endif
+ifndef COMPILER_TARGETDIR
+COMPILER_TARGETDIR=.
+endif
+ifndef INSTALL_BASEDIR
+ifdef UNIXHier
+ifdef INSTALL_FPCPACKAGE
+INSTALL_BASEDIR:=$(INSTALL_PREFIX)/lib/fpc/$(FPC_VERSION)
+else
+INSTALL_BASEDIR:=$(INSTALL_PREFIX)/lib/$(PACKAGE_NAME)
+endif
+else
+INSTALL_BASEDIR:=$(INSTALL_PREFIX)
+endif
+endif
+ifndef INSTALL_BINDIR
+ifdef UNIXHier
+INSTALL_BINDIR:=$(INSTALL_PREFIX)/bin
+else
+INSTALL_BINDIR:=$(INSTALL_BASEDIR)/bin
+ifdef INSTALL_FPCPACKAGE
+ifdef CROSSCOMPILE
+ifdef CROSSINSTALL
+INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(SOURCESUFFIX)
+else
+INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(TARGETSUFFIX)
+endif
+else
+INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(TARGETSUFFIX)
+endif
+endif
+endif
+endif
+ifndef INSTALL_UNITDIR
+INSTALL_UNITDIR:=$(INSTALL_BASEDIR)/units/$(TARGETSUFFIX)
+ifdef INSTALL_FPCPACKAGE
+ifdef PACKAGE_NAME
+INSTALL_UNITDIR:=$(INSTALL_UNITDIR)/$(PACKAGE_NAME)
+endif
+endif
+endif
+ifndef INSTALL_LIBDIR
+ifdef UNIXHier
+INSTALL_LIBDIR:=$(INSTALL_PREFIX)/lib
+else
+INSTALL_LIBDIR:=$(INSTALL_UNITDIR)
+endif
+endif
+ifndef INSTALL_SOURCEDIR
+ifdef UNIXHier
+ifdef BSDhier
+SRCPREFIXDIR=share/src
+else
+ifdef linuxHier
+SRCPREFIXDIR=share/src
+else
+SRCPREFIXDIR=src
+endif
+endif
+ifdef INSTALL_FPCPACKAGE
+ifdef INSTALL_FPCSUBDIR
+INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/fpc-$(FPC_VERSION)/$(INSTALL_FPCSUBDIR)/$(PACKAGE_NAME)
+else
+INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/fpc-$(FPC_VERSION)/$(PACKAGE_NAME)
+endif
+else
+INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+endif
+else
+ifdef INSTALL_FPCPACKAGE
+ifdef INSTALL_FPCSUBDIR
+INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source/$(INSTALL_FPCSUBDIR)/$(PACKAGE_NAME)
+else
+INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source/$(PACKAGE_NAME)
+endif
+else
+INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source
+endif
+endif
+endif
+ifndef INSTALL_DOCDIR
+ifdef UNIXHier
+ifdef BSDhier
+DOCPREFIXDIR=share/doc
+else
+ifdef linuxHier
+DOCPREFIXDIR=share/doc
+else
+DOCPREFIXDIR=doc
+endif
+endif
+ifdef INSTALL_FPCPACKAGE
+INSTALL_DOCDIR:=$(INSTALL_PREFIX)/$(DOCPREFIXDIR)/fpc-$(FPC_VERSION)/$(PACKAGE_NAME)
+else
+INSTALL_DOCDIR:=$(INSTALL_PREFIX)/$(DOCPREFIXDIR)/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+endif
+else
+ifdef INSTALL_FPCPACKAGE
+INSTALL_DOCDIR:=$(INSTALL_BASEDIR)/doc/$(PACKAGE_NAME)
+else
+INSTALL_DOCDIR:=$(INSTALL_BASEDIR)/doc
+endif
+endif
+endif
+ifndef INSTALL_EXAMPLEDIR
+ifdef UNIXHier
+ifdef INSTALL_FPCPACKAGE
+ifdef BSDhier
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/share/examples/fpc-$(FPC_VERSION)/$(PACKAGE_NAME)
+else
+ifdef linuxHier
+INSTALL_EXAMPLEDIR:=$(INSTALL_DOCDIR)/examples
+else
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/doc/fpc-$(FPC_VERSION)/examples/$(PACKAGE_NAME)
+endif
+endif
+else
+ifdef BSDhier
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/share/examples/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+else
+ifdef linuxHier
+INSTALL_EXAMPLEDIR:=$(INSTALL_DOCDIR)/examples/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+else
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/doc/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+endif
+endif
+endif
+else
+ifdef INSTALL_FPCPACKAGE
+INSTALL_EXAMPLEDIR:=$(INSTALL_BASEDIR)/examples/$(PACKAGE_NAME)
+else
+INSTALL_EXAMPLEDIR:=$(INSTALL_BASEDIR)/examples
+endif
+endif
+endif
+ifndef INSTALL_DATADIR
+INSTALL_DATADIR=$(INSTALL_BASEDIR)
+endif
+ifndef INSTALL_SHAREDDIR
+INSTALL_SHAREDDIR=$(INSTALL_PREFIX)/lib
+endif
+ifdef CROSSCOMPILE
+ifndef CROSSBINDIR
+CROSSBINDIR:=$(wildcard $(CROSSTARGETDIR)/bin/$(SOURCESUFFIX))
+ifeq ($(CROSSBINDIR),)
+CROSSBINDIR:=$(wildcard $(INSTALL_BASEDIR)/cross/$(TARGETSUFFIX)/bin/$(FULL_SOURCE))
+endif
+endif
+else
+CROSSBINDIR=
+endif
+BATCHEXT=.bat
+LOADEREXT=.as
+EXEEXT=.exe
+PPLEXT=.ppl
+PPUEXT=.ppu
+OEXT=.o
+ASMEXT=.s
+SMARTEXT=.sl
+STATICLIBEXT=.a
+SHAREDLIBEXT=.so
+SHAREDLIBPREFIX=libfp
+STATICLIBPREFIX=libp
+IMPORTLIBPREFIX=libimp
+RSTEXT=.rst
+EXEDBGEXT=.dbg
+ifeq ($(OS_TARGET),go32v1)
+STATICLIBPREFIX=
+SHORTSUFFIX=v1
+endif
+ifeq ($(OS_TARGET),go32v2)
+STATICLIBPREFIX=
+SHORTSUFFIX=dos
+IMPORTLIBPREFIX=
+endif
+ifeq ($(OS_TARGET),watcom)
+STATICLIBPREFIX=
+OEXT=.obj
+ASMEXT=.asm
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=wat
+IMPORTLIBPREFIX=
+endif
+ifneq ($(CPU_TARGET),jvm)
+ifeq ($(OS_TARGET),android)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=lnx
+endif
+endif
+ifeq ($(OS_TARGET),linux)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=lnx
+endif
+ifeq ($(OS_TARGET),dragonfly)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=df
+endif
+ifeq ($(OS_TARGET),freebsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=fbs
+endif
+ifeq ($(OS_TARGET),netbsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=nbs
+endif
+ifeq ($(OS_TARGET),openbsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=obs
+endif
+ifeq ($(OS_TARGET),win32)
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=w32
+endif
+ifeq ($(OS_TARGET),os2)
+BATCHEXT=.cmd
+AOUTEXT=.out
+STATICLIBPREFIX=
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=os2
+ECHO=echo
+IMPORTLIBPREFIX=
+endif
+ifeq ($(OS_TARGET),emx)
+BATCHEXT=.cmd
+AOUTEXT=.out
+STATICLIBPREFIX=
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=emx
+ECHO=echo
+IMPORTLIBPREFIX=
+endif
+ifeq ($(OS_TARGET),amiga)
+EXEEXT=
+SHAREDLIBEXT=.library
+SHORTSUFFIX=amg
+endif
+ifeq ($(OS_TARGET),aros)
+EXEEXT=
+SHAREDLIBEXT=.library
+SHORTSUFFIX=aros
+endif
+ifeq ($(OS_TARGET),morphos)
+EXEEXT=
+SHAREDLIBEXT=.library
+SHORTSUFFIX=mos
+endif
+ifeq ($(OS_TARGET),atari)
+EXEEXT=.ttp
+SHORTSUFFIX=ata
+endif
+ifeq ($(OS_TARGET),beos)
+BATCHEXT=.sh
+EXEEXT=
+SHORTSUFFIX=be
+endif
+ifeq ($(OS_TARGET),haiku)
+BATCHEXT=.sh
+EXEEXT=
+SHORTSUFFIX=hai
+endif
+ifeq ($(OS_TARGET),solaris)
+BATCHEXT=.sh
+EXEEXT=
+SHORTSUFFIX=sun
+endif
+ifeq ($(OS_TARGET),qnx)
+BATCHEXT=.sh
+EXEEXT=
+SHORTSUFFIX=qnx
+endif
+ifeq ($(OS_TARGET),netware)
+EXEEXT=.nlm
+STATICLIBPREFIX=
+SHORTSUFFIX=nw
+IMPORTLIBPREFIX=imp
+endif
+ifeq ($(OS_TARGET),netwlibc)
+EXEEXT=.nlm
+STATICLIBPREFIX=
+SHORTSUFFIX=nwl
+IMPORTLIBPREFIX=imp
+endif
+ifeq ($(OS_TARGET),macos)
+BATCHEXT=
+EXEEXT=
+DEBUGSYMEXT=.xcoff
+SHORTSUFFIX=mac
+IMPORTLIBPREFIX=imp
+endif
+ifneq ($(findstring $(OS_TARGET),darwin iphonesim),)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=dwn
+EXEDBGEXT=.dSYM
+endif
+ifeq ($(OS_TARGET),gba)
+EXEEXT=.gba
+SHAREDLIBEXT=.so
+SHORTSUFFIX=gba
+endif
+ifeq ($(OS_TARGET),symbian)
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=symbian
+endif
+ifeq ($(OS_TARGET),NativeNT)
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=nativent
+endif
+ifeq ($(OS_TARGET),wii)
+EXEEXT=.dol
+SHAREDLIBEXT=.so
+SHORTSUFFIX=wii
+endif
+ifeq ($(OS_TARGET),aix)
+BATCHEXT=.sh
+EXEEXT=
+SHORTSUFFIX=aix
+endif
+ifeq ($(OS_TARGET),java)
+OEXT=.class
+ASMEXT=.j
+SHAREDLIBEXT=.jar
+SHORTSUFFIX=java
+endif
+ifeq ($(CPU_TARGET),jvm)
+ifeq ($(OS_TARGET),android)
+OEXT=.class
+ASMEXT=.j
+SHAREDLIBEXT=.jar
+SHORTSUFFIX=android
+endif
+endif
+ifeq ($(OS_TARGET),msdos)
+STATICLIBPREFIX=
+STATICLIBEXT=.a
+SHORTSUFFIX=d16
+endif
+ifeq ($(OS_TARGET),embedded)
+EXEEXT=.bin
+SHORTSUFFIX=emb
+endif
+ifeq ($(OS_TARGET),win16)
+STATICLIBPREFIX=
+STATICLIBEXT=.a
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=w16
+endif
+ifneq ($(findstring $(OS_SOURCE),$(LIMIT83fs)),)
+FPCMADE=fpcmade.$(SHORTSUFFIX)
+ZIPSUFFIX=$(SHORTSUFFIX)
+ZIPCROSSPREFIX=
+ZIPSOURCESUFFIX=src
+ZIPEXAMPLESUFFIX=exm
+else
+FPCMADE=fpcmade.$(TARGETSUFFIX)
+ZIPSOURCESUFFIX=.source
+ZIPEXAMPLESUFFIX=.examples
+ifdef CROSSCOMPILE
+ZIPSUFFIX=.$(SOURCESUFFIX)
+ZIPCROSSPREFIX=$(TARGETSUFFIX)-
+else
+ZIPSUFFIX=.$(TARGETSUFFIX)
+ZIPCROSSPREFIX=
+endif
+endif
+ifndef ECHO
+ECHO:=$(strip $(wildcard $(addsuffix /gecho$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO:=$(strip $(wildcard $(addsuffix /echo$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO= __missing_command_ECHO
+else
+ECHO:=$(firstword $(ECHO))
+endif
+else
+ECHO:=$(firstword $(ECHO))
+endif
+endif
+export ECHO
+ifndef DATE
+DATE:=$(strip $(wildcard $(addsuffix /gdate$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(DATE),)
+DATE:=$(strip $(wildcard $(addsuffix /date$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(DATE),)
+DATE= __missing_command_DATE
+else
+DATE:=$(firstword $(DATE))
+endif
+else
+DATE:=$(firstword $(DATE))
+endif
+endif
+export DATE
+ifndef GINSTALL
+GINSTALL:=$(strip $(wildcard $(addsuffix /ginstall$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(GINSTALL),)
+GINSTALL:=$(strip $(wildcard $(addsuffix /install$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(GINSTALL),)
+GINSTALL= __missing_command_GINSTALL
+else
+GINSTALL:=$(firstword $(GINSTALL))
+endif
+else
+GINSTALL:=$(firstword $(GINSTALL))
+endif
+endif
+export GINSTALL
+ifndef CPPROG
+CPPROG:=$(strip $(wildcard $(addsuffix /cp$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(CPPROG),)
+CPPROG= __missing_command_CPPROG
+else
+CPPROG:=$(firstword $(CPPROG))
+endif
+endif
+export CPPROG
+ifndef RMPROG
+RMPROG:=$(strip $(wildcard $(addsuffix /rm$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(RMPROG),)
+RMPROG= __missing_command_RMPROG
+else
+RMPROG:=$(firstword $(RMPROG))
+endif
+endif
+export RMPROG
+ifndef MVPROG
+MVPROG:=$(strip $(wildcard $(addsuffix /mv$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(MVPROG),)
+MVPROG= __missing_command_MVPROG
+else
+MVPROG:=$(firstword $(MVPROG))
+endif
+endif
+export MVPROG
+ifndef MKDIRPROG
+MKDIRPROG:=$(strip $(wildcard $(addsuffix /gmkdir$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(MKDIRPROG),)
+MKDIRPROG:=$(strip $(wildcard $(addsuffix /mkdir$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(MKDIRPROG),)
+MKDIRPROG= __missing_command_MKDIRPROG
+else
+MKDIRPROG:=$(firstword $(MKDIRPROG))
+endif
+else
+MKDIRPROG:=$(firstword $(MKDIRPROG))
+endif
+endif
+export MKDIRPROG
+ifndef ECHOREDIR
+ifndef inUnix
+ECHOREDIR=echo
+else
+ECHOREDIR=$(ECHO)
+endif
+endif
+ifndef COPY
+COPY:=$(CPPROG) -fp
+endif
+ifndef COPYTREE
+COPYTREE:=$(CPPROG) -Rfp
+endif
+ifndef MKDIRTREE
+MKDIRTREE:=$(MKDIRPROG) -p
+endif
+ifndef MOVE
+MOVE:=$(MVPROG) -f
+endif
+ifndef DEL
+DEL:=$(RMPROG) -f
+endif
+ifndef DELTREE
+DELTREE:=$(RMPROG) -rf
+endif
+ifndef INSTALL
+ifdef inUnix
+INSTALL:=$(GINSTALL) -c -m 644
+else
+INSTALL:=$(COPY)
+endif
+endif
+ifndef INSTALLEXE
+ifdef inUnix
+INSTALLEXE:=$(GINSTALL) -c -m 755
+else
+INSTALLEXE:=$(COPY)
+endif
+endif
+ifndef MKDIR
+MKDIR:=$(GINSTALL) -m 755 -d
+endif
+export ECHOREDIR COPY COPYTREE MOVE DEL DELTREE INSTALL INSTALLEXE MKDIR
+ifndef PPUMOVE
+PPUMOVE:=$(strip $(wildcard $(addsuffix /ppumove$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(PPUMOVE),)
+PPUMOVE= __missing_command_PPUMOVE
+else
+PPUMOVE:=$(firstword $(PPUMOVE))
+endif
+endif
+export PPUMOVE
+ifndef FPCMAKE
+FPCMAKE:=$(strip $(wildcard $(addsuffix /fpcmake$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(FPCMAKE),)
+FPCMAKE= __missing_command_FPCMAKE
+else
+FPCMAKE:=$(firstword $(FPCMAKE))
+endif
+endif
+export FPCMAKE
+ifndef ZIPPROG
+ZIPPROG:=$(strip $(wildcard $(addsuffix /zip$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ZIPPROG),)
+ZIPPROG= __missing_command_ZIPPROG
+else
+ZIPPROG:=$(firstword $(ZIPPROG))
+endif
+endif
+export ZIPPROG
+ifndef TARPROG
+TARPROG:=$(strip $(wildcard $(addsuffix /gtar$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(TARPROG),)
+TARPROG:=$(strip $(wildcard $(addsuffix /tar$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(TARPROG),)
+TARPROG= __missing_command_TARPROG
+else
+TARPROG:=$(firstword $(TARPROG))
+endif
+else
+TARPROG:=$(firstword $(TARPROG))
+endif
+endif
+export TARPROG
+ASNAME=$(BINUTILSPREFIX)as
+LDNAME=$(BINUTILSPREFIX)ld
+ARNAME=$(BINUTILSPREFIX)ar
+RCNAME=$(BINUTILSPREFIX)rc
+NASMNAME=$(BINUTILSPREFIX)nasm
+ifndef ASPROG
+ifdef CROSSBINDIR
+ASPROG=$(CROSSBINDIR)/$(ASNAME)$(SRCEXEEXT)
+else
+ASPROG=$(ASNAME)
+endif
+endif
+ifndef LDPROG
+ifdef CROSSBINDIR
+LDPROG=$(CROSSBINDIR)/$(LDNAME)$(SRCEXEEXT)
+else
+LDPROG=$(LDNAME)
+endif
+endif
+ifndef RCPROG
+ifdef CROSSBINDIR
+RCPROG=$(CROSSBINDIR)/$(RCNAME)$(SRCEXEEXT)
+else
+RCPROG=$(RCNAME)
+endif
+endif
+ifndef ARPROG
+ifdef CROSSBINDIR
+ARPROG=$(CROSSBINDIR)/$(ARNAME)$(SRCEXEEXT)
+else
+ARPROG=$(ARNAME)
+endif
+endif
+ifndef NASMPROG
+ifdef CROSSBINDIR
+NASMPROG=$(CROSSBINDIR)/$(NASMNAME)$(SRCEXEEXT)
+else
+NASMPROG=$(NASMNAME)
+endif
+endif
+AS=$(ASPROG)
+LD=$(LDPROG)
+RC=$(RCPROG)
+AR=$(ARPROG)
+NASM=$(NASMPROG)
+ifdef inUnix
+PPAS=./ppas$(SRCBATCHEXT)
+else
+PPAS=ppas$(SRCBATCHEXT)
+endif
+ifdef inUnix
+LDCONFIG=ldconfig
+else
+LDCONFIG=
+endif
+ifdef DATE
+DATESTR:=$(shell $(DATE) +%Y%m%d)
+else
+DATESTR=
+endif
+ZIPOPT=-9
+ZIPEXT=.zip
+ifeq ($(USETAR),bz2)
+TAROPT=vj
+TAREXT=.tar.bz2
+else
+TAROPT=vz
+TAREXT=.tar.gz
+endif
+override REQUIRE_PACKAGES=rtl
+ifeq ($(FULL_TARGET),i386-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-go32v2)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-win32)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-os2)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-freebsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-beos)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-haiku)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-netbsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-solaris)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-qnx)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-netware)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-openbsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-wdosx)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-darwin)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-emx)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-watcom)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-netwlibc)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-wince)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-symbian)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-nativent)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-iphonesim)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-android)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-aros)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),m68k-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),m68k-freebsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),m68k-netbsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),m68k-amiga)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),m68k-atari)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),m68k-openbsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),m68k-palmos)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),m68k-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc-netbsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc-amiga)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc-macos)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc-darwin)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc-morphos)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc-wii)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc-aix)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),sparc-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),sparc-netbsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),sparc-solaris)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),sparc-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),x86_64-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),x86_64-freebsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),x86_64-netbsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),x86_64-solaris)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),x86_64-openbsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),x86_64-darwin)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),x86_64-win64)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),x86_64-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),x86_64-iphonesim)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),x86_64-aros)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),x86_64-dragonfly)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),arm-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),arm-palmos)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),arm-darwin)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),arm-wince)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),arm-gba)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),arm-nds)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),arm-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),arm-symbian)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),arm-android)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc64-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc64-darwin)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc64-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc64-aix)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),avr-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),armeb-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),armeb-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),mips-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),mipsel-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),mipsel-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),mipsel-android)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),jvm-java)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),jvm-android)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i8086-msdos)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i8086-win16)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),aarch64-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),aarch64-darwin)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifdef REQUIRE_PACKAGES_RTL
+PACKAGEDIR_RTL:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /rtl/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_RTL),)
+ifneq ($(wildcard $(PACKAGEDIR_RTL)/units/$(TARGETSUFFIX)),)
+UNITDIR_RTL=$(PACKAGEDIR_RTL)/units/$(TARGETSUFFIX)
+else
+UNITDIR_RTL=$(PACKAGEDIR_RTL)
+endif
+ifneq ($(wildcard $(PACKAGEDIR_RTL)/units/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_RTL=$(PACKAGEDIR_RTL)/units/$(SOURCESUFFIX)
+else
+ifneq ($(wildcard $(PACKAGEDIR_RTL)/units_bs/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_RTL=$(PACKAGEDIR_RTL)/units_bs/$(SOURCESUFFIX)
+else
+UNITDIR_FPMAKE_RTL=$(PACKAGEDIR_RTL)
+endif
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_RTL)/$(OS_TARGET)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_RTL)/$(OS_TARGET) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_RTL)/$(OS_TARGET)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_RTL=
+UNITDIR_RTL:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /rtl/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_RTL),)
+UNITDIR_RTL:=$(firstword $(UNITDIR_RTL))
+else
+UNITDIR_RTL=
+endif
+endif
+ifdef UNITDIR_RTL
+override COMPILER_UNITDIR+=$(UNITDIR_RTL)
+endif
+ifdef UNITDIR_FPMAKE_RTL
+override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_RTL)
+endif
+endif
+ifndef NOCPUDEF
+override FPCOPTDEF=$(ARCH)
+endif
+ifneq ($(OS_TARGET),$(OS_SOURCE))
+override FPCOPT+=-T$(OS_TARGET)
+endif
+ifneq ($(CPU_TARGET),$(CPU_SOURCE))
+override FPCOPT+=-P$(ARCH)
+endif
+ifeq ($(OS_SOURCE),openbsd)
+override FPCOPT+=-FD$(NEW_BINUTILS_PATH)
+override FPCMAKEOPT+=-FD$(NEW_BINUTILS_PATH)
+override FPMAKE_BUILD_OPT+=-FD$(NEW_BINUTILS_PATH)
+endif
+ifndef CROSSBOOTSTRAP
+ifneq ($(BINUTILSPREFIX),)
+override FPCOPT+=-XP$(BINUTILSPREFIX)
+endif
+ifneq ($(BINUTILSPREFIX),)
+override FPCOPT+=-Xr$(RLINKPATH)
+endif
+endif
+ifndef CROSSCOMPILE
+ifneq ($(BINUTILSPREFIX),)
+override FPCMAKEOPT+=-XP$(BINUTILSPREFIX)
+override FPMAKE_BUILD_OPT+=-XP$(BINUTILSPREFIX)
+endif
+endif
+ifdef UNITDIR
+override FPCOPT+=$(addprefix -Fu,$(UNITDIR))
+endif
+ifdef LIBDIR
+override FPCOPT+=$(addprefix -Fl,$(LIBDIR))
+endif
+ifdef OBJDIR
+override FPCOPT+=$(addprefix -Fo,$(OBJDIR))
+endif
+ifdef INCDIR
+override FPCOPT+=$(addprefix -Fi,$(INCDIR))
+endif
+ifdef LINKSMART
+override FPCOPT+=-XX
+endif
+ifdef CREATESMART
+override FPCOPT+=-CX
+endif
+ifdef DEBUG
+override FPCOPT+=-gl
+override FPCOPTDEF+=DEBUG
+endif
+ifdef RELEASE
+ifneq ($(findstring 2.0.,$(FPC_VERSION)),)
+ifeq ($(CPU_TARGET),i386)
+FPCCPUOPT:=-OG2p3
+endif
+ifeq ($(CPU_TARGET),powerpc)
+FPCCPUOPT:=-O1r
+endif
+else
+FPCCPUOPT:=-O2
+endif
+override FPCOPT+=-Ur -Xs $(FPCCPUOPT) -n
+override FPCOPTDEF+=RELEASE
+endif
+ifdef STRIP
+override FPCOPT+=-Xs
+endif
+ifdef OPTIMIZE
+override FPCOPT+=-O2
+endif
+ifdef VERBOSE
+override FPCOPT+=-vwni
+endif
+ifdef COMPILER_OPTIONS
+override FPCOPT+=$(COMPILER_OPTIONS)
+endif
+ifdef COMPILER_UNITDIR
+override FPCOPT+=$(addprefix -Fu,$(COMPILER_UNITDIR))
+endif
+ifdef COMPILER_LIBRARYDIR
+override FPCOPT+=$(addprefix -Fl,$(COMPILER_LIBRARYDIR))
+endif
+ifdef COMPILER_OBJECTDIR
+override FPCOPT+=$(addprefix -Fo,$(COMPILER_OBJECTDIR))
+endif
+ifdef COMPILER_INCLUDEDIR
+override FPCOPT+=$(addprefix -Fi,$(COMPILER_INCLUDEDIR))
+endif
+ifdef CROSSBINDIR
+override FPCOPT+=-FD$(CROSSBINDIR)
+endif
+ifdef COMPILER_TARGETDIR
+override FPCOPT+=-FE$(COMPILER_TARGETDIR)
+ifeq ($(COMPILER_TARGETDIR),.)
+override TARGETDIRPREFIX=
+else
+override TARGETDIRPREFIX=$(COMPILER_TARGETDIR)/
+endif
+endif
+ifdef COMPILER_UNITTARGETDIR
+override FPCOPT+=-FU$(COMPILER_UNITTARGETDIR)
+ifeq ($(COMPILER_UNITTARGETDIR),.)
+override UNITTARGETDIRPREFIX=
+else
+override UNITTARGETDIRPREFIX=$(COMPILER_UNITTARGETDIR)/
+endif
+else
+ifdef COMPILER_TARGETDIR
+override COMPILER_UNITTARGETDIR=$(COMPILER_TARGETDIR)
+override UNITTARGETDIRPREFIX=$(TARGETDIRPREFIX)
+endif
+endif
+ifdef CREATESHARED
+override FPCOPT+=-Cg
+endif
+ifneq ($(findstring $(OS_TARGET),dragonfly freebsd openbsd netbsd linux solaris),)
+ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel),)
+override FPCOPT+=-Cg
+endif
+endif
+ifdef LINKSHARED
+endif
+ifdef OPT
+override FPCOPT+=$(OPT)
+endif
+ifdef FPMAKEBUILDOPT
+override FPMAKE_BUILD_OPT+=$(FPMAKEBUILDOPT)
+endif
+ifdef FPCOPTDEF
+override FPCOPT+=$(addprefix -d,$(FPCOPTDEF))
+endif
+ifdef CFGFILE
+override FPCOPT+=@$(CFGFILE)
+endif
+ifdef USEENV
+override FPCEXTCMD:=$(FPCOPT)
+override FPCOPT:=!FPCEXTCMD
+export FPCEXTCMD
+endif
+override AFULL_TARGET=$(CPU_TARGET)-$(OS_TARGET)
+override AFULL_SOURCE=$(CPU_SOURCE)-$(OS_SOURCE)
+ifneq ($(AFULL_TARGET),$(AFULL_SOURCE))
+override ACROSSCOMPILE=1
+endif
+ifdef ACROSSCOMPILE
+override FPCOPT+=$(CROSSOPT)
+endif
+override COMPILER:=$(strip $(FPC) $(FPCOPT))
+ifneq (,$(findstring -sh ,$(COMPILER)))
+UseEXECPPAS=1
+endif
+ifneq (,$(findstring -s ,$(COMPILER)))
+ifeq ($(FULL_SOURCE),$(FULL_TARGET))
+UseEXECPPAS=1
+endif
+endif
+ifneq ($(UseEXECPPAS),1)
+EXECPPAS=
+else
+ifdef RUNBATCH
+EXECPPAS:=@$(RUNBATCH) $(PPAS)
+else
+EXECPPAS:=@$(PPAS)
+endif
+endif
+ifdef TARGET_RSTS
+override RSTFILES=$(addsuffix $(RSTEXT),$(TARGET_RSTS))
+override CLEANRSTFILES+=$(RSTFILES)
+endif
+.PHONY: fpc_install fpc_sourceinstall fpc_exampleinstall
+ifdef INSTALL_UNITS
+override INSTALLPPUFILES+=$(addsuffix $(PPUEXT),$(INSTALL_UNITS))
+endif
+ifdef INSTALL_BUILDUNIT
+override INSTALLPPUFILES:=$(filter-out $(INSTALL_BUILDUNIT)$(PPUEXT),$(INSTALLPPUFILES))
+endif
+ifdef INSTALLPPUFILES
+override INSTALLPPULINKFILES:=$(subst $(PPUEXT),$(OEXT),$(INSTALLPPUFILES)) $(addprefix $(STATICLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(INSTALLPPUFILES))) $(addprefix $(IMPORTLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(INSTALLPPUFILES)))
+ifneq ($(UNITTARGETDIRPREFIX),)
+override INSTALLPPUFILES:=$(addprefix $(UNITTARGETDIRPREFIX),$(notdir $(INSTALLPPUFILES)))
+override INSTALLPPULINKFILES:=$(wildcard $(addprefix $(UNITTARGETDIRPREFIX),$(notdir $(INSTALLPPULINKFILES))))
+endif
+override INSTALL_CREATEPACKAGEFPC=1
+endif
+ifdef INSTALLEXEFILES
+ifneq ($(TARGETDIRPREFIX),)
+override INSTALLEXEFILES:=$(addprefix $(TARGETDIRPREFIX),$(notdir $(INSTALLEXEFILES)))
+endif
+endif
+fpc_install: all $(INSTALLTARGET)
+ifdef INSTALLEXEFILES
+	$(MKDIR) $(INSTALL_BINDIR)
+	$(INSTALLEXE) $(INSTALLEXEFILES) $(INSTALL_BINDIR)
+endif
+ifdef INSTALL_CREATEPACKAGEFPC
+ifdef FPCMAKE
+ifdef PACKAGE_VERSION
+ifneq ($(wildcard Makefile.fpc),)
+	$(FPCMAKE) -p -T$(CPU_TARGET)-$(OS_TARGET) Makefile.fpc
+	$(MKDIR) $(INSTALL_UNITDIR)
+	$(INSTALL) Package.fpc $(INSTALL_UNITDIR)
+endif
+endif
+endif
+endif
+ifdef INSTALLPPUFILES
+	$(MKDIR) $(INSTALL_UNITDIR)
+	$(INSTALL) $(INSTALLPPUFILES) $(INSTALL_UNITDIR)
+ifneq ($(INSTALLPPULINKFILES),)
+	$(INSTALL) $(INSTALLPPULINKFILES) $(INSTALL_UNITDIR)
+endif
+ifneq ($(wildcard $(LIB_FULLNAME)),)
+	$(MKDIR) $(INSTALL_LIBDIR)
+	$(INSTALL) $(LIB_FULLNAME) $(INSTALL_LIBDIR)
+ifdef inUnix
+	ln -sf $(LIB_FULLNAME) $(INSTALL_LIBDIR)/$(LIB_NAME)
+endif
+endif
+endif
+ifdef INSTALL_FILES
+	$(MKDIR) $(INSTALL_DATADIR)
+	$(INSTALL) $(INSTALL_FILES) $(INSTALL_DATADIR)
+endif
+fpc_sourceinstall: distclean
+	$(MKDIR) $(INSTALL_SOURCEDIR)
+	$(COPYTREE) $(BASEDIR)/* $(INSTALL_SOURCEDIR)
+fpc_exampleinstall: $(EXAMPLEINSTALLTARGET) $(addsuffix _distclean,$(TARGET_EXAMPLEDIRS))
+ifdef HASEXAMPLES
+	$(MKDIR) $(INSTALL_EXAMPLEDIR)
+endif
+ifdef EXAMPLESOURCEFILES
+	$(COPY) $(EXAMPLESOURCEFILES) $(INSTALL_EXAMPLEDIR)
+endif
+ifdef TARGET_EXAMPLEDIRS
+	$(COPYTREE) $(addsuffix /*,$(TARGET_EXAMPLEDIRS)) $(INSTALL_EXAMPLEDIR)
+endif
+.PHONY: fpc_distinstall
+fpc_distinstall: install exampleinstall
+.PHONY: fpc_zipinstall fpc_zipsourceinstall fpc_zipexampleinstall
+ifndef PACKDIR
+ifndef inUnix
+PACKDIR=$(BASEDIR)/../fpc-pack
+else
+PACKDIR=/tmp/fpc-pack
+endif
+endif
+ifndef ZIPNAME
+ifdef DIST_ZIPNAME
+ZIPNAME=$(DIST_ZIPNAME)
+else
+ZIPNAME=$(PACKAGE_NAME)
+endif
+endif
+ifndef FULLZIPNAME
+FULLZIPNAME=$(ZIPCROSSPREFIX)$(ZIPPREFIX)$(ZIPNAME)$(ZIPSUFFIX)
+endif
+ifndef ZIPTARGET
+ifdef DIST_ZIPTARGET
+ZIPTARGET=DIST_ZIPTARGET
+else
+ZIPTARGET=install
+endif
+endif
+ifndef USEZIP
+ifdef inUnix
+USETAR=1
+endif
+endif
+ifndef inUnix
+USEZIPWRAPPER=1
+endif
+ifdef USEZIPWRAPPER
+ZIPPATHSEP=$(PATHSEP)
+ZIPWRAPPER=$(subst /,$(PATHSEP),$(DIST_DESTDIR)/fpczip$(SRCBATCHEXT))
+else
+ZIPPATHSEP=/
+endif
+ZIPCMD_CDPACK:=cd $(subst /,$(ZIPPATHSEP),$(PACKDIR))
+ZIPCMD_CDBASE:=cd $(subst /,$(ZIPPATHSEP),$(BASEDIR))
+ifdef USETAR
+ZIPDESTFILE:=$(DIST_DESTDIR)/$(FULLZIPNAME)$(TAREXT)
+ZIPCMD_ZIP:=$(TARPROG) c$(TAROPT)f $(ZIPDESTFILE) *
+else
+ZIPDESTFILE:=$(DIST_DESTDIR)/$(FULLZIPNAME)$(ZIPEXT)
+ZIPCMD_ZIP:=$(subst /,$(ZIPPATHSEP),$(ZIPPROG)) -Dr $(ZIPOPT) $(ZIPDESTFILE) *
+endif
+fpc_zipinstall:
+	$(MAKE) $(ZIPTARGET) INSTALL_PREFIX=$(PACKDIR) ZIPINSTALL=1
+	$(MKDIR) $(DIST_DESTDIR)
+	$(DEL) $(ZIPDESTFILE)
+ifdef USEZIPWRAPPER
+ifneq ($(ECHOREDIR),echo)
+	$(ECHOREDIR) -e "$(subst \,\\,$(ZIPCMD_CDPACK))" > $(ZIPWRAPPER)
+	$(ECHOREDIR) -e "$(subst \,\\,$(ZIPCMD_ZIP))" >> $(ZIPWRAPPER)
+	$(ECHOREDIR) -e "$(subst \,\\,$(ZIPCMD_CDBASE))" >> $(ZIPWRAPPER)
+else
+	echo $(ZIPCMD_CDPACK) > $(ZIPWRAPPER)
+	echo $(ZIPCMD_ZIP) >> $(ZIPWRAPPER)
+	echo $(ZIPCMD_CDBASE) >> $(ZIPWRAPPER)
+endif
+ifdef inUnix
+	/bin/sh $(ZIPWRAPPER)
+else
+ifdef RUNBATCH
+	$(RUNBATCH) $(ZIPWRAPPER)
+else
+	$(ZIPWRAPPER)
+endif
+endif
+	$(DEL) $(ZIPWRAPPER)
+else
+	$(ZIPCMD_CDPACK) ; $(ZIPCMD_ZIP) ; $(ZIPCMD_CDBASE)
+endif
+	$(DELTREE) $(PACKDIR)
+fpc_zipsourceinstall:
+	$(MAKE) fpc_zipinstall ZIPTARGET=sourceinstall ZIPSUFFIX=$(ZIPSOURCESUFFIX)
+fpc_zipexampleinstall:
+ifdef HASEXAMPLES
+	$(MAKE) fpc_zipinstall ZIPTARGET=exampleinstall ZIPSUFFIX=$(ZIPEXAMPLESUFFIX)
+endif
+fpc_zipdistinstall:
+	$(MAKE) fpc_zipinstall ZIPTARGET=distinstall
+.PHONY: fpc_clean fpc_cleanall fpc_distclean
+ifdef EXEFILES
+override CLEANEXEFILES:=$(addprefix $(TARGETDIRPREFIX),$(CLEANEXEFILES))
+override CLEANEXEDBGFILES:=$(addprefix $(TARGETDIRPREFIX),$(CLEANEXEDBGFILES))
+endif
+ifdef CLEAN_PROGRAMS
+override CLEANEXEFILES+=$(addprefix $(TARGETDIRPREFIX),$(addsuffix $(EXEEXT), $(CLEAN_PROGRAMS)))
+override CLEANEXEDBGFILES+=$(addprefix $(TARGETDIRPREFIX),$(addsuffix $(EXEDBGEXT), $(CLEAN_PROGRAMS)))
+endif
+ifdef CLEAN_UNITS
+override CLEANPPUFILES+=$(addsuffix $(PPUEXT),$(CLEAN_UNITS))
+endif
+ifdef CLEANPPUFILES
+override CLEANPPULINKFILES:=$(subst $(PPUEXT),$(OEXT),$(CLEANPPUFILES)) $(addprefix $(STATICLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(CLEANPPUFILES))) $(addprefix $(IMPORTLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(CLEANPPUFILES)))
+ifdef DEBUGSYMEXT
+override CLEANPPULINKFILES+=$(subst $(PPUEXT),$(DEBUGSYMEXT),$(CLEANPPUFILES))
+endif
+override CLEANPPUFILES:=$(addprefix $(UNITTARGETDIRPREFIX),$(CLEANPPUFILES))
+override CLEANPPULINKFILES:=$(wildcard $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANPPULINKFILES)))
+endif
+fpc_clean: $(CLEANTARGET)
+ifdef CLEANEXEFILES
+	-$(DEL) $(CLEANEXEFILES)
+endif
+ifdef CLEANEXEDBGFILES
+	-$(DELTREE) $(CLEANEXEDBGFILES)
+endif
+ifdef CLEANPPUFILES
+	-$(DEL) $(CLEANPPUFILES)
+endif
+ifneq ($(CLEANPPULINKFILES),)
+	-$(DEL) $(CLEANPPULINKFILES)
+endif
+ifdef CLEANRSTFILES
+	-$(DEL) $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANRSTFILES))
+endif
+ifdef CLEAN_FILES
+	-$(DEL) $(CLEAN_FILES)
+endif
+ifdef LIB_NAME
+	-$(DEL) $(LIB_NAME) $(LIB_FULLNAME)
+endif
+	-$(DEL) $(FPCMADE) Package.fpc $(PPAS) script.res link.res $(FPCEXTFILE) $(REDIRFILE)
+	-$(DEL) *$(ASMEXT) *_ppas$(BATCHEXT)
+fpc_cleanall: $(CLEANTARGET)
+ifdef CLEANEXEFILES
+	-$(DEL) $(CLEANEXEFILES)
+endif
+ifdef COMPILER_UNITTARGETDIR
+ifdef CLEANPPUFILES
+	-$(DEL) $(CLEANPPUFILES)
+endif
+ifneq ($(CLEANPPULINKFILES),)
+	-$(DEL) $(CLEANPPULINKFILES)
+endif
+ifdef CLEANRSTFILES
+	-$(DEL) $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANRSTFILES))
+endif
+endif
+ifdef CLEAN_FILES
+	-$(DEL) $(CLEAN_FILES)
+endif
+	-$(DELTREE) units
+	-$(DEL) *$(OEXT) *$(PPUEXT) *$(RSTEXT) *$(ASMEXT) *$(STATICLIBEXT) *$(SHAREDLIBEXT) *$(PPLEXT)
+ifneq ($(PPUEXT),.ppu)
+	-$(DEL) *.o *.ppu *.a
+endif
+	-$(DELTREE) *$(SMARTEXT)
+	-$(DEL) fpcmade.* Package.fpc $(PPAS) script.res link.res $(FPCEXTFILE) $(REDIRFILE)
+	-$(DEL) *_ppas$(BATCHEXT)
+ifdef AOUTEXT
+	-$(DEL) *$(AOUTEXT)
+endif
+ifdef DEBUGSYMEXT
+	-$(DEL) *$(DEBUGSYMEXT)
+endif
+ifdef LOCALFPMAKEBIN
+	-$(DEL) $(LOCALFPMAKEBIN)
+	-$(DEL) $(FPMAKEBINOBJ)
+endif
+fpc_distclean: cleanall
+.PHONY: fpc_baseinfo
+override INFORULES+=fpc_baseinfo
+fpc_baseinfo:
+	@$(ECHO)
+	@$(ECHO)  == Package info ==
+	@$(ECHO)  Package Name..... $(PACKAGE_NAME)
+	@$(ECHO)  Package Version.. $(PACKAGE_VERSION)
+	@$(ECHO)
+	@$(ECHO)  == Configuration info ==
+	@$(ECHO)
+	@$(ECHO)  FPC.......... $(FPC)
+	@$(ECHO)  FPC Version.. $(FPC_VERSION)
+	@$(ECHO)  Source CPU... $(CPU_SOURCE)
+	@$(ECHO)  Target CPU... $(CPU_TARGET)
+	@$(ECHO)  Source OS.... $(OS_SOURCE)
+	@$(ECHO)  Target OS.... $(OS_TARGET)
+	@$(ECHO)  Full Source.. $(FULL_SOURCE)
+	@$(ECHO)  Full Target.. $(FULL_TARGET)
+	@$(ECHO)  SourceSuffix. $(SOURCESUFFIX)
+	@$(ECHO)  TargetSuffix. $(TARGETSUFFIX)
+	@$(ECHO)  FPC fpmake... $(FPCFPMAKE)
+	@$(ECHO)
+	@$(ECHO)  == Directory info ==
+	@$(ECHO)
+	@$(ECHO)  Required pkgs... $(REQUIRE_PACKAGES)
+	@$(ECHO)
+	@$(ECHO)  Basedir......... $(BASEDIR)
+	@$(ECHO)  FPCDir.......... $(FPCDIR)
+	@$(ECHO)  CrossBinDir..... $(CROSSBINDIR)
+	@$(ECHO)  UnitsDir........ $(UNITSDIR)
+	@$(ECHO)  PackagesDir..... $(PACKAGESDIR)
+	@$(ECHO)
+	@$(ECHO)  GCC library..... $(GCCLIBDIR)
+	@$(ECHO)  Other library... $(OTHERLIBDIR)
+	@$(ECHO)
+	@$(ECHO)  == Tools info ==
+	@$(ECHO)
+	@$(ECHO)  As........ $(AS)
+	@$(ECHO)  Ld........ $(LD)
+	@$(ECHO)  Ar........ $(AR)
+	@$(ECHO)  Rc........ $(RC)
+	@$(ECHO)
+	@$(ECHO)  Mv........ $(MVPROG)
+	@$(ECHO)  Cp........ $(CPPROG)
+	@$(ECHO)  Rm........ $(RMPROG)
+	@$(ECHO)  GInstall.. $(GINSTALL)
+	@$(ECHO)  Echo...... $(ECHO)
+	@$(ECHO)  Shell..... $(SHELL)
+	@$(ECHO)  Date...... $(DATE)
+	@$(ECHO)  FPCMake... $(FPCMAKE)
+	@$(ECHO)  PPUMove... $(PPUMOVE)
+	@$(ECHO)  Zip....... $(ZIPPROG)
+	@$(ECHO)
+	@$(ECHO)  == Object info ==
+	@$(ECHO)
+	@$(ECHO)  Target Loaders........ $(TARGET_LOADERS)
+	@$(ECHO)  Target Units.......... $(TARGET_UNITS)
+	@$(ECHO)  Target Implicit Units. $(TARGET_IMPLICITUNITS)
+	@$(ECHO)  Target Programs....... $(TARGET_PROGRAMS)
+	@$(ECHO)  Target Dirs........... $(TARGET_DIRS)
+	@$(ECHO)  Target Examples....... $(TARGET_EXAMPLES)
+	@$(ECHO)  Target ExampleDirs.... $(TARGET_EXAMPLEDIRS)
+	@$(ECHO)
+	@$(ECHO)  Clean Units......... $(CLEAN_UNITS)
+	@$(ECHO)  Clean Files......... $(CLEAN_FILES)
+	@$(ECHO)
+	@$(ECHO)  Install Units....... $(INSTALL_UNITS)
+	@$(ECHO)  Install Files....... $(INSTALL_FILES)
+	@$(ECHO)
+	@$(ECHO)  == Install info ==
+	@$(ECHO)
+	@$(ECHO)  DateStr.............. $(DATESTR)
+	@$(ECHO)  ZipName.............. $(ZIPNAME)
+	@$(ECHO)  ZipPrefix............ $(ZIPPREFIX)
+	@$(ECHO)  ZipCrossPrefix....... $(ZIPCROSSPREFIX)
+	@$(ECHO)  ZipSuffix............ $(ZIPSUFFIX)
+	@$(ECHO)  FullZipName.......... $(FULLZIPNAME)
+	@$(ECHO)  Install FPC Package.. $(INSTALL_FPCPACKAGE)
+	@$(ECHO)
+	@$(ECHO)  Install base dir..... $(INSTALL_BASEDIR)
+	@$(ECHO)  Install binary dir... $(INSTALL_BINDIR)
+	@$(ECHO)  Install library dir.. $(INSTALL_LIBDIR)
+	@$(ECHO)  Install units dir.... $(INSTALL_UNITDIR)
+	@$(ECHO)  Install source dir... $(INSTALL_SOURCEDIR)
+	@$(ECHO)  Install doc dir...... $(INSTALL_DOCDIR)
+	@$(ECHO)  Install example dir.. $(INSTALL_EXAMPLEDIR)
+	@$(ECHO)  Install data dir..... $(INSTALL_DATADIR)
+	@$(ECHO)
+	@$(ECHO)  Dist destination dir. $(DIST_DESTDIR)
+	@$(ECHO)  Dist zip name........ $(DIST_ZIPNAME)
+	@$(ECHO)
+.PHONY: fpc_info
+fpc_info: $(INFORULES)
+.PHONY: fpc_makefile fpc_makefiles fpc_makefile_sub1 fpc_makefile_sub2 \
+	fpc_makefile_dirs
+fpc_makefile:
+	$(FPCMAKE) -w -T$(OS_TARGET) Makefile.fpc
+fpc_makefile_sub1:
+ifdef TARGET_DIRS
+	$(FPCMAKE) -w -T$(OS_TARGET) $(addsuffix /Makefile.fpc,$(TARGET_DIRS))
+endif
+ifdef TARGET_EXAMPLEDIRS
+	$(FPCMAKE) -w -T$(OS_TARGET) $(addsuffix /Makefile.fpc,$(TARGET_EXAMPLEDIRS))
+endif
+fpc_makefile_sub2: $(addsuffix _makefile_dirs,$(TARGET_DIRS) $(TARGET_EXAMPLEDIRS))
+fpc_makefile_dirs: fpc_makefile_sub1 fpc_makefile_sub2
+fpc_makefiles: fpc_makefile fpc_makefile_dirs
+units:
+examples:
+shared:
+sourceinstall: fpc_sourceinstall
+exampleinstall: fpc_exampleinstall
+zipexampleinstall: fpc_zipexampleinstall
+info: fpc_info
+makefiles: fpc_makefiles
+.PHONY: units examples shared sourceinstall exampleinstall zipexampleinstall info makefiles
+ifneq ($(wildcard fpcmake.loc),)
+include fpcmake.loc
+endif
+override FPCOPT:=$(filter-out -FU%,$(FPCOPT))
+override FPCOPT:=$(filter-out -FE%,$(FPCOPT))
+override FPCOPT:=$(filter-out $(addprefix -Fu,$(COMPILER_UNITDIR)),$(FPCOPT))# Compose general fpmake-parameters
+ifdef FPMAKEOPT
+FPMAKE_OPT+=$(FPMAKEOPT)
+endif
+FPMAKE_OPT+=--localunitdir=../..
+FPMAKE_OPT+=--globalunitdir=..
+FPMAKE_OPT+=$(FPC_TARGETOPT)
+FPMAKE_OPT+=$(addprefix -o ,$(FPCOPT))
+FPMAKE_OPT+=--compiler=$(FPC)
+FPMAKE_OPT+=-bu
+.NOTPARALLEL:
+fpmake$(SRCEXEEXT): fpmake.pp
+	$(FPCFPMAKE) fpmake.pp $(FPMAKE_SKIP_CONFIG) $(addprefix -Fu,$(COMPILER_FPMAKE_UNITDIR)) $(FPCMAKEOPT) $(OPT)
+all:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) compile $(FPMAKE_OPT)
+smart:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -XX -o -CX
+release:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -dRELEASE
+debug:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -dDEBUG
+ifeq ($(FPMAKE_BIN_CLEAN),)
+clean:
+else
+clean:
+	$(FPMAKE_BIN_CLEAN) clean $(FPMAKE_OPT)
+endif
+ifeq ($(FPMAKE_BIN_CLEAN),)
+distclean:	$(addsuffix _distclean,$(TARGET_DIRS)) fpc_cleanall
+else
+distclean:
+ifdef inUnix
+	{ $(FPMAKE_BIN_CLEAN) distclean $(FPMAKE_OPT); if [ $$? != "0" ]; then { echo Something wrong with fpmake exectable. Remove the executable and call make recursively to recover.; $(DEL) $(FPMAKE_BIN_CLEAN); $(MAKE) fpc_cleanall; }; fi;  }
+else
+	$(FPMAKE_BIN_CLEAN) distclean $(FPMAKE_OPT)
+endif
+	-$(DEL) $(LOCALFPMAKE)
+endif
+cleanall: distclean
+install:	fpmake$(SRCEXEEXT)
+ifdef UNIXHier
+	$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_PREFIX) --baseinstalldir=$(INSTALL_LIBDIR)/fpc/$(FPC_VERSION) --unitinstalldir=$(INSTALL_UNITDIR)
+else
+	$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_BASEDIR) --baseinstalldir=$(INSTALL_BASEDIR) --unitinstalldir=$(INSTALL_UNITDIR)
+endif
+distinstall:	fpmake$(SRCEXEEXT)
+ifdef UNIXHier
+	$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_PREFIX) --baseinstalldir=$(INSTALL_LIBDIR)/fpc/$(FPC_VERSION) --unitinstalldir=$(INSTALL_UNITDIR) -ie -fsp 0
+else
+	$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_BASEDIR) --baseinstalldir=$(INSTALL_BASEDIR) --unitinstalldir=$(INSTALL_UNITDIR) -ie -fsp 0
+endif
+zipinstall:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) zipinstall $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX)
+zipdistinstall:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) zipinstall $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) -ie -fsp 0
+zipsourceinstall:	fpmake$(SRCEXEEXT)
+ifdef UNIXHier
+	$(LOCALFPMAKE) archive $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) --prefix=share/src/fpc-\$$\(PACKAGEVERSION\)/$(INSTALL_FPCSUBDIR)/\$$\(PACKAGEDIRECTORY\)
+else
+	$(LOCALFPMAKE) archive $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) --prefix=source\\$(INSTALL_FPCSUBDIR)\\\$$\(PACKAGEDIRECTORY\)
+endif

+ 102 - 0
packages/libmicrohttpd/Makefile.fpc

@@ -0,0 +1,102 @@
+#
+#   Makefile.fpc for running fpmake
+#
+
+[package]
+name=libmicrohttpd
+version=3.1.1
+
+[require]
+packages=rtl
+
+[install]
+fpcpackage=y
+
+[default]
+fpcdir=../..
+
+[prerules]
+FPMAKE_BIN_CLEAN=$(wildcard ./fpmake$(SRCEXEEXT))
+ifdef OS_TARGET
+FPC_TARGETOPT+=--os=$(OS_TARGET)
+endif
+ifdef CPU_TARGET
+FPC_TARGETOPT+=--cpu=$(CPU_TARGET)
+endif
+LOCALFPMAKE=./fpmake$(SRCEXEEXT)
+
+[rules]
+# Do not pass the Makefile's unit and binary target locations. Fpmake uses it's own.
+override FPCOPT:=$(filter-out -FU%,$(FPCOPT))
+override FPCOPT:=$(filter-out -FE%,$(FPCOPT))
+# Do not pass the package-unitdirectories. Fpmake adds those and this way they don't apear in the .fpm
+override FPCOPT:=$(filter-out $(addprefix -Fu,$(COMPILER_UNITDIR)),$(FPCOPT))# Compose general fpmake-parameters
+# Compose general fpmake-parameters
+ifdef FPMAKEOPT
+FPMAKE_OPT+=$(FPMAKEOPT)
+endif
+FPMAKE_OPT+=--localunitdir=../..
+FPMAKE_OPT+=--globalunitdir=..
+FPMAKE_OPT+=$(FPC_TARGETOPT)
+FPMAKE_OPT+=$(addprefix -o ,$(FPCOPT))
+FPMAKE_OPT+=--compiler=$(FPC)
+FPMAKE_OPT+=-bu
+.NOTPARALLEL:
+
+fpmake$(SRCEXEEXT): fpmake.pp
+	$(FPCFPMAKE) fpmake.pp $(FPMAKE_SKIP_CONFIG) $(addprefix -Fu,$(COMPILER_FPMAKE_UNITDIR)) $(FPCMAKEOPT) $(OPT)
+all:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) compile $(FPMAKE_OPT)
+smart:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -XX -o -CX
+release:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -dRELEASE
+debug:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -dDEBUG
+# If no fpmake exists and (dist)clean is called, do not try to build fpmake, it will
+# most often fail because the dependencies are cleared.
+# In case of a clean, simply do nothing
+ifeq ($(FPMAKE_BIN_CLEAN),)
+clean:
+else
+clean:
+	$(FPMAKE_BIN_CLEAN) clean $(FPMAKE_OPT)
+endif
+# In case of a distclean, perform an 'old'-style distclean. This to avoid problems
+# when the package is compiled using fpcmake prior to running this clean using fpmake
+ifeq ($(FPMAKE_BIN_CLEAN),)
+distclean:	$(addsuffix _distclean,$(TARGET_DIRS)) fpc_cleanall
+else
+distclean:
+ifdef inUnix
+        { $(FPMAKE_BIN_CLEAN) distclean $(FPMAKE_OPT); if [ $$? != "0" ]; then { echo Something wrong with fpmake exectable. Remove the executable and call make recursively to recover.; $(DEL) $(FPMAKE_BIN_CLEAN); $(MAKE) fpc_cleanall; }; fi;  }
+else
+        $(FPMAKE_BIN_CLEAN) distclean $(FPMAKE_OPT)
+endif
+	-$(DEL) $(LOCALFPMAKE)
+endif
+cleanall: distclean
+install:	fpmake$(SRCEXEEXT)
+ifdef UNIXHier
+	$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_PREFIX) --baseinstalldir=$(INSTALL_LIBDIR)/fpc/$(FPC_VERSION) --unitinstalldir=$(INSTALL_UNITDIR)
+else
+	$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_BASEDIR) --baseinstalldir=$(INSTALL_BASEDIR) --unitinstalldir=$(INSTALL_UNITDIR)
+endif
+# distinstall also installs the example-sources and omits the location of the source-
+# files from the fpunits.cfg files.
+distinstall:	fpmake$(SRCEXEEXT)
+ifdef UNIXHier
+	$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_PREFIX) --baseinstalldir=$(INSTALL_LIBDIR)/fpc/$(FPC_VERSION) --unitinstalldir=$(INSTALL_UNITDIR) -ie -fsp 0
+else
+	$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_BASEDIR) --baseinstalldir=$(INSTALL_BASEDIR) --unitinstalldir=$(INSTALL_UNITDIR) -ie -fsp 0
+endif
+zipinstall:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) zipinstall $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX)
+zipdistinstall:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) zipinstall $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) -ie -fsp 0
+zipsourceinstall:	fpmake$(SRCEXEEXT)
+ifdef UNIXHier
+	$(LOCALFPMAKE) archive $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) --prefix=share/src/fpc-\$$\(PACKAGEVERSION\)/$(INSTALL_FPCSUBDIR)/\$$\(PACKAGEDIRECTORY\)
+else
+	$(LOCALFPMAKE) archive $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) --prefix=source\\$(INSTALL_FPCSUBDIR)\\\$$\(PACKAGEDIRECTORY\)
+endif

+ 70 - 0
packages/libmicrohttpd/examples/basicauthentication.pp

@@ -0,0 +1,70 @@
+(* Feel free to use this example code in any way
+   you see fit (Public Domain) *)
+
+// Original example: https://gnunet.org/svn/libmicrohttpd/doc/examples/basicauthentication.c
+
+program basicauthentication;
+
+{$mode objfpc}{$H+}
+
+uses
+  libmicrohttpd, SysUtils;
+
+const
+  PORT = 8888;
+
+  function AnswerToConnection(ACls: Pointer; AConnection: PMHD_Connection;
+    AUrl: Pcchar; AMethod: Pcchar; AVersion: Pcchar; AUploadData: Pcchar;
+    AUploadDataSize: Psize_t; AConCls: PPointer): cint; cdecl;
+  var
+    VPage: Pcchar;
+    VUser: Pcchar;
+    VPass: Pcchar;
+    VReturn: cint;
+    VFail: Boolean;
+    VResponse: PMHD_Response;
+  begin
+    if StrComp(AMethod, 'GET') <> 0 then
+      Exit(MHD_NO);
+    if not Assigned(AConCls^) then
+    begin
+      AConCls^ := AConnection;
+      Exit(MHD_YES);
+    end;
+    VPass := nil;
+    VUser := MHD_basic_auth_get_username_password(AConnection, @VPass);
+    VFail := (VUser = nil) or (StrComp(VUser, 'root') <> 0) or
+      (StrComp(VPass, 'pa$$w0rd') <> 0);
+    if VUser <> nil then
+      VUser := nil;
+    if VPass <> nil then
+      VPass := nil;
+    if VFail then
+    begin
+      VPage := '<html><body>Go away.</body></html>';
+      VResponse := MHD_create_response_from_buffer(Length(VPage),
+        Pointer(VPage), MHD_RESPMEM_PERSISTENT);
+      VReturn := MHD_queue_basic_auth_fail_response(AConnection,
+        'my realm', VResponse);
+    end
+    else
+    begin
+      VPage := '<html><body>A secret.</body></html>';
+      VResponse := MHD_create_response_from_buffer(Length(VPage),
+        Pointer(VPage), MHD_RESPMEM_PERSISTENT);
+      VReturn := MHD_queue_response(AConnection, MHD_HTTP_OK, VResponse);
+    end;
+    MHD_destroy_response(VResponse);
+    Result := VReturn;
+  end;
+
+var
+  VDaemon: PMHD_Daemon;
+begin
+  VDaemon := MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, PORT, nil,
+    nil, @AnswerToConnection, nil, MHD_OPTION_END);
+  if not Assigned(VDaemon) then
+    Halt(1);
+  ReadLn;
+  MHD_stop_daemon(VDaemon);
+end.

+ 131 - 0
packages/libmicrohttpd/examples/benchmark.pp

@@ -0,0 +1,131 @@
+(*
+     This file is part of libmicrohttpd
+     Copyright (C) 2007, 2013 Christian Grothoff (and other contributing authors)
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*)
+(**
+ * @file benchmark.pp (Original: benchmark.c)
+ * @brief minimal code to benchmark MHD GET performance
+ * @author Christian Grothoff / Silvio Clécio
+ *)
+
+program benchmark;
+
+{$mode objfpc}{$H+}
+{$MACRO ON}
+{$IF DEFINED(CPU_COUNT) and (CPU_COUNT + 0) < 2}
+  {$UNDEF CPU_COUNT}
+{$ENDIF}
+{$IF NOT DEFINED(CPU_COUNT)}
+  {$DEFINE CPU_COUNT := 2}
+{$ENDIF}
+
+uses
+{$IFDEF MSWINDOWS}
+  WinSock2,
+{$ELSE}
+  BaseUnix, Unix,
+{$ENDIF}
+  cmem, sysutils, cutils, libmicrohttpd;
+
+const
+  PAGE: Pcchar = '<html><head><title>libmicrohttpd demo</title></head><body>libmicrohttpd demo</body></html>';
+  SMALL = 1024 * 128;
+  NUMBER_OF_THREADS = CPU_COUNT;
+
+var
+  small_deltas: array[0..SMALL] of cuint;
+  response: PMHD_Response;
+
+  procedure completed_callback(cls: Pointer; connection: PMHD_Connection;
+    con_cls: PPointer; toe: MHD_RequestTerminationCode); cdecl;
+  var
+    tv: ptimeval;
+    tve: timeval;
+    delta: cuint64;
+  begin
+    tv := con_cls^;
+    if nil = tv then
+      Exit;
+    fpgettimeofday(@tve, nil);
+    delta := 0;
+    if tve.tv_usec >= tv^.tv_usec then
+      delta += (tve.tv_sec - tv^.tv_sec) * 1000000 +
+        (tve.tv_usec - tv^.tv_usec)
+    else
+      delta += (tve.tv_sec - tv^.tv_sec) * 1000000 -
+        tv^.tv_usec + tve.tv_usec;
+    if delta < SMALL then
+      Inc(small_deltas[delta])
+    else
+      WriteLn(stdout, Format('D: %u 1', [delta]));
+    Free(tv);
+  end;
+
+  function uri_logger_cb(cls: Pointer; uri: Pcchar): Pointer; cdecl;
+  var
+    tv: ptimeval;
+  begin
+    tv := Malloc(SizeOf(timeval));
+    if nil <> tv then
+      fpgettimeofday(tv, nil);
+    Result := tv;
+  end;
+
+  function ahc_echo(cls: Pointer; connection: PMHD_Connection; url: Pcchar;
+    method: Pcchar; version: Pcchar; upload_data: Pcchar;
+    upload_data_size: Psize_t; ptr: PPointer): cint; cdecl;
+  begin
+    if 0 <> strcomp(method, 'GET') then
+      Exit(MHD_NO);
+    Result := MHD_queue_response(connection, MHD_HTTP_OK, response);
+  end;
+
+var
+  d: PMHD_Daemon;
+  i: cuint;
+begin
+  if argc <> 2 then
+  begin
+    WriteLn(argv[0] + ' PORT');
+    Halt(1);
+  end;
+  response := MHD_create_response_from_buffer(Length(PAGE), Pointer(PAGE),
+    MHD_RESPMEM_PERSISTENT);
+{$IF 0}
+  MHD_add_response_header (response, MHD_HTTP_HEADER_CONNECTION, 'close');
+{$ENDIF}
+  d := MHD_start_daemon(MHD_USE_SELECT_INTERNALLY or MHD_SUPPRESS_DATE_NO_CLOCK
+{$IFDEF EPOLL_SUPPORT}
+         or MHD_USE_EPOLL_LINUX_ONLY or MHD_USE_EPOLL_TURBO
+{$ENDIF},
+         StrToInt(argv[1]), nil, nil, @ahc_echo, nil,
+         MHD_OPTION_CONNECTION_TIMEOUT, 120,
+         MHD_OPTION_THREAD_POOL_SIZE, NUMBER_OF_THREADS,
+         MHD_OPTION_URI_LOG_CALLBACK, @uri_logger_cb, nil,
+         MHD_OPTION_NOTIFY_COMPLETED, @completed_callback, nil,
+         MHD_OPTION_CONNECTION_LIMIT, 1000,
+         MHD_OPTION_END);
+  if d = nil then
+    Halt(1);
+  ReadLn;
+  MHD_stop_daemon(d);
+  MHD_destroy_response(response);
+  for i := 0 to SMALL do
+    if 0 <> small_deltas[i] then
+      WriteLn(stdout, Format('D: %d %u', [i, small_deltas[i]]));
+end.
+

+ 182 - 0
packages/libmicrohttpd/examples/benchmark_https.pp

@@ -0,0 +1,182 @@
+(*
+     This file is part of libmicrohttpd
+     Copyright (C) 2007, 2013 Christian Grothoff (and other contributing authors)
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*)
+(**
+ * @file benchmark_https.pp (Original: benchmark_https.c)
+ * @brief minimal code to benchmark MHD GET performance with HTTPS
+ * @author Christian Grothoff / Silvio Clécio
+ *)
+
+program benchmark_https;
+
+{$mode objfpc}{$H+}
+{$MACRO ON}
+{$IF DEFINED(CPU_COUNT) and (CPU_COUNT + 0) < 2}
+  {$UNDEF CPU_COUNT}
+{$ENDIF}
+{$IF NOT DEFINED(CPU_COUNT)}
+  {$DEFINE CPU_COUNT := 2}
+{$ENDIF}
+
+uses
+{$IFDEF MSWINDOWS}
+  WinSock2,
+{$ELSE}
+  BaseUnix, Unix,
+{$ENDIF}
+  cmem, sysutils, cutils, libmicrohttpd;
+
+const
+  PAGE: Pcchar = '<html><head><title>libmicrohttpd demo</title></head><body>libmicrohttpd demo</body></html>';
+  SMALL = 1024 * 128;
+  NUMBER_OF_THREADS = CPU_COUNT;
+
+var
+  small_deltas: array[0..SMALL] of cuint;
+  response: PMHD_Response;
+
+  procedure completed_callback(cls: Pointer; connection: PMHD_Connection;
+    con_cls: PPointer; toe: MHD_RequestTerminationCode); cdecl;
+  var
+    tv: ptimeval;
+    tve: timeval;
+    delta: cuint64;
+  begin
+    tv := con_cls^;
+    if nil = tv then
+      Exit;
+    fpgettimeofday(@tve, nil);
+    delta := 0;
+    if tve.tv_usec >= tv^.tv_usec then
+      delta += (tve.tv_sec - tv^.tv_sec) * 1000000 +
+        (tve.tv_usec - tv^.tv_usec)
+    else
+      delta += (tve.tv_sec - tv^.tv_sec) * 1000000 -
+        tv^.tv_usec + tve.tv_usec;
+    if delta < SMALL then
+      Inc(small_deltas[delta])
+    else
+      WriteLn(stdout, Format('D: %u 1', [delta]));
+    Free(tv);
+  end;
+
+  function uri_logger_cb(cls: Pointer; uri: Pcchar): Pointer; cdecl;
+  var
+    tv: ptimeval;
+  begin
+    tv := Malloc(SizeOf(timeval));
+    if nil <> tv then
+      fpgettimeofday(tv, nil);
+    Result := tv;
+  end;
+
+  function ahc_echo(cls: Pointer; connection: PMHD_Connection; url: Pcchar;
+    method: Pcchar; version: Pcchar; upload_data: Pcchar;
+    upload_data_size: Psize_t; ptr: PPointer): cint; cdecl;
+  begin
+    if 0 <> strcomp(method, 'GET') then
+      Exit(MHD_NO);
+    Result := MHD_queue_response(connection, MHD_HTTP_OK, response);
+  end;
+
+const
+  srv_signed_key_pem: array[0..1674] of AnsiChar =
+    '-----BEGIN RSA PRIVATE KEY-----'#10+
+    'MIIEowIBAAKCAQEAvfTdv+3fgvVTKRnP/HVNG81cr8TrUP/iiyuve/THMzvFXhCW'#10+
+    '+K03KwEku55QvnUndwBfU/ROzLlv+5hotgiDRNFT3HxurmhouySBrJNJv7qWp8IL'#10+
+    'q4sw32vo0fbMu5BZF49bUXK9L3kW2PdhTtSQPWHEzNrCxO+YgCilKHkY3vQNfdJ0'#10+
+    '20Q5EAAEseD1YtWCIpRvJzYlZMpjYB1ubTl24kwrgOKUJYKqM4jmF4DVQp4oOK/6'#10+
+    'QYGGh1QmHRPAy3CBII6sbb+sZT9cAqU6GYQVB35lm4XAgibXV6KgmpVxVQQ69U6x'#10+
+    'yoOl204xuekZOaG9RUPId74Rtmwfi1TLbBzo2wIDAQABAoIBADu09WSICNq5cMe4'#10+
+    '+NKCLlgAT1NiQpLls1gKRbDhKiHU9j8QWNvWWkJWrCya4QdUfLCfeddCMeiQmv3K'#10+
+    'lJMvDs+5OjJSHFoOsGiuW2Ias7IjnIojaJalfBml6frhJ84G27IXmdz6gzOiTIer'#10+
+    'DjeAgcwBaKH5WwIay2TxIaScl7AwHBauQkrLcyb4hTmZuQh6ArVIN6+pzoVuORXM'#10+
+    'bpeNWl2l/HSN3VtUN6aCAKbN/X3o0GavCCMn5Fa85uJFsab4ss/uP+2PusU71+zP'#10+
+    'sBm6p/2IbGvF5k3VPDA7X5YX61sukRjRBihY8xSnNYx1UcoOsX6AiPnbhifD8+xQ'#10+
+    'Tlf8oJUCgYEA0BTfzqNpr9Wxw5/QXaSdw7S/0eP5a0C/nwURvmfSzuTD4equzbEN'#10+
+    'd+dI/s2JMxrdj/I4uoAfUXRGaabevQIjFzC9uyE3LaOyR2zhuvAzX+vVcs6bSXeU'#10+
+    'pKpCAcN+3Z3evMaX2f+z/nfSUAl2i4J2R+/LQAWJW4KwRky/m+cxpfUCgYEA6bN1'#10+
+    'b73bMgM8wpNt6+fcmS+5n0iZihygQ2U2DEud8nZJL4Nrm1dwTnfZfJBnkGj6+0Q0'#10+
+    'cOwj2KS0/wcEdJBP0jucU4v60VMhp75AQeHqidIde0bTViSRo3HWKXHBIFGYoU3T'#10+
+    'LyPyKndbqsOObnsFXHn56Nwhr2HLf6nw4taGQY8CgYBoSW36FLCNbd6QGvLFXBGt'#10+
+    '2lMhEM8az/K58kJ4WXSwOLtr6MD/WjNT2tkcy0puEJLm6BFCd6A6pLn9jaKou/92'#10+
+    'SfltZjJPb3GUlp9zn5tAAeSSi7YMViBrfuFiHObij5LorefBXISLjuYbMwL03MgH'#10+
+    'Ocl2JtA2ywMp2KFXs8GQWQKBgFyIVv5ogQrbZ0pvj31xr9HjqK6d01VxIi+tOmpB'#10+
+    '4ocnOLEcaxX12BzprW55ytfOCVpF1jHD/imAhb3YrHXu0fwe6DXYXfZV4SSG2vB7'#10+
+    'IB9z14KBN5qLHjNGFpMQXHSMek+b/ftTU0ZnPh9uEM5D3YqRLVd7GcdUhHvG8P8Q'#10+
+    'C9aXAoGBAJtID6h8wOGMP0XYX5YYnhlC7dOLfk8UYrzlp3xhqVkzKthTQTj6wx9R'#10+
+    'GtC4k7U1ki8oJsfcIlBNXd768fqDVWjYju5rzShMpo8OCTS6ipAblKjCxPPVhIpv'#10+
+    'tWPlbSn1qj6wylstJ5/3Z+ZW5H4wIKp5jmLiioDhcP0L/Ex3Zx8O'#10+
+    '-----END RSA PRIVATE KEY-----'#10;
+
+  srv_signed_cert_pem: array[0..1138] of AnsiChar =
+    '-----BEGIN CERTIFICATE-----'#10+
+    'MIIDGzCCAgWgAwIBAgIES0KCvTALBgkqhkiG9w0BAQUwFzEVMBMGA1UEAxMMdGVz'#10+
+    'dF9jYV9jZXJ0MB4XDTEwMDEwNTAwMDcyNVoXDTQ1MDMxMjAwMDcyNVowFzEVMBMG'#10+
+    'A1UEAxMMdGVzdF9jYV9jZXJ0MIIBHzALBgkqhkiG9w0BAQEDggEOADCCAQkCggEA'#10+
+    'vfTdv+3fgvVTKRnP/HVNG81cr8TrUP/iiyuve/THMzvFXhCW+K03KwEku55QvnUn'#10+
+    'dwBfU/ROzLlv+5hotgiDRNFT3HxurmhouySBrJNJv7qWp8ILq4sw32vo0fbMu5BZ'#10+
+    'F49bUXK9L3kW2PdhTtSQPWHEzNrCxO+YgCilKHkY3vQNfdJ020Q5EAAEseD1YtWC'#10+
+    'IpRvJzYlZMpjYB1ubTl24kwrgOKUJYKqM4jmF4DVQp4oOK/6QYGGh1QmHRPAy3CB'#10+
+    'II6sbb+sZT9cAqU6GYQVB35lm4XAgibXV6KgmpVxVQQ69U6xyoOl204xuekZOaG9'#10+
+    'RUPId74Rtmwfi1TLbBzo2wIDAQABo3YwdDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQM'#10+
+    'MAoGCCsGAQUFBwMBMA8GA1UdDwEB/wQFAwMHIAAwHQYDVR0OBBYEFOFi4ilKOP1d'#10+
+    'XHlWCMwmVKr7mgy8MB8GA1UdIwQYMBaAFP2olB4s2T/xuoQ5pT2RKojFwZo2MAsG'#10+
+    'CSqGSIb3DQEBBQOCAQEAHVWPxazupbOkG7Did+dY9z2z6RjTzYvurTtEKQgzM2Vz'#10+
+    'GQBA+3pZ3c5mS97fPIs9hZXfnQeelMeZ2XP1a+9vp35bJjZBBhVH+pqxjCgiUflg'#10+
+    'A3Zqy0XwwVCgQLE2HyaU3DLUD/aeIFK5gJaOSdNTXZLv43K8kl4cqDbMeRpVTbkt'#10+
+    'YmG4AyEOYRNKGTqMEJXJoxD5E3rBUNrVI/XyTjYrulxbNPcMWEHKNeeqWpKDYTFo'#10+
+    'Bb01PCthGXiq/4A2RLAFosadzRa8SBpoSjPPfZ0b2w4MJpReHqKbR5+T2t6hzml6'#10+
+    '4ToyOKPDmamiTuN5KzLN3cw7DQlvWMvqSOChPLnA3Q=='#10+
+    '-----END CERTIFICATE-----'#10;
+
+
+var
+  d: PMHD_Daemon;
+  i: cuint;
+begin
+  if argc <> 2 then
+  begin
+    WriteLn(argv[0] + ' PORT');
+    Halt(1);
+  end;
+  response := MHD_create_response_from_buffer(Length(PAGE), Pointer(PAGE),
+    MHD_RESPMEM_PERSISTENT);
+  d := MHD_start_daemon(MHD_USE_SELECT_INTERNALLY or MHD_USE_SSL
+{$IFDEF EPOLL_SUPPORT}
+         or MHD_USE_EPOLL_LINUX_ONLY or MHD_USE_EPOLL_TURBO
+{$ENDIF},
+         StrToInt(argv[1]), nil, nil, @ahc_echo, nil,
+         MHD_OPTION_CONNECTION_TIMEOUT, 120,
+         MHD_OPTION_THREAD_POOL_SIZE, NUMBER_OF_THREADS,
+         MHD_OPTION_URI_LOG_CALLBACK, @uri_logger_cb, nil,
+         MHD_OPTION_NOTIFY_COMPLETED, @completed_callback, nil,
+         MHD_OPTION_CONNECTION_LIMIT, 1000,
+         MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem,
+         MHD_OPTION_HTTPS_MEM_CERT, srv_signed_cert_pem,
+         MHD_OPTION_END);
+  if d = nil then
+    Halt(1);
+  ReadLn;
+  MHD_stop_daemon(d);
+  MHD_destroy_response(response);
+  for i := 0 to SMALL do
+    if 0 <> small_deltas[i] then
+      WriteLn(stdout, Format('D: %d %u', [i, small_deltas[i]]));
+end.
+

+ 81 - 0
packages/libmicrohttpd/examples/chunked_example.pp

@@ -0,0 +1,81 @@
+(*
+     This file is part of libmicrohttpd
+     Copyright (C) 2015 Christian Grothoff (and other contributing authors)
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*)
+(**
+ * @file chunked_example.pp (original: chunked_example.c)
+ * @brief example for generating chunked encoding with libmicrohttpd
+ * @author Christian Grothoff / Silvio Clécio / Gilson Nunes
+ *)
+
+program chunked_example;
+
+{$mode objfpc}{$H+}
+
+uses
+  sysutils, libmicrohttpd;
+
+  function callback(cls: Pointer; pos: cuint64; buf: Pcchar;
+    max: size_t): ssize_t; cdecl;
+  begin
+    Result := MHD_CONTENT_READER_END_OF_STREAM;
+  end;
+
+  function ahc_echo(cls:  Pointer; connection: PMHD_Connection; url: Pcchar;
+    method: Pcchar; version: Pcchar; upload_data: Pcchar;
+    upload_data_size: Psize_t; ptr: PPointer): cint; cdecl;
+  const
+    aptr: cint = 0;
+  var
+    response: PMHD_Response;
+    ret: cint;
+  begin
+    if 0 <> strcomp(method, 'GET') then
+      Exit(MHD_NO);
+    if @aptr <> ptr^ then
+    begin
+      ptr^ := @aptr;
+      Exit(MHD_YES);
+    end;
+    ptr^ := nil;
+    response := MHD_create_response_from_callback(UInt64(MHD_SIZE_UNKNOWN), 1024,
+      @callback, nil, nil);
+    ret := MHD_queue_response(connection, MHD_HTTP_OK, response);
+    MHD_destroy_response(response);
+    Result := ret;
+  end;
+
+var
+  d: PMHD_Daemon;
+begin
+  if argc <> 2 then
+  begin
+    WriteLn(argv[0], ' PORT');
+    Halt(1);
+  end;
+  d := MHD_start_daemon(// MHD_USE_SELECT_INTERNALLY or MHD_USE_DEBUG or MHD_USE_POLL,
+         MHD_USE_SELECT_INTERNALLY or MHD_USE_DEBUG,
+         // MHD_USE_THREAD_PER_CONNECTION or MHD_USE_DEBUG or MHD_USE_POLL,
+         // MHD_USE_THREAD_PER_CONNECTION or MHD_USE_DEBUG,
+         StrToInt(argv[1]), nil, nil, @ahc_echo, nil,
+         MHD_OPTION_CONNECTION_TIMEOUT, 120, MHD_OPTION_END);
+  if d = nil then
+    Halt(1);
+  ReadLn;
+  MHD_stop_daemon(d);
+end.
+

+ 225 - 0
packages/libmicrohttpd/examples/cutils.pas

@@ -0,0 +1,225 @@
+unit cutils;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+{$IFDEF MSWINDOWS}
+  Windows, WinSock2,
+{$ELSE}
+  BaseUnix,
+{$ENDIF}
+  ctypes;
+
+const
+  LIB_NAME = {$IFDEF MSWINDOWS}'msvcrt'{$ELSE}'c'{$ENDIF};
+{$IFDEF UNIX}
+  UINT16_MAX = 65535;
+{$ENDIF}
+  SEEK_SET = 0;
+  SEEK_CUR = 1;
+  SEEK_END = 2;
+{$IFDEF MSWINDOWS}
+  DELTA_EPOCH_IN_MICROSECS: culonglong = 11644473600000000;
+{$ENDIF}
+
+type
+{$IFDEF UNIX}
+  __off_t = longint;
+{$ENDIF}
+  Pcchar = PAnsiChar;
+  Ppcchar = ^Pcchar;
+  FILEptr = ^File;
+  seek_mode = longint;
+  open_mode = (fopenread, fopenwrite, fappendwrite);
+
+{$IFDEF MSWINDOWS}
+function fpgettimeofday(tv: PTimeVal; tz: PTimeZone): cint;
+procedure _tzset; cdecl; external LIB_NAME name '_tzset';
+function _timezone: cint; cdecl; external LIB_NAME name '_timezone';
+function _daylight: clong; cdecl; external LIB_NAME name '__daylight';
+{$ENDIF}
+
+{$IFDEF UNIX}
+function sscanf(s: Pcchar; format: Pcchar): cint; cdecl; varargs; external LIB_NAME name 'sscanf';
+function lseek(fd: cint; offset: __off_t; whence: cint): __off_t; cdecl; external LIB_NAME name 'lseek';
+function isprint(p: Char): cint; cdecl; external LIB_NAME name 'isprint';
+function strdup(para1: Pcchar): Pcchar; cdecl; external LIB_NAME name 'strdup';
+function strchr(para1: Pcchar; para2: cint): Pcchar; cdecl; external LIB_NAME name 'strchr';
+function strstr(haystack: Pcchar; needle: Pcchar): Pcchar; cdecl; external LIB_NAME name 'strstr';
+function sprintf(s: Pcchar; format: Pcchar): cint; cdecl; varargs; external LIB_NAME name 'sprintf';
+function asprintf(resultp: Ppcchar; format: Pcchar): cint; cdecl; varargs; external LIB_NAME name 'asprintf';
+function errno: PInteger; cdecl; external LIB_NAME name '__errno_location';
+{$ENDIF}
+function memset(s: pointer; c: longint; n: size_t): pointer; cdecl; external LIB_NAME name 'memset';
+function snprintf(str: Pcchar; size: size_t; format: Pcchar): cint; cdecl; varargs; external LIB_NAME Name {$IFDEF MSWINDOWS}'_snprintf'{$ELSE}'snprintf'{$ENDIF};
+function rand: cint; cdecl; external LIB_NAME name 'rand';
+function strerror(errnum: cint): Pchar; cdecl; external LIB_NAME name 'strerror';
+function strncat(a, b: Pcchar; sz: size_t): Pchar; cdecl; external LIB_NAME name 'strncat';
+function strcpy(a, b: Pcchar): Pchar; cdecl; external LIB_NAME name 'strcpy';
+function strncmp(a, b: Pcchar; sz: size_t): cint; cdecl;  external LIB_NAME name 'strncmp';
+
+function fopen(filename: PAnsiChar; mode: open_mode): FILEptr;
+procedure fclose(fp: FILEptr);
+function fseek(fp: FILEptr; recPos: longint; mode: seek_mode): longint;
+function fread(buf: pointer; recSize: longint; recCount: longint; fp: FILEptr): longint;
+function fwrite(buf: pointer; recSize: longint; recCount: longint; fp: FILEptr): longint;
+function ftell(fp: FILEptr): LongInt;
+function feof(fp: FILEptr): LongInt;
+
+implementation
+
+{$IFDEF MSWINDOWS}
+function fpgettimeofday(tv: PTimeVal; tz: PTimeZone): cint;
+const
+  tzflag: cint = 0;
+var
+  ft: FILETIME;
+  tmpres: QWord = 0;
+begin
+  if nil <> tv then
+  begin
+    GetSystemTimeAsFileTime(@ft);
+    tmpres := tmpres or ft.dwHighDateTime;
+    tmpres := tmpres shl 32;
+    tmpres := tmpres or ft.dwLowDateTime;
+    tmpres := tmpres div 10;
+    tmpres -= DELTA_EPOCH_IN_MICROSECS;
+    tv^.tv_sec := clong(tmpres div culong(1000000));
+    tv^.tv_usec := clong(tmpres mod culong(1000000));
+  end;
+  if nil <> tz then
+  begin
+    if tzflag <> 1 then
+    begin
+      _tzset;
+      Inc(tzflag);
+    end;
+    tz^.tz_minuteswest := _timezone div 60;
+    tz^.tz_dsttime := _daylight;
+  end;
+  Result := 0;
+end;
+{$ENDIF}
+
+function fopen(filename: PAnsiChar; mode: open_mode): FILEptr;
+var
+  fp: FILEptr;
+  OldFileMode: Byte;
+begin
+  fp := nil;
+  OldFileMode := FileMode;
+  GetMem(fp, SizeOf(File));
+  Assign(fp^, StrPas(filename));
+{$PUSH}{$I-}
+  case mode of
+    fopenread:
+    begin
+      FileMode := 0;
+      Reset(fp^, 1);
+    end;
+    fopenwrite:
+    begin
+      FileMode := 1;
+      ReWrite(fp^, 1);
+    end;
+    fappendwrite:
+    begin
+      FileMode := 2;
+      Reset(fp^, 1);
+      if IOResult = 2 then
+        ReWrite(fp^, 1);
+      Seek(fp^, FileSize(fp^));
+    end;
+  end;
+  FileMode := OldFileMode;
+{$POP}
+  if IOResult <> 0 then
+  begin
+    FreeMem(fp, SizeOf(File));
+    fp := nil;
+  end;
+  fopen := fp;
+end;
+
+procedure fclose(fp : FILEptr);
+begin
+  if Assigned(fp) then
+  begin
+{$PUSH}{$I-}
+    Close(fp^);
+{$POP}
+    if IOresult = 0 then
+      FreeMem(fp, SizeOf(File));
+  end;
+end;
+
+function fread(buf: Pointer; recSize: LongInt; recCount: LongInt;
+  fp : FILEptr): LongInt;
+var
+  totalSize, readcount : LongInt;
+begin
+  if Assigned(buf) then
+  begin
+    totalSize := recCount * LongInt(recSize);
+{$PUSH}{$I-}{$HINTS OFF}
+    BlockRead(fp^, buf^, totalSize, readcount);
+    if readcount <> totalSize then
+      fread := readcount div recSize
+    else
+      fread := recCount;
+{$POP}
+  end
+  else
+    fread := 0;
+end;
+
+function fwrite(buf: Pointer; recSize: LongInt; recCount: LongInt;
+  fp: FILEptr) : LongInt;
+var
+  totalSize, written: LongInt;
+begin
+  if Assigned(buf) then
+  begin
+    totalSize := recCount * LongInt(recSize);
+{$PUSH}{$I-}{$HINTS OFF}
+    BlockWrite(fp^, buf^, totalSize, written);
+    if written <> totalSize then
+      fwrite := written div recSize
+    else
+      fwrite := recCount;
+{$POP}
+  end
+  else
+    fwrite := 0;
+end;
+
+function fseek(fp: FILEptr; recPos: LongInt; mode: seek_mode): LongInt;
+begin
+{$PUSH}{$I-}
+  case mode of
+    SEEK_SET: Seek(fp^, recPos);
+    SEEK_CUR: Seek(fp^, FilePos(fp^) + recPos);
+    SEEK_END: Seek(fp^, FileSize(fp^) - 1 - recPos);
+  end;
+{$POP}
+  fseek := IOResult;
+end;
+
+function ftell(fp: FILEptr): LongInt;
+begin
+  ftell := FilePos(fp^);
+end;
+
+function feof(fp: FILEptr): LongInt;
+begin
+  feof := 0;
+  if Assigned(fp) then
+    if eof(fp^) then
+      feof := 1
+    else
+      feof := 0;
+end;
+
+end.

+ 811 - 0
packages/libmicrohttpd/examples/demo.pp

@@ -0,0 +1,811 @@
+(*
+     This file is part of libmicrohttpd
+     Copyright (C) 2013 Christian Grothoff (and other contributing authors)
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*)
+
+(**
+ * @file demo.pp (Original: demo.c)
+ * @brief complex demonstration site: create directory index, offer
+ *        upload via form and HTTP POST, download with mime type detection
+ *        and error reporting (403, etc.) --- and all of this with
+ *        high-performance settings (large buffers, thread pool).
+ *        If you want to benchmark MHD, this code should be used to
+ *        run tests against.  Note that the number of threads may need
+ *        to be adjusted depending on the number of available cores.
+ * @author Christian Grothoff
+ *)
+
+program demo;
+
+{$mode objfpc}{$H+}
+{$MACRO ON}
+{$IF DEFINED(CPU_COUNT) AND (CPU_COUNT + 0) < 2}
+  {$UNDEF CPU_COUNT}
+{$ENDIF}
+{$IF NOT DEFINED(CPU_COUNT)}
+  {$DEFINE CPU_COUNT := 2}
+{$ENDIF}
+
+uses
+  sysutils, pthreads, ctypes, BaseUnix, cmem, cutils, libmicrohttpd;
+
+type
+{$i magic.inc}
+
+const
+
+  (**
+   * Number of threads to run in the thread pool.  Should (roughly) match
+   * the number of cores on your system.
+   *)
+  NUMBER_OF_THREADS = CPU_COUNT;
+
+  (**
+   * How many bytes of a file do we give to libmagic to determine the mime type?
+   * 16k might be a bit excessive, but ought not hurt performance much anyway,
+   * and should definitively be on the safe side.
+   *)
+  MAGIC_HEADER_SIZE = 16 * 1024;
+
+  (**
+   * Page returned for file-not-found.
+   *)
+  FILE_NOT_FOUND_PAGE: Pcchar = '<html><head><title>File not found</title></head><body>File not found</body></html>';
+
+  (**
+   * Page returned for internal errors.
+   *)
+  INTERNAL_ERROR_PAGE: Pcchar = '<html><head><title>Internal error</title></head><body>Internal error</body></html>';
+
+
+  (**
+   * Page returned for refused requests.
+   *)
+  REQUEST_REFUSED_PAGE: Pcchar = '<html><head><title>Request refused</title></head><body>Request refused (file exists?)</body></html>';
+
+  (**
+   * Head of index page.
+   *)
+  INDEX_PAGE_HEADER = '<html>'#10'<head><title>Welcome</title></head>'#10'<body>'#10+
+    '<h1>Upload</h1>'#10+
+    '<form method="POST" enctype="multipart/form-data" action="/">'#10+
+    '<dl><dt>Content type:</dt><dd>'+
+    '<input type="radio" name="category" value="books">Book</input>'+
+    '<input type="radio" name="category" value="images">Image</input>'+
+    '<input type="radio" name="category" value="music">Music</input>'+
+    '<input type="radio" name="category" value="software">Software</input>'+
+    '<input type="radio" name="category" value="videos">Videos</input>'#10+
+    '<input type="radio" name="category" value="other" checked>Other</input></dd>'+
+    '<dt>Language:</dt><dd>'+
+    '<input type="radio" name="language" value="no-lang" checked>none</input>'+
+    '<input type="radio" name="language" value="en">English</input>'+
+    '<input type="radio" name="language" value="de">German</input>'+
+    '<input type="radio" name="language" value="fr">French</input>'+
+    '<input type="radio" name="language" value="es">Spanish</input></dd>'#10+
+    '<dt>File:</dt><dd>'+
+    '<input type="file" name="upload"/></dd></dl>'+
+    '<input type="submit" value="Send!"/>'#10+
+    '</form>'#10+
+    '<h1>Download</h1>'#10+
+    '<ol>'#10;
+
+  (**
+   * Footer of index page.
+   *)
+  INDEX_PAGE_FOOTER = '</ol>'#10'</body>'#10'</html>';
+
+  (**
+   * NULL-terminated array of supported upload categories.  Should match HTML
+   * in the form.
+   *)
+  categories: array[0..6] of Pcchar = (
+    'books',
+    'images',
+    'music',
+    'software',
+    'videos',
+    'other',
+    nil
+  );
+
+type
+
+  (**
+   * Specification of a supported language.
+   *)
+  Language = packed record
+    (**
+     * Directory name for the language.
+     *)
+    dirname: Pcchar;
+
+    (**
+     * Long name for humans.
+     *)
+    longname: Pcchar;
+  end;
+  PLanguage = ^Language;
+
+const
+  (**
+   * NULL-terminated array of supported upload categories.  Should match HTML
+   * in the form.
+   *)
+  languages: array[0..5] of Language = (
+    (dirname: 'no-lang'; longname: 'No language specified'),
+    (dirname: 'en'; longname: 'English'),
+    (dirname: 'de'; longname: 'German'),
+    (dirname: 'fr'; longname: 'French'),
+    (dirname: 'es'; longname: 'Spanish'),
+    (dirname: nil; longname: nil)
+  );
+
+var
+  (**
+   * Response returned if the requested file does not exist (or is not accessible).
+   *)
+  file_not_found_response: PMHD_Response;
+
+  (**
+   * Response returned for internal errors.
+   *)
+  internal_error_response: PMHD_Response;
+
+  (**
+   * Response returned for '/' (GET) to list the contents of the directory and allow upload.
+   *)
+  cached_directory_response: PMHD_Response;
+
+  (**
+   * Response returned for refused uploads.
+   *)
+  request_refused_response: PMHD_Response;
+
+  (**
+   * Mutex used when we update the cached directory response object.
+   *)
+  mutex: pthread_mutex_t;
+
+  (**
+   * Global handle to MAGIC data.
+   *)
+  magic: magic_t;
+
+  (**
+   * Mark the given response as HTML for the brower.
+   *
+   * @param response response to mark
+   *)
+  procedure mark_as_html(response: PMHD_Response);
+  begin
+    MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE, 'text/html');
+  end;
+
+  (**
+   * Replace the existing 'cached_directory_response' with the
+   * given response.
+   *
+   * @param response new directory response
+   *)
+  procedure update_cached_response(response: PMHD_Response);
+  begin
+    pthread_mutex_lock(@mutex);
+    if nil <> cached_directory_response then
+      MHD_destroy_response(cached_directory_response);
+    cached_directory_response := response;
+    pthread_mutex_unlock(@mutex);
+  end;
+
+type
+  (**
+   * Context keeping the data for the response we're building.
+   *)
+  ResponseDataContext = packed record
+    (**
+     * Response data string.
+     *)
+    buf: Pcchar;
+
+    (**
+     * Number of bytes allocated for 'buf'.
+     *)
+    buf_len: size_t;
+
+    (**
+     * Current position where we append to 'buf'. Must be smaller or equal to 'buf_len'.
+     *)
+    off: size_t;
+  end;
+  PResponseDataContext = ^ResponseDataContext;
+
+  (**
+   * Create a listing of the files in 'dirname' in HTML.
+   *
+   * @param rdc where to store the list of files
+   * @param dirname name of the directory to list
+   * @return MHD_YES on success, MHD_NO on error
+   *)
+  function list_directory(rdc: PResponseDataContext; dirname: Pcchar): cint; cdecl;
+  var
+    fullname: array[0..PATH_MAX] of AnsiChar;
+    sbuf: stat;
+    dir: pDir;
+    de: pDirent;
+    r: Pointer;
+  begin
+    dir := FpOpendir(dirname);
+    if nil = dir then
+      Exit(MHD_NO);
+    while True do
+    begin
+      de := FpReaddir(dir^);
+      if de = nil then
+        Break;
+      if '.' = de^.d_name[0] then
+        Continue;
+      if SizeOf(fullname) <= size_t(
+        snprintf(fullname, SizeOf(fullname), '%s/%s', dirname, de^.d_name)) then
+        Continue; (* ugh, file too long? how can this be!? *)
+      if 0 <> FpStat(PAnsiChar(fullname), sbuf) then
+        Continue; (* ugh, failed to 'stat' *)
+      if not fpS_ISREG(sbuf.st_mode) then
+        Continue; (* not a regular file, skip *)
+      if rdc^.off + 1024 > rdc^.buf_len then
+      begin
+        if (2 * rdc^.buf_len + 1024) < rdc^.buf_len then
+          Break; (* more than SIZE_T _index_ size? Too big for us *)
+        rdc^.buf_len := 2 * rdc^.buf_len + 1024;
+        r := ReAlloc(rdc^.buf, rdc^.buf_len);
+        if nil = r then
+          Break; (* out of memory *)
+        rdc^.buf := r;
+      end;
+      rdc^.off += snprintf(@rdc^.buf[rdc^.off], rdc^.buf_len - rdc^.off,
+                    '<li><a href="/%s">%s</a></li>'#10, fullname, de^.d_name);
+    end;
+    FpClosedir(dir^);
+    Result := MHD_YES;
+  end;
+
+  (**
+   * Re-scan our local directory and re-build the index.
+   *)
+  procedure update_directory;
+  const
+    initial_allocation: size_t = 32 * 1024; (* initial size for response buffer *)
+  var
+    response: PMHD_Response;
+    rdc: ResponseDataContext;
+    language_idx: cuint;
+    category_idx: cuint;
+    language: PLanguage;
+    category: Pcchar;
+    dir_name: array[0..128] of AnsiChar;
+    sbuf: stat;
+  begin
+    rdc.buf_len := initial_allocation;
+    rdc.buf := Malloc(rdc.buf_len);
+    if nil = rdc.buf then
+    begin
+      update_cached_response(nil);
+      Exit;
+    end;
+    rdc.off := snprintf(rdc.buf, rdc.buf_len, '%s', INDEX_PAGE_HEADER);
+    language_idx := 0;
+    while True do
+    begin
+      try
+        if languages[language_idx].dirname = nil then
+          Break;
+        language := @languages[language_idx];
+        if 0 <> FpStat(language^.dirname, sbuf) then
+          Continue; (* empty *)
+        (* we ensured always +1k room, filenames are ~256 bytes,
+           so there is always still enough space for the header
+           without need for an additional reallocation check. *)
+        rdc.off += snprintf(@rdc.buf[rdc.off], rdc.buf_len - rdc.off,
+                     '<h2>%s</h2>'#10, language^.longname);
+        category_idx := 0;
+        while True do
+        begin
+          try
+            if categories[category_idx] = nil then
+              Break;
+            category := categories[category_idx];
+            snprintf(dir_name, sizeof(dir_name), '%s/%s', language^.dirname, category);
+            if 0 <> FpStat(PAnsiChar(dir_name), sbuf) then
+              Continue; (* empty *)
+            (* we ensured always +1k room, filenames are ~256 bytes,
+               so there is always still enough space for the header
+               without need for an additional reallocation check. *)
+            rdc.off += snprintf(@rdc.buf[rdc.off], rdc.buf_len - rdc.off,
+                         '<h3>%s</h3>'#10, category);
+            if MHD_NO = list_directory(@rdc, dir_name) then
+            begin
+              Free(rdc.buf);
+              update_cached_response(nil);
+              Exit;
+            end;
+          finally
+            Inc(category_idx);
+          end;
+        end;
+      finally
+        Inc(language_idx);
+      end;
+    end;
+    (* we ensured always +1k room, filenames are ~256 bytes,
+         so there is always still enough space for the footer
+         without need for a final reallocation check. *)
+    rdc.off += snprintf(@rdc.buf[rdc.off], rdc.buf_len - rdc.off, '%s',
+      INDEX_PAGE_FOOTER);
+    initial_allocation := rdc.buf_len; (* remember for next time *)
+    response := MHD_create_response_from_buffer(rdc.off, rdc.buf,
+      MHD_RESPMEM_MUST_FREE);
+    mark_as_html(response);
+{$IFDEF FORCE_CLOSE}
+    MHD_add_response_header (response, MHD_HTTP_HEADER_CONNECTION, 'close');
+{$ENDIF}
+    update_cached_response(response);
+  end;
+
+type
+  (**
+   * Context we keep for an upload.
+   *)
+  UploadContext = packed record
+    (**
+     * Handle where we write the uploaded file to.
+     *)
+    fd: cint;
+
+    (**
+     * Name of the file on disk (used to remove on errors).
+     *)
+    filename: Pcchar;
+
+    (**
+     * Language for the upload.
+     *)
+    language: Pcchar;
+
+    (**
+     * Category for the upload.
+     *)
+    category: Pcchar;
+
+    (**
+     * Post processor we're using to process the upload.
+     *)
+    pp: PMHD_PostProcessor;
+
+    (**
+     * Handle to connection that we're processing the upload for.
+     *)
+    connection: PMHD_Connection;
+
+    (**
+     * Response to generate, NULL to use directory.
+     *)
+    response: PMHD_Response;
+  end;
+  PUploadContext = ^UploadContext;
+
+  (**
+   * Append the 'size' bytes from 'data' to '*ret', adding
+   * 0-termination.  If '*ret' is NULL, allocate an empty string first.
+   *
+   * @param ret string to update, NULL or 0-terminated
+   * @param data data to append
+   * @param size number of bytes in 'data'
+   * @return MHD_NO on allocation failure, MHD_YES on success
+   *)
+  function do_append(ret: Ppcchar; data: Pcchar; size: size_t): cint; cdecl;
+  var
+    buf: Pcchar;
+    old_len: size_t;
+  begin
+    if nil = ret^ then
+      old_len := 0
+    else
+      old_len := strlen(ret^);
+    buf := Malloc(old_len + size + 1);
+    if nil = buf then
+      Exit(MHD_NO);
+    Move(ret^^, buf, old_len);
+    if nil <> ret^ then
+      Free(ret^);
+    Move(data^, buf[old_len], size);
+    buf[old_len + size] := #0;
+    ret^ := buf;
+    Result := MHD_YES;
+  end;
+
+  (**
+   * Iterator over key-value pairs where the value
+   * maybe made available in increments and/or may
+   * not be zero-terminated.  Used for processing
+   * POST data.
+   *
+   * @param cls user-specified closure
+   * @param kind type of the value, always MHD_POSTDATA_KIND when called from MHD
+   * @param key 0-terminated key for the value
+   * @param filename name of the uploaded file, NULL if not known
+   * @param content_type mime-type of the data, NULL if not known
+   * @param transfer_encoding encoding of the data, NULL if not known
+   * @param data pointer to size bytes of data at the
+   *              specified offset
+   * @param off offset of data in the overall value
+   * @param size number of bytes in data available
+   * @return MHD_YES to continue iterating,
+   *         MHD_NO to abort the iteration
+   *)
+  function process_upload_data(cls: Pointer; kind: MHD_ValueKind; key: Pcchar;
+    filename: Pcchar; content_type: Pcchar; transfer_encoding: Pcchar;
+    data: Pcchar; off: cuint64; size: size_t): cint; cdecl;
+  var
+    uc: PUploadContext;
+    i: cint;
+    fn: array[0..PATH_MAX] of AnsiChar;
+  begin
+    uc := cls;
+    if 0 = strcomp(key, 'category') then
+      Exit(do_append(@uc^.category, data, size));
+    if 0 = strcomp(key, 'language') then
+      Exit(do_append(@uc^.language, data, size));
+    if 0 <> strcomp(key, 'upload') then
+    begin
+      WriteLn(stderr, Format('Ignoring unexpected form value `%s''', [key]));
+      Exit(MHD_YES); (* ignore *)
+    end;
+    if nil = filename then
+    begin
+      WriteLn(stderr, 'No filename, aborting upload');
+      Exit(MHD_NO); (* no filename, error *)
+    end;
+    if (nil = uc^.category) or (nil = uc^.language) then
+    begin
+      WriteLn(stderr, Format('Missing form data for upload `%s''', [filename]));
+      uc^.response := request_refused_response;
+      Exit(MHD_NO);
+    end;
+    if -1 = uc^.fd then
+    begin
+      if (nil <> strstr(filename, '..')) or (nil <> strchr(filename, Ord('/'))) or
+        (nil <> strchr(filename, Ord('\'))) then
+      begin
+        uc^.response := request_refused_response;
+        Exit(MHD_NO);
+      end;
+      (* create directories -- if they don't exist already *)
+{$IFDEF MSWINDOWS}
+      FpMkdir(uc^.language);
+{$ELSE}
+      FpMkdir(uc^.language, S_IRWXU);
+{$ENDIF}
+      snprintf(fn, SizeOf(fn), '%s/%s', uc^.language, uc^.category);
+{$IFDEF MSWINDOWS}
+      FpMkdir(fn);
+{$ELSE}
+      FpMkdir(PAnsiChar(fn), S_IRWXU);
+{$ENDIF}
+      (* open file *)
+      snprintf(fn, sizeof(fn), '%s/%s/%s', uc^.language, uc^.category, filename);
+      for i := strlen(fn) - 1 downto 0 do
+        if isprint(fn[i]) = 1 then
+          fn[i] := '_';
+      uc^.fd := FpOpen(PAnsiChar(fn), O_CREAT or O_EXCL
+{$IFDEF O_LARGEFILE}
+                  or O_LARGEFILE
+{$ENDIF}
+                  or O_WRONLY, S_IRUSR or S_IWUSR);
+      if -1 = uc^.fd then
+      begin
+        WriteLn(stderr, Format('Error opening file `%s'' for upload: %s',
+          [fn, strerror(errno^)]));
+        uc^.response := request_refused_response;
+        Exit(MHD_NO);
+      end;
+      uc^.filename := strdup(fn);
+    end;
+    if (0 <> size) and (size <> size_t(FpWrite(uc^.fd, data, size))) then
+    begin
+      (* write failed; likely: disk full *)
+      WriteLn(stderr, Format('Error writing to file `%s'': %s', [uc^.filename,
+        strerror(errno^)]));
+      uc^.response := internal_error_response;
+      FpClose(uc^.fd);
+      uc^.fd := -1;
+      if nil <> uc^.filename then
+      begin
+        FpUnlink(uc^.filename);
+        Free(uc^.filename);
+        uc^.filename := nil;
+      end;
+      Exit(MHD_NO);
+    end;
+    Exit(MHD_YES);
+  end;
+
+  (**
+   * Function called whenever a request was completed.
+   * Used to clean up 'struct UploadContext' objects.
+   *
+   * @param cls client-defined closure, NULL
+   * @param connection connection handle
+   * @param con_cls value as set by the last call to
+   *        the MHD_AccessHandlerCallback, points to NULL if this was
+   *            not an upload
+   * @param toe reason for request termination
+   *)
+  procedure response_completed_callback(cls: Pointer; connection: PMHD_Connection;
+    con_cls: PPointer; toe: MHD_RequestTerminationCode); cdecl;
+  var
+    uc: PUploadContext;
+  begin
+    uc := con_cls^;
+    if nil = uc then
+      Exit; (* this request wasn't an upload request *)
+    if nil <> uc^.pp then
+    begin
+      MHD_destroy_post_processor(uc^.pp);
+      uc^.pp := nil;
+    end;
+    if -1 <> uc^.fd then
+    begin
+      FpClose(uc^.fd);
+      if nil <> uc^.filename then
+      begin
+        WriteLn(stderr, Format(
+          'Upload of file `%s'' failed (incomplete or aborted), removing file.',
+          [uc^.filename]));
+        FpUnlink(uc^.filename);
+      end;
+    end;
+    if nil <> uc^.filename then
+      Free(uc^.filename);
+    Free(uc);
+  end;
+
+  (**
+   * Return the current directory listing.
+   *
+   * @param connection connection to return the directory for
+   * @return MHD_YES on success, MHD_NO on error
+   *)
+  function return_directory_response(connection: PMHD_Connection): cint;
+  var
+    ret: cint;
+  begin
+    pthread_mutex_lock(@mutex);
+    if nil = cached_directory_response then
+      ret := MHD_queue_response(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
+        internal_error_response)
+    else
+      ret := MHD_queue_response(connection, MHD_HTTP_OK,
+        cached_directory_response);
+    pthread_mutex_unlock(@mutex);
+    Result := ret;
+  end;
+
+  (**
+   * Main callback from MHD, used to generate the page.
+   *
+   * @param cls NULL
+   * @param connection connection handle
+   * @param url requested URL
+   * @param method GET, PUT, POST, etc.
+   * @param version HTTP version
+   * @param upload_data data from upload (PUT/POST)
+   * @param upload_data_size number of bytes in "upload_data"
+   * @param ptr our context
+   * @return MHD_YES on success, MHD_NO to drop connection
+   *)
+  function generate_page(cls: Pointer; connection: PMHD_Connection; url: Pcchar;
+    method: Pcchar; version: Pcchar; upload_data: Pcchar;
+    upload_data_size: Psize_t; ptr: PPointer): cint; cdecl;
+  var
+    response: PMHD_Response;
+    ret: cint;
+    fd: cint;
+    buf: stat;
+    (* should be file download *)
+    file_data: array[0..MAGIC_HEADER_SIZE] of AnsiChar;
+    got: ssize_t ;
+    mime: Pcchar;
+    uc: PUploadContext;
+  begin
+    if 0 <> strcomp(url, '/') then
+    begin
+      if (0 <> strcomp(method, MHD_HTTP_METHOD_GET)) and
+        (0 <> strcomp(method, MHD_HTTP_METHOD_HEAD)) then
+        Exit(MHD_NO);  (* unexpected method (we're not polite...) *)
+      if (0 = FpStat(@url[1], buf)) and (nil = strstr(@url[1], '..')) and
+        ('/' <> url[1]) then
+        fd := FpOpen(@url[1], O_RDONLY)
+      else
+        fd := -1;
+      if -1 = fd then
+        Exit(MHD_queue_response(connection, MHD_HTTP_NOT_FOUND,
+          file_not_found_response));
+      (* read beginning of the file to determine mime type  *)
+      got := FpRead(fd, file_data, SizeOf(file_data));
+      if -1 <> got then
+        mime := magic_buffer(magic, Pcchar(file_data), got)
+      else
+        mime := nil;
+      lseek(fd, 0, SEEK_SET);
+      response := MHD_create_response_from_fd(buf.st_size, fd);
+      if nil = response then
+      begin
+        (* internal error (i.e. out of memory) *)
+        FpClose(fd);
+        Exit(MHD_NO);
+      end;
+      (* add mime type if we had one *)
+      if nil <> mime then
+        MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE, mime);
+      ret := MHD_queue_response(connection, MHD_HTTP_OK, response);
+      MHD_destroy_response(response);
+      Exit(ret);
+    end;
+    if 0 = strcomp(method, MHD_HTTP_METHOD_POST) then
+    begin
+      (* upload! *)
+      uc := ptr^;
+      if nil = uc then
+      begin
+        uc := Malloc(SizeOf(UploadContext));
+        if nil = uc then
+          Exit(MHD_NO); (* out of memory, close connection *)
+        memset(uc, 0, SizeOf(UploadContext));
+        uc^.fd := -1;
+        uc^.connection := connection;
+        uc^.pp := MHD_create_post_processor(connection, 64 * 1024 (* buffer size *),
+                   @process_upload_data, uc);
+        if nil = uc^.pp then
+        begin
+          (* out of memory, close connection *)
+          Free(uc);
+          Exit(MHD_NO);
+        end;
+        ptr^ := uc;
+        Exit(MHD_YES);
+      end;
+      if 0 <> upload_data_size^ then
+      begin
+        if nil = uc^.response then
+          MHD_post_process(uc^.pp, upload_data, upload_data_size^);
+        upload_data_size^ := 0;
+        Exit(MHD_YES);
+      end;
+      (* end of upload, finish it! *)
+      MHD_destroy_post_processor(uc^.pp);
+      uc^.pp := nil;
+      if -1 <> uc^.fd then
+      begin
+        FpClose(uc^.fd);
+        uc^.fd := -1;
+      end;
+      if nil <> uc^.response then
+        Exit(MHD_queue_response(connection, MHD_HTTP_FORBIDDEN, uc^.response))
+      else
+      begin
+        update_directory;
+        Exit(return_directory_response(connection));
+      end;
+    end;
+    if (0 = strcomp(method, MHD_HTTP_METHOD_GET)) or
+      (0 = strcomp(method, MHD_HTTP_METHOD_HEAD)) then
+      Exit(return_directory_response(connection));
+    (* unexpected request, refuse *)
+    Result := MHD_queue_response(connection, MHD_HTTP_FORBIDDEN,
+      request_refused_response);
+  end;
+
+  (**
+   * Function called if we get a SIGPIPE. Does nothing.
+   *
+   * @param sig will be SIGPIPE (ignored)
+   *)
+  procedure catcher(signal: longint; info: psiginfo; context: psigcontext); cdecl;
+  begin
+    (* do nothing *)
+  end;
+
+  (**
+   * setup handlers to ignore SIGPIPE.
+   *)
+  procedure ignore_sigpipe;
+  var
+    oldsig: sigactionrec;
+    sig: sigactionrec;
+  begin
+    sig.sa_handler := @catcher;
+    FpsigEmptySet(sig.sa_mask);
+  {$IFDEF SA_INTERRUPT}
+    sig.sa_flags := SA_INTERRUPT; (* SunOS *)
+  {$ELSE}
+    sig.sa_flags := SA_RESTART;
+  {$ENDIF}
+    if 0 <> FPSigaction(SIGPIPE, @sig, @oldsig) then
+      WriteLn(stderr, Format('Failed to install SIGPIPE handler: %s',
+        [strerror(errno^)]));
+  end;
+
+  (**
+   * Entry point to demo.  Note: this HTTP server will make all
+   * files in the current directory and its subdirectories available
+   * to anyone.  Press ENTER to stop the server once it has started.
+   *
+   * @param argc number of arguments in argv
+   * @param argv first and only argument should be the port number
+   * @return 0 on success
+   *)
+var
+  d: PMHD_Daemon;
+  port: cuint;
+begin
+  if (argc <> 2) or (1 <> sscanf(argv[1], '%u', @port)) or
+    (UINT16_MAX < port) then
+  begin
+    WriteLn(stderr, argv[0], ' PORT');
+    Halt(1);
+  end;
+  ignore_sigpipe;
+  magic := magic_open(MAGIC_MIME_TYPE);
+  magic_load(magic, nil);
+  pthread_mutex_init(@mutex, nil);
+  file_not_found_response := MHD_create_response_from_buffer(
+    strlen(FILE_NOT_FOUND_PAGE), FILE_NOT_FOUND_PAGE,
+    MHD_RESPMEM_PERSISTENT);
+  mark_as_html(file_not_found_response);
+  request_refused_response := MHD_create_response_from_buffer(
+    strlen(REQUEST_REFUSED_PAGE), REQUEST_REFUSED_PAGE,
+    MHD_RESPMEM_PERSISTENT);
+  mark_as_html(request_refused_response);
+  internal_error_response := MHD_create_response_from_buffer(
+    strlen(INTERNAL_ERROR_PAGE), INTERNAL_ERROR_PAGE,
+    MHD_RESPMEM_PERSISTENT);
+  mark_as_html(internal_error_response);
+  update_directory;
+  d := MHD_start_daemon(MHD_USE_SELECT_INTERNALLY or MHD_USE_DEBUG
+{$IFDEF EPOLL_SUPPORT}
+         or MHD_USE_EPOLL_LINUX_ONLY
+{$ENDIF},
+         port, nil, nil, @generate_page, nil,
+         MHD_OPTION_CONNECTION_MEMORY_LIMIT, size_t(256 * 1024),
+{$IFDEF PRODUCTION}
+         MHD_OPTION_PER_IP_CONNECTION_LIMIT, cuint(64),
+{$ENDIF}
+         MHD_OPTION_CONNECTION_TIMEOUT, cuint(120 (* seconds *)),
+         MHD_OPTION_THREAD_POOL_SIZE, cuint(NUMBER_OF_THREADS),
+         MHD_OPTION_NOTIFY_COMPLETED, @response_completed_callback, nil,
+         MHD_OPTION_END);
+  if nil = d then
+    Halt(1);
+  WriteLn(stderr, 'HTTP server running. Press ENTER to stop the server');
+  ReadLn;
+  MHD_stop_daemon(d);
+  MHD_destroy_response(file_not_found_response);
+  MHD_destroy_response(request_refused_response);
+  MHD_destroy_response(internal_error_response);
+  update_cached_response(nil);
+  pthread_mutex_destroy(@mutex);
+  magic_close(magic);
+end.
+

+ 865 - 0
packages/libmicrohttpd/examples/demo_https.pp

@@ -0,0 +1,865 @@
+(*
+     This file is part of libmicrohttpd
+     Copyright (C) 2013 Christian Grothoff (and other contributing authors)
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*)
+
+(**
+ * @file demo_https.pp (Original: demo_https.c)
+ * @brief complex demonstration site: create directory index, offer
+ *        upload via form and HTTP POST, download with mime type detection
+ *        and error reporting (403, etc.) --- and all of this with
+ *        high-performance settings (large buffers, thread pool).
+ *        If you want to benchmark MHD, this code should be used to
+ *        run tests against.  Note that the number of threads may need
+ *        to be adjusted depending on the number of available cores.
+ *        Logic is identical to demo.pp, just adds HTTPS support.
+ * @author Christian Grothoff
+ *)
+
+program demo_https;
+
+{$mode objfpc}{$H+}
+{$MACRO ON}
+{$IF DEFINED(CPU_COUNT) AND (CPU_COUNT + 0) < 2}
+  {$UNDEF CPU_COUNT}
+{$ENDIF}
+{$IF NOT DEFINED(CPU_COUNT)}
+  {$DEFINE CPU_COUNT := 2}
+{$ENDIF}
+
+uses
+  sysutils, pthreads, ctypes, BaseUnix, cmem, cutils, libmicrohttpd;
+
+type
+{$i magic.inc}
+
+const
+
+  (**
+   * Number of threads to run in the thread pool.  Should (roughly) match
+   * the number of cores on your system.
+   *)
+  NUMBER_OF_THREADS = CPU_COUNT;
+
+  (**
+   * How many bytes of a file do we give to libmagic to determine the mime type?
+   * 16k might be a bit excessive, but ought not hurt performance much anyway,
+   * and should definitively be on the safe side.
+   *)
+  MAGIC_HEADER_SIZE = 16 * 1024;
+
+  (**
+   * Page returned for file-not-found.
+   *)
+  FILE_NOT_FOUND_PAGE: Pcchar = '<html><head><title>File not found</title></head><body>File not found</body></html>';
+
+  (**
+   * Page returned for internal errors.
+   *)
+  INTERNAL_ERROR_PAGE: Pcchar = '<html><head><title>Internal error</title></head><body>Internal error</body></html>';
+
+
+  (**
+   * Page returned for refused requests.
+   *)
+  REQUEST_REFUSED_PAGE: Pcchar = '<html><head><title>Request refused</title></head><body>Request refused (file exists?)</body></html>';
+
+  (**
+   * Head of index page.
+   *)
+  INDEX_PAGE_HEADER = '<html>'#10'<head><title>Welcome</title></head>'#10'<body>'#10+
+    '<h1>Upload</h1>'#10+
+    '<form method="POST" enctype="multipart/form-data" action="/">'#10+
+    '<dl><dt>Content type:</dt><dd>'+
+    '<input type="radio" name="category" value="books">Book</input>'+
+    '<input type="radio" name="category" value="images">Image</input>'+
+    '<input type="radio" name="category" value="music">Music</input>'+
+    '<input type="radio" name="category" value="software">Software</input>'+
+    '<input type="radio" name="category" value="videos">Videos</input>'#10+
+    '<input type="radio" name="category" value="other" checked>Other</input></dd>'+
+    '<dt>Language:</dt><dd>'+
+    '<input type="radio" name="language" value="no-lang" checked>none</input>'+
+    '<input type="radio" name="language" value="en">English</input>'+
+    '<input type="radio" name="language" value="de">German</input>'+
+    '<input type="radio" name="language" value="fr">French</input>'+
+    '<input type="radio" name="language" value="es">Spanish</input></dd>'#10+
+    '<dt>File:</dt><dd>'+
+    '<input type="file" name="upload"/></dd></dl>'+
+    '<input type="submit" value="Send!"/>'#10+
+    '</form>'#10+
+    '<h1>Download</h1>'#10+
+    '<ol>'#10;
+
+  (**
+   * Footer of index page.
+   *)
+  INDEX_PAGE_FOOTER = '</ol>'#10'</body>'#10'</html>';
+
+  (**
+   * NULL-terminated array of supported upload categories.  Should match HTML
+   * in the form.
+   *)
+  categories: array[0..6] of Pcchar = (
+    'books',
+    'images',
+    'music',
+    'software',
+    'videos',
+    'other',
+    nil
+  );
+
+type
+
+  (**
+   * Specification of a supported language.
+   *)
+  Language = packed record
+    (**
+     * Directory name for the language.
+     *)
+    dirname: Pcchar;
+
+    (**
+     * Long name for humans.
+     *)
+    longname: Pcchar;
+  end;
+  PLanguage = ^Language;
+
+const
+  (**
+   * NULL-terminated array of supported upload categories.  Should match HTML
+   * in the form.
+   *)
+  languages: array[0..5] of Language = (
+    (dirname: 'no-lang'; longname: 'No language specified'),
+    (dirname: 'en'; longname: 'English'),
+    (dirname: 'de'; longname: 'German'),
+    (dirname: 'fr'; longname: 'French'),
+    (dirname: 'es'; longname: 'Spanish'),
+    (dirname: nil; longname: nil)
+  );
+
+var
+  (**
+   * Response returned if the requested file does not exist (or is not accessible).
+   *)
+  file_not_found_response: PMHD_Response;
+
+  (**
+   * Response returned for internal errors.
+   *)
+  internal_error_response: PMHD_Response;
+
+  (**
+   * Response returned for '/' (GET) to list the contents of the directory and allow upload.
+   *)
+  cached_directory_response: PMHD_Response;
+
+  (**
+   * Response returned for refused uploads.
+   *)
+  request_refused_response: PMHD_Response;
+
+  (**
+   * Mutex used when we update the cached directory response object.
+   *)
+  mutex: pthread_mutex_t;
+
+  (**
+   * Global handle to MAGIC data.
+   *)
+  magic: magic_t;
+
+  (**
+   * Mark the given response as HTML for the brower.
+   *
+   * @param response response to mark
+   *)
+  procedure mark_as_html(response: PMHD_Response);
+  begin
+    MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE, 'text/html');
+  end;
+
+  (**
+   * Replace the existing 'cached_directory_response' with the
+   * given response.
+   *
+   * @param response new directory response
+   *)
+  procedure update_cached_response(response: PMHD_Response);
+  begin
+    pthread_mutex_lock(@mutex);
+    if nil <> cached_directory_response then
+      MHD_destroy_response(cached_directory_response);
+    cached_directory_response := response;
+    pthread_mutex_unlock(@mutex);
+  end;
+
+type
+  (**
+   * Context keeping the data for the response we're building.
+   *)
+  ResponseDataContext = packed record
+    (**
+     * Response data string.
+     *)
+    buf: Pcchar;
+
+    (**
+     * Number of bytes allocated for 'buf'.
+     *)
+    buf_len: size_t;
+
+    (**
+     * Current position where we append to 'buf'. Must be smaller or equal to 'buf_len'.
+     *)
+    off: size_t;
+  end;
+  PResponseDataContext = ^ResponseDataContext;
+
+  (**
+   * Create a listing of the files in 'dirname' in HTML.
+   *
+   * @param rdc where to store the list of files
+   * @param dirname name of the directory to list
+   * @return MHD_YES on success, MHD_NO on error
+   *)
+  function list_directory(rdc: PResponseDataContext; dirname: Pcchar): cint; cdecl;
+  var
+    fullname: array[0..PATH_MAX] of AnsiChar;
+    sbuf: stat;
+    dir: pDir;
+    de: pDirent;
+    r: Pointer;
+  begin
+    dir := FpOpendir(dirname);
+    if nil = dir then
+      Exit(MHD_NO);
+    while True do
+    begin
+      de := FpReaddir(dir^);
+      if de = nil then
+        Break;
+      if '.' = de^.d_name[0] then
+        Continue;
+      if SizeOf(fullname) <= size_t(
+        snprintf(fullname, SizeOf(fullname), '%s/%s', dirname, de^.d_name)) then
+        Continue; (* ugh, file too long? how can this be!? *)
+      if 0 <> FpStat(PAnsiChar(fullname), sbuf) then
+        Continue; (* ugh, failed to 'stat' *)
+      if not fpS_ISREG(sbuf.st_mode) then
+        Continue; (* not a regular file, skip *)
+      if rdc^.off + 1024 > rdc^.buf_len then
+      begin
+        if (2 * rdc^.buf_len + 1024) < rdc^.buf_len then
+          Break; (* more than SIZE_T _index_ size? Too big for us *)
+        rdc^.buf_len := 2 * rdc^.buf_len + 1024;
+        r := ReAlloc(rdc^.buf, rdc^.buf_len);
+        if nil = r then
+          Break; (* out of memory *)
+        rdc^.buf := r;
+      end;
+      rdc^.off += snprintf(@rdc^.buf[rdc^.off], rdc^.buf_len - rdc^.off,
+                    '<li><a href="/%s">%s</a></li>'#10, fullname, de^.d_name);
+    end;
+    FpClosedir(dir^);
+    Result := MHD_YES;
+  end;
+
+  (**
+   * Re-scan our local directory and re-build the index.
+   *)
+  procedure update_directory;
+  const
+    initial_allocation: size_t = 32 * 1024; (* initial size for response buffer *)
+  var
+    response: PMHD_Response;
+    rdc: ResponseDataContext;
+    language_idx: cuint;
+    category_idx: cuint;
+    language: PLanguage;
+    category: Pcchar;
+    dir_name: array[0..128] of AnsiChar;
+    sbuf: stat;
+  begin
+    rdc.buf_len := initial_allocation;
+    rdc.buf := Malloc(rdc.buf_len);
+    if nil = rdc.buf then
+    begin
+      update_cached_response(nil);
+      Exit;
+    end;
+    rdc.off := snprintf(rdc.buf, rdc.buf_len, '%s', INDEX_PAGE_HEADER);
+    language_idx := 0;
+    while True do
+    begin
+      try
+        if languages[language_idx].dirname = nil then
+          Break;
+        language := @languages[language_idx];
+        if 0 <> FpStat(language^.dirname, sbuf) then
+          Continue; (* empty *)
+        (* we ensured always +1k room, filenames are ~256 bytes,
+           so there is always still enough space for the header
+           without need for an additional reallocation check. *)
+        rdc.off += snprintf(@rdc.buf[rdc.off], rdc.buf_len - rdc.off,
+                     '<h2>%s</h2>'#10, language^.longname);
+        category_idx := 0;
+        while True do
+        begin
+          try
+            if categories[category_idx] = nil then
+              Break;
+            category := categories[category_idx];
+            snprintf(dir_name, sizeof(dir_name), '%s/%s', language^.dirname, category);
+            if 0 <> FpStat(PAnsiChar(dir_name), sbuf) then
+              Continue; (* empty *)
+            (* we ensured always +1k room, filenames are ~256 bytes,
+               so there is always still enough space for the header
+               without need for an additional reallocation check. *)
+            rdc.off += snprintf(@rdc.buf[rdc.off], rdc.buf_len - rdc.off,
+                         '<h3>%s</h3>'#10, category);
+            if MHD_NO = list_directory(@rdc, dir_name) then
+            begin
+              Free(rdc.buf);
+              update_cached_response(nil);
+              Exit;
+            end;
+          finally
+            Inc(category_idx);
+          end;
+        end;
+      finally
+        Inc(language_idx);
+      end;
+    end;
+    (* we ensured always +1k room, filenames are ~256 bytes,
+         so there is always still enough space for the footer
+         without need for a final reallocation check. *)
+    rdc.off += snprintf(@rdc.buf[rdc.off], rdc.buf_len - rdc.off, '%s',
+      INDEX_PAGE_FOOTER);
+    initial_allocation := rdc.buf_len; (* remember for next time *)
+    response := MHD_create_response_from_buffer(rdc.off, rdc.buf,
+      MHD_RESPMEM_MUST_FREE);
+    mark_as_html(response);
+{$IFDEF FORCE_CLOSE}
+    MHD_add_response_header (response, MHD_HTTP_HEADER_CONNECTION, 'close');
+{$ENDIF}
+    update_cached_response(response);
+  end;
+
+type
+  (**
+   * Context we keep for an upload.
+   *)
+  UploadContext = packed record
+    (**
+     * Handle where we write the uploaded file to.
+     *)
+    fd: cint;
+
+    (**
+     * Name of the file on disk (used to remove on errors).
+     *)
+    filename: Pcchar;
+
+    (**
+     * Language for the upload.
+     *)
+    language: Pcchar;
+
+    (**
+     * Category for the upload.
+     *)
+    category: Pcchar;
+
+    (**
+     * Post processor we're using to process the upload.
+     *)
+    pp: PMHD_PostProcessor;
+
+    (**
+     * Handle to connection that we're processing the upload for.
+     *)
+    connection: PMHD_Connection;
+
+    (**
+     * Response to generate, NULL to use directory.
+     *)
+    response: PMHD_Response;
+  end;
+  PUploadContext = ^UploadContext;
+
+  (**
+   * Append the 'size' bytes from 'data' to '*ret', adding
+   * 0-termination.  If '*ret' is NULL, allocate an empty string first.
+   *
+   * @param ret string to update, NULL or 0-terminated
+   * @param data data to append
+   * @param size number of bytes in 'data'
+   * @return MHD_NO on allocation failure, MHD_YES on success
+   *)
+  function do_append(ret: Ppcchar; data: Pcchar; size: size_t): cint; cdecl;
+  var
+    buf: Pcchar;
+    old_len: size_t;
+  begin
+    if nil = ret^ then
+      old_len := 0
+    else
+      old_len := strlen(ret^);
+    buf := Malloc(old_len + size + 1);
+    if nil = buf then
+      Exit(MHD_NO);
+    Move(ret^^, buf, old_len);
+    if nil <> ret^ then
+      Free(ret^);
+    Move(data^, buf[old_len], size);
+    buf[old_len + size] := #0;
+    ret^ := buf;
+    Result := MHD_YES;
+  end;
+
+  (**
+   * Iterator over key-value pairs where the value
+   * maybe made available in increments and/or may
+   * not be zero-terminated.  Used for processing
+   * POST data.
+   *
+   * @param cls user-specified closure
+   * @param kind type of the value, always MHD_POSTDATA_KIND when called from MHD
+   * @param key 0-terminated key for the value
+   * @param filename name of the uploaded file, NULL if not known
+   * @param content_type mime-type of the data, NULL if not known
+   * @param transfer_encoding encoding of the data, NULL if not known
+   * @param data pointer to size bytes of data at the
+   *              specified offset
+   * @param off offset of data in the overall value
+   * @param size number of bytes in data available
+   * @return MHD_YES to continue iterating,
+   *         MHD_NO to abort the iteration
+   *)
+  function process_upload_data(cls: Pointer; kind: MHD_ValueKind; key: Pcchar;
+    filename: Pcchar; content_type: Pcchar; transfer_encoding: Pcchar;
+    data: Pcchar; off: cuint64; size: size_t): cint; cdecl;
+  var
+    uc: PUploadContext;
+    i: cint;
+    fn: array[0..PATH_MAX] of AnsiChar;
+  begin
+    uc := cls;
+    if 0 = strcomp(key, 'category') then
+      Exit(do_append(@uc^.category, data, size));
+    if 0 = strcomp(key, 'language') then
+      Exit(do_append(@uc^.language, data, size));
+    if 0 <> strcomp(key, 'upload') then
+    begin
+      WriteLn(stderr, Format('Ignoring unexpected form value `%s''', [key]));
+      Exit(MHD_YES); (* ignore *)
+    end;
+    if nil = filename then
+    begin
+      WriteLn(stderr, 'No filename, aborting upload');
+      Exit(MHD_NO); (* no filename, error *)
+    end;
+    if (nil = uc^.category) or (nil = uc^.language) then
+    begin
+      WriteLn(stderr, Format('Missing form data for upload `%s''', [filename]));
+      uc^.response := request_refused_response;
+      Exit(MHD_NO);
+    end;
+    if -1 = uc^.fd then
+    begin
+      if (nil <> strstr(filename, '..')) or (nil <> strchr(filename, Ord('/'))) or
+        (nil <> strchr(filename, Ord('\'))) then
+      begin
+        uc^.response := request_refused_response;
+        Exit(MHD_NO);
+      end;
+      (* create directories -- if they don't exist already *)
+{$IFDEF MSWINDOWS}
+      FpMkdir(uc^.language);
+{$ELSE}
+      FpMkdir(uc^.language, S_IRWXU);
+{$ENDIF}
+      snprintf(fn, SizeOf(fn), '%s/%s', uc^.language, uc^.category);
+{$IFDEF MSWINDOWS}
+      FpMkdir(fn);
+{$ELSE}
+      FpMkdir(PAnsiChar(fn), S_IRWXU);
+{$ENDIF}
+      (* open file *)
+      snprintf(fn, sizeof(fn), '%s/%s/%s', uc^.language, uc^.category, filename);
+      for i := strlen(fn) - 1 downto 0 do
+        if isprint(fn[i]) = 1 then
+          fn[i] := '_';
+      uc^.fd := FpOpen(PAnsiChar(fn), O_CREAT or O_EXCL
+{$IFDEF O_LARGEFILE}
+                  or O_LARGEFILE
+{$ENDIF}
+                  or O_WRONLY, S_IRUSR or S_IWUSR);
+      if -1 = uc^.fd then
+      begin
+        WriteLn(stderr, Format('Error opening file `%s'' for upload: %s',
+          [fn, strerror(errno^)]));
+        uc^.response := request_refused_response;
+        Exit(MHD_NO);
+      end;
+      uc^.filename := strdup(fn);
+    end;
+    if (0 <> size) and (size <> size_t(FpWrite(uc^.fd, data, size))) then
+    begin
+      (* write failed; likely: disk full *)
+      WriteLn(stderr, Format('Error writing to file `%s'': %s', [uc^.filename,
+        strerror(errno^)]));
+      uc^.response := internal_error_response;
+      FpClose(uc^.fd);
+      uc^.fd := -1;
+      if nil <> uc^.filename then
+      begin
+        FpUnlink(uc^.filename);
+        Free(uc^.filename);
+        uc^.filename := nil;
+      end;
+      Exit(MHD_NO);
+    end;
+    Exit(MHD_YES);
+  end;
+
+  (**
+   * Function called whenever a request was completed.
+   * Used to clean up 'struct UploadContext' objects.
+   *
+   * @param cls client-defined closure, NULL
+   * @param connection connection handle
+   * @param con_cls value as set by the last call to
+   *        the MHD_AccessHandlerCallback, points to NULL if this was
+   *            not an upload
+   * @param toe reason for request termination
+   *)
+  procedure response_completed_callback(cls: Pointer; connection: PMHD_Connection;
+    con_cls: PPointer; toe: MHD_RequestTerminationCode); cdecl;
+  var
+    uc: PUploadContext;
+  begin
+    uc := con_cls^;
+    if nil = uc then
+      Exit; (* this request wasn't an upload request *)
+    if nil <> uc^.pp then
+    begin
+      MHD_destroy_post_processor(uc^.pp);
+      uc^.pp := nil;
+    end;
+    if -1 <> uc^.fd then
+    begin
+      FpClose(uc^.fd);
+      if nil <> uc^.filename then
+      begin
+        WriteLn(stderr, Format(
+          'Upload of file `%s'' failed (incomplete or aborted), removing file.',
+          [uc^.filename]));
+        FpUnlink(uc^.filename);
+      end;
+    end;
+    if nil <> uc^.filename then
+      Free(uc^.filename);
+    Free(uc);
+  end;
+
+  (**
+   * Return the current directory listing.
+   *
+   * @param connection connection to return the directory for
+   * @return MHD_YES on success, MHD_NO on error
+   *)
+  function return_directory_response(connection: PMHD_Connection): cint;
+  var
+    ret: cint;
+  begin
+    pthread_mutex_lock(@mutex);
+    if nil = cached_directory_response then
+      ret := MHD_queue_response(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
+        internal_error_response)
+    else
+      ret := MHD_queue_response(connection, MHD_HTTP_OK,
+        cached_directory_response);
+    pthread_mutex_unlock(@mutex);
+    Result := ret;
+  end;
+
+  (**
+   * Main callback from MHD, used to generate the page.
+   *
+   * @param cls NULL
+   * @param connection connection handle
+   * @param url requested URL
+   * @param method GET, PUT, POST, etc.
+   * @param version HTTP version
+   * @param upload_data data from upload (PUT/POST)
+   * @param upload_data_size number of bytes in "upload_data"
+   * @param ptr our context
+   * @return MHD_YES on success, MHD_NO to drop connection
+   *)
+  function generate_page(cls: Pointer; connection: PMHD_Connection; url: Pcchar;
+    method: Pcchar; version: Pcchar; upload_data: Pcchar;
+    upload_data_size: Psize_t; ptr: PPointer): cint; cdecl;
+  var
+    response: PMHD_Response;
+    ret: cint;
+    fd: cint;
+    buf: stat;
+    (* should be file download *)
+    file_data: array[0..MAGIC_HEADER_SIZE] of AnsiChar;
+    got: ssize_t ;
+    mime: Pcchar;
+    uc: PUploadContext;
+  begin
+    if 0 <> strcomp(url, '/') then
+    begin
+      if 0 <> strcomp(method, MHD_HTTP_METHOD_GET) then
+        Exit(MHD_NO);  (* unexpected method (we're not polite...) *)
+      if (0 = FpStat(@url[1], buf)) and (nil = strstr(@url[1], '..')) and
+        ('/' <> url[1]) then
+        fd := FpOpen(@url[1], O_RDONLY)
+      else
+        fd := -1;
+      if -1 = fd then
+        Exit(MHD_queue_response(connection, MHD_HTTP_NOT_FOUND,
+          file_not_found_response));
+      (* read beginning of the file to determine mime type  *)
+      got := FpRead(fd, file_data, SizeOf(file_data));
+      if -1 <> got then
+        mime := magic_buffer(magic, Pcchar(file_data), got)
+      else
+        mime := nil;
+      lseek(fd, 0, SEEK_SET);
+      response := MHD_create_response_from_fd(buf.st_size, fd);
+      if nil = response then
+      begin
+        (* internal error (i.e. out of memory) *)
+        FpClose(fd);
+        Exit(MHD_NO);
+      end;
+      (* add mime type if we had one *)
+      if nil <> mime then
+        MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE, mime);
+      ret := MHD_queue_response(connection, MHD_HTTP_OK, response);
+      MHD_destroy_response(response);
+      Exit(ret);
+    end;
+    if 0 = strcomp(method, MHD_HTTP_METHOD_POST) then
+    begin
+      (* upload! *)
+      uc := ptr^;
+      if nil = uc then
+      begin
+        uc := Malloc(SizeOf(UploadContext));
+        if nil = uc then
+          Exit(MHD_NO); (* out of memory, close connection *)
+        memset(uc, 0, SizeOf(UploadContext));
+        uc^.fd := -1;
+        uc^.connection := connection;
+        uc^.pp := MHD_create_post_processor(connection, 64 * 1024 (* buffer size *),
+                   @process_upload_data, uc);
+        if nil = uc^.pp then
+        begin
+          (* out of memory, close connection *)
+          Free(uc);
+          Exit(MHD_NO);
+        end;
+        ptr^ := uc;
+        Exit(MHD_YES);
+      end;
+      if 0 <> upload_data_size^ then
+      begin
+        if nil = uc^.response then
+          MHD_post_process(uc^.pp, upload_data, upload_data_size^);
+        upload_data_size^ := 0;
+        Exit(MHD_YES);
+      end;
+      (* end of upload, finish it! *)
+      MHD_destroy_post_processor(uc^.pp);
+      uc^.pp := nil;
+      if -1 <> uc^.fd then
+      begin
+        FpClose(uc^.fd);
+        uc^.fd := -1;
+      end;
+      if nil <> uc^.response then
+        Exit(MHD_queue_response(connection, MHD_HTTP_FORBIDDEN, uc^.response))
+      else
+      begin
+        update_directory;
+        Exit(return_directory_response(connection));
+      end;
+    end;
+    if 0 = strcomp(method, MHD_HTTP_METHOD_GET) then
+      Exit(return_directory_response(connection));
+    (* unexpected request, refuse *)
+    Result := MHD_queue_response(connection, MHD_HTTP_FORBIDDEN,
+      request_refused_response);
+  end;
+
+  (**
+   * Function called if we get a SIGPIPE. Does nothing.
+   *
+   * @param sig will be SIGPIPE (ignored)
+   *)
+  procedure catcher(signal: longint; info: psiginfo; context: psigcontext); cdecl;
+  begin
+    (* do nothing *)
+  end;
+
+  (**
+   * setup handlers to ignore SIGPIPE.
+   *)
+  procedure ignore_sigpipe;
+  var
+    oldsig: sigactionrec;
+    sig: sigactionrec;
+  begin
+    sig.sa_handler := @catcher;
+    FpsigEmptySet(sig.sa_mask);
+  {$IFDEF SA_INTERRUPT}
+    sig.sa_flags := SA_INTERRUPT; (* SunOS *)
+  {$ELSE}
+    sig.sa_flags := SA_RESTART;
+  {$ENDIF}
+    if 0 <> FPSigaction(SIGPIPE, @sig, @oldsig) then
+      WriteLn(stderr, Format('Failed to install SIGPIPE handler: %s',
+        [strerror(errno^)]));
+  end;
+
+const
+  (* test server key *)
+  srv_signed_key_pem: array[0..1674] of AnsiChar =
+    '-----BEGIN RSA PRIVATE KEY-----'#10+
+    'MIIEowIBAAKCAQEAvfTdv+3fgvVTKRnP/HVNG81cr8TrUP/iiyuve/THMzvFXhCW'#10+
+    '+K03KwEku55QvnUndwBfU/ROzLlv+5hotgiDRNFT3HxurmhouySBrJNJv7qWp8IL'#10+
+    'q4sw32vo0fbMu5BZF49bUXK9L3kW2PdhTtSQPWHEzNrCxO+YgCilKHkY3vQNfdJ0'#10+
+    '20Q5EAAEseD1YtWCIpRvJzYlZMpjYB1ubTl24kwrgOKUJYKqM4jmF4DVQp4oOK/6'#10+
+    'QYGGh1QmHRPAy3CBII6sbb+sZT9cAqU6GYQVB35lm4XAgibXV6KgmpVxVQQ69U6x'#10+
+    'yoOl204xuekZOaG9RUPId74Rtmwfi1TLbBzo2wIDAQABAoIBADu09WSICNq5cMe4'#10+
+    '+NKCLlgAT1NiQpLls1gKRbDhKiHU9j8QWNvWWkJWrCya4QdUfLCfeddCMeiQmv3K'#10+
+    'lJMvDs+5OjJSHFoOsGiuW2Ias7IjnIojaJalfBml6frhJ84G27IXmdz6gzOiTIer'#10+
+    'DjeAgcwBaKH5WwIay2TxIaScl7AwHBauQkrLcyb4hTmZuQh6ArVIN6+pzoVuORXM'#10+
+    'bpeNWl2l/HSN3VtUN6aCAKbN/X3o0GavCCMn5Fa85uJFsab4ss/uP+2PusU71+zP'#10+
+    'sBm6p/2IbGvF5k3VPDA7X5YX61sukRjRBihY8xSnNYx1UcoOsX6AiPnbhifD8+xQ'#10+
+    'Tlf8oJUCgYEA0BTfzqNpr9Wxw5/QXaSdw7S/0eP5a0C/nwURvmfSzuTD4equzbEN'#10+
+    'd+dI/s2JMxrdj/I4uoAfUXRGaabevQIjFzC9uyE3LaOyR2zhuvAzX+vVcs6bSXeU'#10+
+    'pKpCAcN+3Z3evMaX2f+z/nfSUAl2i4J2R+/LQAWJW4KwRky/m+cxpfUCgYEA6bN1'#10+
+    'b73bMgM8wpNt6+fcmS+5n0iZihygQ2U2DEud8nZJL4Nrm1dwTnfZfJBnkGj6+0Q0'#10+
+    'cOwj2KS0/wcEdJBP0jucU4v60VMhp75AQeHqidIde0bTViSRo3HWKXHBIFGYoU3T'#10+
+    'LyPyKndbqsOObnsFXHn56Nwhr2HLf6nw4taGQY8CgYBoSW36FLCNbd6QGvLFXBGt'#10+
+    '2lMhEM8az/K58kJ4WXSwOLtr6MD/WjNT2tkcy0puEJLm6BFCd6A6pLn9jaKou/92'#10+
+    'SfltZjJPb3GUlp9zn5tAAeSSi7YMViBrfuFiHObij5LorefBXISLjuYbMwL03MgH'#10+
+    'Ocl2JtA2ywMp2KFXs8GQWQKBgFyIVv5ogQrbZ0pvj31xr9HjqK6d01VxIi+tOmpB'#10+
+    '4ocnOLEcaxX12BzprW55ytfOCVpF1jHD/imAhb3YrHXu0fwe6DXYXfZV4SSG2vB7'#10+
+    'IB9z14KBN5qLHjNGFpMQXHSMek+b/ftTU0ZnPh9uEM5D3YqRLVd7GcdUhHvG8P8Q'#10+
+    'C9aXAoGBAJtID6h8wOGMP0XYX5YYnhlC7dOLfk8UYrzlp3xhqVkzKthTQTj6wx9R'#10+
+    'GtC4k7U1ki8oJsfcIlBNXd768fqDVWjYju5rzShMpo8OCTS6ipAblKjCxPPVhIpv'#10+
+    'tWPlbSn1qj6wylstJ5/3Z+ZW5H4wIKp5jmLiioDhcP0L/Ex3Zx8O'#10+
+    '-----END RSA PRIVATE KEY-----'#10;
+
+  (* test server CA signed certificates *)
+  srv_signed_cert_pem: array[0..1138] of AnsiChar =
+    '-----BEGIN CERTIFICATE-----'#10+
+    'MIIDGzCCAgWgAwIBAgIES0KCvTALBgkqhkiG9w0BAQUwFzEVMBMGA1UEAxMMdGVz'#10+
+    'dF9jYV9jZXJ0MB4XDTEwMDEwNTAwMDcyNVoXDTQ1MDMxMjAwMDcyNVowFzEVMBMG'#10+
+    'A1UEAxMMdGVzdF9jYV9jZXJ0MIIBHzALBgkqhkiG9w0BAQEDggEOADCCAQkCggEA'#10+
+    'vfTdv+3fgvVTKRnP/HVNG81cr8TrUP/iiyuve/THMzvFXhCW+K03KwEku55QvnUn'#10+
+    'dwBfU/ROzLlv+5hotgiDRNFT3HxurmhouySBrJNJv7qWp8ILq4sw32vo0fbMu5BZ'#10+
+    'F49bUXK9L3kW2PdhTtSQPWHEzNrCxO+YgCilKHkY3vQNfdJ020Q5EAAEseD1YtWC'#10+
+    'IpRvJzYlZMpjYB1ubTl24kwrgOKUJYKqM4jmF4DVQp4oOK/6QYGGh1QmHRPAy3CB'#10+
+    'II6sbb+sZT9cAqU6GYQVB35lm4XAgibXV6KgmpVxVQQ69U6xyoOl204xuekZOaG9'#10+
+    'RUPId74Rtmwfi1TLbBzo2wIDAQABo3YwdDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQM'#10+
+    'MAoGCCsGAQUFBwMBMA8GA1UdDwEB/wQFAwMHIAAwHQYDVR0OBBYEFOFi4ilKOP1d'#10+
+    'XHlWCMwmVKr7mgy8MB8GA1UdIwQYMBaAFP2olB4s2T/xuoQ5pT2RKojFwZo2MAsG'#10+
+    'CSqGSIb3DQEBBQOCAQEAHVWPxazupbOkG7Did+dY9z2z6RjTzYvurTtEKQgzM2Vz'#10+
+    'GQBA+3pZ3c5mS97fPIs9hZXfnQeelMeZ2XP1a+9vp35bJjZBBhVH+pqxjCgiUflg'#10+
+    'A3Zqy0XwwVCgQLE2HyaU3DLUD/aeIFK5gJaOSdNTXZLv43K8kl4cqDbMeRpVTbkt'#10+
+    'YmG4AyEOYRNKGTqMEJXJoxD5E3rBUNrVI/XyTjYrulxbNPcMWEHKNeeqWpKDYTFo'#10+
+    'Bb01PCthGXiq/4A2RLAFosadzRa8SBpoSjPPfZ0b2w4MJpReHqKbR5+T2t6hzml6'#10+
+    '4ToyOKPDmamiTuN5KzLN3cw7DQlvWMvqSOChPLnA3Q=='#10+
+    '-----END CERTIFICATE-----'#10;
+
+  (**
+   * Entry point to demo.  Note: this HTTP server will make all
+   * files in the current directory and its subdirectories available
+   * to anyone.  Press ENTER to stop the server once it has started.
+   *
+   * @param argc number of arguments in argv
+   * @param argv first and only argument should be the port number
+   * @return 0 on success
+   *)
+var
+  d: PMHD_Daemon;
+  port: cuint;
+begin
+  if (argc <> 2) or (1 <> sscanf(argv[1], '%u', @port)) or
+    (UINT16_MAX < port) then
+  begin
+    WriteLn(stderr, argv[0], ' PORT');
+    Halt(1);
+  end;
+  ignore_sigpipe;
+  magic := magic_open(MAGIC_MIME_TYPE);
+  magic_load(magic, nil);
+  pthread_mutex_init(@mutex, nil);
+  file_not_found_response := MHD_create_response_from_buffer(
+    strlen(FILE_NOT_FOUND_PAGE), FILE_NOT_FOUND_PAGE,
+    MHD_RESPMEM_PERSISTENT);
+  mark_as_html(file_not_found_response);
+  request_refused_response := MHD_create_response_from_buffer(
+    strlen(REQUEST_REFUSED_PAGE), REQUEST_REFUSED_PAGE,
+    MHD_RESPMEM_PERSISTENT);
+  mark_as_html(request_refused_response);
+  internal_error_response := MHD_create_response_from_buffer(
+    strlen(INTERNAL_ERROR_PAGE), INTERNAL_ERROR_PAGE,
+    MHD_RESPMEM_PERSISTENT);
+  mark_as_html(internal_error_response);
+  update_directory;
+  d := MHD_start_daemon(MHD_USE_SELECT_INTERNALLY or MHD_USE_DEBUG or MHD_USE_SSL
+{$IFDEF EPOLL_SUPPORT}
+         or MHD_USE_EPOLL_LINUX_ONLY
+{$ENDIF},
+         port, nil, nil, @generate_page, nil,
+         MHD_OPTION_CONNECTION_MEMORY_LIMIT, size_t(256 * 1024),
+{$IFDEF PRODUCTION}
+         MHD_OPTION_PER_IP_CONNECTION_LIMIT, cuint(64),
+{$ENDIF}
+         MHD_OPTION_CONNECTION_TIMEOUT, cuint(120 (* seconds *)),
+         MHD_OPTION_THREAD_POOL_SIZE, cuint(NUMBER_OF_THREADS),
+         MHD_OPTION_NOTIFY_COMPLETED, @response_completed_callback, nil,
+         MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem,
+         MHD_OPTION_HTTPS_MEM_CERT, srv_signed_cert_pem,
+         MHD_OPTION_END);
+  if nil = d then
+    Halt(1);
+  WriteLn(stderr, 'HTTP server running. Press ENTER to stop the server');
+  ReadLn;
+  MHD_stop_daemon(d);
+  MHD_destroy_response(file_not_found_response);
+  MHD_destroy_response(request_refused_response);
+  MHD_destroy_response(internal_error_response);
+  update_cached_response(nil);
+  pthread_mutex_destroy(@mutex);
+  magic_close(magic);
+end.
+

+ 127 - 0
packages/libmicrohttpd/examples/digest_auth_example.pp

@@ -0,0 +1,127 @@
+(*
+     This file is part of libmicrohttpd
+     Copyright (C) 2010 Christian Grothoff (and other contributing authors)
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*)
+(**
+ * @file digest_auth_example.pp (Original: digest_auth_example.c)
+ * @brief minimal example for how to use digest auth with libmicrohttpd
+ * @author Amr Ali / Silvio Clécio
+ *)
+
+program digest_auth_example;
+
+{$mode objfpc}{$H+}
+
+uses
+  sysutils, BaseUnix, cmem, cutils, libmicrohttpd;
+
+const
+  PAGE: Pcchar = '<html><head><title>libmicrohttpd demo</title></head><body>Access granted</body></html>';
+  DENIED: Pcchar = '<html><head><title>libmicrohttpd demo</title></head><body>Access denied</body></html>';
+  MY_OPAQUE_STR = '11733b200778ce33060f31c9af70a870ba96ddd4';
+
+  function ahc_echo(cls: Pointer; connection: PMHD_Connection; url: Pcchar;
+    method: Pcchar; version: Pcchar; upload_data: Pcchar;
+    upload_data_size: Psize_t; ptr: PPointer): cint; cdecl;
+  const
+    password: Pcchar = 'testpass';
+    realm: Pcchar = '[email protected]';
+  var
+    response: PMHD_Response;
+    username: Pcchar;
+    ret: cint;
+    signal_stale: cint;
+  begin
+    username := MHD_digest_auth_get_username(connection);
+    if username = nil then
+    begin
+      response := MHD_create_response_from_buffer(strlen(DENIED), DENIED,
+                    MHD_RESPMEM_PERSISTENT);
+      ret := MHD_queue_auth_fail_response(connection, realm, MY_OPAQUE_STR,
+               response, MHD_NO);
+      MHD_destroy_response(response);
+      Exit(ret);
+    end;
+    ret := MHD_digest_auth_check(connection, realm, username, password, 300);
+    Free(username);
+    if (ret = MHD_INVALID_NONCE) or (ret = MHD_NO) then
+    begin
+      response := MHD_create_response_from_buffer(strlen(DENIED), DENIED,
+                    MHD_RESPMEM_PERSISTENT);
+      if nil = response then
+        Exit(MHD_NO);
+      if ret = MHD_INVALID_NONCE then
+        signal_stale := MHD_YES
+      else
+        signal_stale := MHD_NO;
+      ret := MHD_queue_auth_fail_response(connection, realm, MY_OPAQUE_STR,
+               response, signal_stale);
+      MHD_destroy_response(response);
+      Exit(ret);
+    end;
+    response := MHD_create_response_from_buffer(strlen(PAGE), PAGE,
+      MHD_RESPMEM_PERSISTENT);
+    ret := MHD_queue_response(connection, MHD_HTTP_OK, response);
+    MHD_destroy_response(response);
+    Result := ret;
+  end;
+
+var
+  fd: cint;
+  rnd: array[0..7] of AnsiChar;
+  len: ssize_t;
+  off: size_t;
+  d: PMHD_Daemon;
+begin
+  if argc <> 2 then
+  begin
+    WriteLn(argv[0], ' PORT');
+    Halt(1);
+  end;
+  fd := FpOpen('/dev/urandom', O_RDONLY);
+  if -1 = fd then
+  begin
+    WriteLn(stderr, Format('Failed to open `%s'': %s', [
+      '/dev/urandom', strerror(errno^)]));
+    Halt(1);
+  end;
+  off := 0;
+  while off < 8 do
+  begin
+    len := FpRead(fd, rnd, 8);
+    if len = -1 then
+    begin
+      WriteLn(stderr, Format('Failed to read `%s'': %s', [
+        '/dev/urandom', strerror(errno^)]));
+      FpClose(fd);
+      Halt(1);
+    end;
+    off += len;
+  end;
+  FpClose(fd);
+  d := MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION or MHD_USE_DEBUG,
+         StrToInt(argv[1]), nil, nil, @ahc_echo, PAGE,
+         MHD_OPTION_DIGEST_AUTH_RANDOM, SizeOf(rnd), rnd,
+         MHD_OPTION_NONCE_NC_SIZE, 300,
+         MHD_OPTION_CONNECTION_TIMEOUT, cuint(120),
+         MHD_OPTION_END);
+  if d = nil then
+    Halt(1);
+  ReadLn;
+  MHD_stop_daemon (d);
+end.
+

+ 78 - 0
packages/libmicrohttpd/examples/dual_stack_example.pp

@@ -0,0 +1,78 @@
+(*
+     This file is part of libmicrohttpd
+     Copyright (C) 2007, 2012 Christian Grothoff (and other contributing authors)
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*)
+(**
+ * @file dual_stack_example.pp (Original: dual_stack_example.c)
+ * @brief how to use MHD with both IPv4 and IPv6 support (dual-stack)
+ * @author Christian Grothoff / Silvio Clécio
+ *)
+
+// To test it, just execute: $ curl -g -6 "http://[::1]:8888/"
+
+program dual_stack_example;
+
+{$mode objfpc}{$H+}
+
+uses
+  sysutils, libmicrohttpd;
+
+const
+  PAGE: Pcchar = '<html><head><title>libmicrohttpd demo</title></head><body>libmicrohttpd demo</body></html>';
+
+  function ahc_echo(cls: Pointer; connection: PMHD_Connection; url: Pcchar;
+    method: Pcchar; version: Pcchar; upload_data: Pcchar;
+    upload_data_size: Psize_t; ptr: PPointer): cint; cdecl;
+  const
+    aptr: cint = 0;
+  var
+    me: Pcchar;
+    response: PMHD_Response;
+    ret: cint;
+  begin
+    me := cls;
+    if 0 <> strcomp(method, 'GET') then
+      Exit(MHD_NO); (* unexpected method *)
+    if @aptr <> ptr^ then
+    begin
+      (* do never respond on first call *)
+      ptr^ := @aptr;
+      Exit(MHD_YES);
+    end;
+    ptr^ := nil; (* reset when done *)
+    response := MHD_create_response_from_buffer(strlen(me), Pointer(me),
+                  MHD_RESPMEM_PERSISTENT);
+    ret := MHD_queue_response(connection, MHD_HTTP_OK, response);
+    MHD_destroy_response(response);
+    Result := ret;
+  end;
+
+var
+  d: PMHD_Daemon;
+begin
+  if argc <> 2 then
+  begin
+    WriteLn(argv[0], ' PORT');
+    Halt(1);
+  end;
+  d := MHD_start_daemon(MHD_USE_SELECT_INTERNALLY or MHD_USE_DEBUG or
+         MHD_USE_DUAL_STACK, StrToInt(argv[1]), nil, nil, @ahc_echo, PAGE,
+         MHD_OPTION_CONNECTION_TIMEOUT, cuint(120), MHD_OPTION_END);
+  ReadLn;
+  MHD_stop_daemon(d);
+end.
+

+ 115 - 0
packages/libmicrohttpd/examples/fileserver_example.pp

@@ -0,0 +1,115 @@
+(*
+     This file is part of libmicrohttpd
+     Copyright (C) 2007 Christian Grothoff (and other contributing authors)
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*)
+(**
+ * @file fileserver_example.pp (Original: fileserver_example.c)
+ * @brief minimal example for how to use libmicrohttpd to serve files
+ * @author Christian Grothoff / Silvio Clécio
+ *)
+
+program fileserver_example;
+
+{$mode objfpc}{$H+}
+
+uses
+  sysutils, BaseUnix, cutils, libmicrohttpd;
+
+const
+  PAGE: Pcchar = '<html><head><title>File not found</title></head><body>File not found</body></html>';
+
+  function file_reader(cls: Pointer; pos: cuint64; buf: Pcchar;
+    max: size_t): ssize_t; cdecl;
+  var
+    &file: FILEptr;
+  begin
+    &file := cls;
+    fseek(&file, pos, SEEK_SET);
+    Result := fread(buf, 1, max, &file);
+  end;
+
+  procedure free_callback(cls: Pointer); cdecl;
+  var
+    &file: FILEptr;
+  begin
+    &file := cls;
+    fclose(&file);
+  end;
+
+  function ahc_echo(cls: Pointer; connection: PMHD_Connection; url: Pcchar;
+    method: Pcchar; version: Pcchar; upload_data: Pcchar;
+    upload_data_size: Psize_t; ptr: PPointer): cint; cdecl;
+  const
+    aptr: cint = 0;
+  var
+    response: PMHD_Response;
+    ret: cint;
+    &file: FILEptr;
+    buf: stat;
+  begin
+    if (0 <> strcomp(method, MHD_HTTP_METHOD_GET)) and
+      (0 <> strcomp(method, MHD_HTTP_METHOD_HEAD)) then
+      Exit(MHD_NO); (* unexpected method *)
+    if @aptr <> ptr^ then
+    begin
+      (* do never respond on first call *)
+      ptr^ := @aptr;
+      Exit(MHD_YES);
+    end;
+    ptr^ := nil; (* reset when done *)
+    if 0 = FpStat(@url[1], buf) then
+      &file := fopen(@url[1], fopenread)
+    else
+      &file := nil;
+    if nil = &file then
+    begin
+      response := MHD_create_response_from_buffer(strlen(PAGE), Pointer(PAGE),
+                    MHD_RESPMEM_PERSISTENT);
+      ret := MHD_queue_response(connection, MHD_HTTP_NOT_FOUND, response);
+      MHD_destroy_response(response);
+    end
+    else
+    begin
+      response := MHD_create_response_from_callback(buf.st_size, 32 * 1024, (* 32k page size *)
+                    @file_reader, &file, @free_callback);
+      if nil = response then
+      begin
+        fclose(&file);
+        Exit(MHD_NO);
+      end;
+      ret := MHD_queue_response(connection, MHD_HTTP_OK, response);
+      MHD_destroy_response(response);
+    end;
+    Result := ret;
+  end;
+
+var
+  d: PMHD_Daemon;
+begin
+  if argc <> 2 then
+  begin
+    WriteLn(argv[0], ' PORT');
+    Halt(1);
+  end;
+  d := MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION or MHD_USE_DEBUG,
+         StrToInt(argv[1]), nil, nil, @ahc_echo, PAGE, MHD_OPTION_END);
+  if d = nil then
+    Halt(1);
+  ReadLn;
+  MHD_stop_daemon(d);
+end.
+

+ 167 - 0
packages/libmicrohttpd/examples/fileserver_example_dirs.pp

@@ -0,0 +1,167 @@
+(*
+     This file is part of libmicrohttpd
+     Copyright (C) 2007 Christian Grothoff (and other contributing authors)
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*)
+
+(**
+ * @file fileserver_example_dirs.pp (Original: fileserver_example_dirs.c)
+ * @brief example for how to use libmicrohttpd to serve files (with directory support)
+ * @author Christian Grothoff / Silvio Clécio
+ *)
+
+program fileserver_example_dirs;
+
+{$mode objfpc}{$H+}
+
+uses
+  sysutils, BaseUnix, cutils, libmicrohttpd;
+
+const
+  PAGE: Pcchar = '<html><head><title>File not found</title></head><body>File not found</body></html>';
+
+  function file_reader(cls: Pointer; pos: cuint64; buf: Pcchar;
+    max: size_t): ssize_t; cdecl;
+  var
+    &file: FILEptr;
+  begin
+    &file := cls;
+    fseek(&file, pos, SEEK_SET);
+    Result := fread(buf, 1, max, &file);
+  end;
+
+  procedure file_free_callback(cls: Pointer); cdecl;
+  var
+    &file: FILEptr;
+  begin
+    &file := cls;
+    fclose(&file);
+  end;
+
+  procedure dir_free_callback(cls: Pointer); cdecl;
+  var
+    dir: pDir;
+  begin
+    dir := cls;
+    if dir <> nil then
+      FpClosedir(dir^);
+  end;
+
+  function dir_reader(cls: Pointer; pos: cuint64; buf: Pcchar;
+    max: size_t): ssize_t; cdecl;
+  var
+    dir: pDir;
+    e: pDirent;
+  begin
+    dir := cls;
+    if max < 512 then
+      Exit(0);
+    repeat
+      e := FpReaddir(dir^);
+      if e = nil then
+        Exit(MHD_CONTENT_READER_END_OF_STREAM);
+    until not (e^.d_name[0] = '.');
+    Result := snprintf(buf, max, '<a href="/%s">%s</a><br>', e^.d_name,
+      e^.d_name);
+  end;
+
+  function ahc_echo(cls: Pointer; connection: PMHD_Connection; url: Pcchar;
+    method: Pcchar; version: Pcchar; upload_data: Pcchar;
+    upload_data_size: Psize_t; ptr: PPointer): cint; cdecl;
+  const
+    aptr: cint = 0;
+  var
+    response: PMHD_Response;
+    ret: cint;
+    &file: FILEptr;
+    dir: pDir;
+    buf: stat;
+    emsg: array[0..1023] of AnsiChar;
+  begin
+    if 0 <> strcomp(method, MHD_HTTP_METHOD_GET) then
+      Exit(MHD_NO); (* unexpected method *)
+    if @aptr <> ptr^ then
+    begin
+      (* do never respond on first call *)
+      ptr^ := @aptr;
+      Exit(MHD_YES);
+    end;
+    ptr^ := nil; (* reset when done *)
+    if (0 = FpStat(@url[1], buf)) and fpS_ISREG(buf.st_mode) then
+      &file := fopen(@url[1], fopenread)
+    else
+      &file := nil;
+    if &file = nil then
+    begin
+      dir := FpOpendir(PChar('.'));
+      if dir = nil then
+      begin
+        (* most likely cause: more concurrent requests than
+           available file descriptors / 2 *)
+        snprintf(emsg, SizeOf(emsg), 'Failed to open directory `.'': %s'#10,
+          strerror(errno^));
+        response := MHD_create_response_from_buffer(strlen(emsg), @emsg,
+          MHD_RESPMEM_MUST_COPY);
+        if response = nil then
+          Exit(MHD_NO);
+        ret := MHD_queue_response(connection, MHD_HTTP_SERVICE_UNAVAILABLE,
+          response);
+        MHD_destroy_response(response);
+      end
+      else
+      begin
+        response := MHD_create_response_from_callback(cuint64(MHD_SIZE_UNKNOWN),
+                      32 * 1024, @dir_reader, dir, @dir_free_callback);
+        if response = nil then
+        begin
+          FpClosedir(dir^);
+          Exit(MHD_NO);
+        end;
+        ret := MHD_queue_response(connection, MHD_HTTP_OK, response);
+        MHD_destroy_response(response);
+      end;
+    end
+    else
+    begin
+      response := MHD_create_response_from_callback(buf.st_size, 32 * 1024, (* 32k page size *)
+                    @file_reader, &file, @file_free_callback);
+      if response = nil then
+      begin
+        fclose(&file);
+        Exit(MHD_NO);
+      end;
+      ret := MHD_queue_response(connection, MHD_HTTP_OK, response);
+      MHD_destroy_response(response);
+    end;
+    Result := ret;
+  end;
+
+var
+  d: PMHD_Daemon;
+begin
+  if argc <> 2 then
+  begin
+    WriteLn(argv[0], ' PORT');
+    Halt(1);
+  end;
+  d := MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION or MHD_USE_DEBUG,
+         StrToInt(argv[1]), nil, nil, @ahc_echo, PAGE, MHD_OPTION_END);
+  if d = nil then
+    Halt(1);
+  ReadLn;
+  MHD_stop_daemon(d);
+end.
+

+ 146 - 0
packages/libmicrohttpd/examples/fileserver_example_external_select.pp

@@ -0,0 +1,146 @@
+(*
+     This file is part of libmicrohttpd
+     Copyright (C) 2007, 2008 Christian Grothoff (and other contributing authors)
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*)
+(**
+ * @file fileserver_example_external_select.pp (Original: fileserver_example_external_select.c)
+ * @brief minimal example for how to use libmicrohttpd to server files
+ * @author Christian Grothoff / Silvio Clécio
+ *)
+
+program fileserver_example_external_select;
+
+{$mode objfpc}{$H+}
+
+uses
+  sysutils, BaseUnix, cutils, libmicrohttpd;
+
+const
+  PAGE: Pcchar = '<html><head><title>File not found</title></head><body>File not found</body></html>';
+
+  function file_reader(cls: Pointer; pos: cuint64; buf: Pcchar;
+    max: size_t): ssize_t; cdecl;
+  var
+    &file: FILEptr;
+  begin
+    &file := cls;
+    fseek(&file, pos, SEEK_SET);
+    Result := fread(buf, 1, max, &file);
+  end;
+
+  procedure free_callback(cls: Pointer); cdecl;
+  var
+    &file: FILEptr;
+  begin
+    &file := cls;
+    fclose(&file);
+  end;
+
+  function ahc_echo(cls: Pointer; connection: PMHD_Connection; url: Pcchar;
+    method: Pcchar; version: Pcchar; upload_data: Pcchar;
+    upload_data_size: Psize_t; ptr: PPointer): cint; cdecl;
+  const
+    aptr: cint = 0;
+  var
+    response: PMHD_Response;
+    ret: cint;
+    &file: FILEptr;
+    buf: stat;
+  begin
+    if 0 <> strcomp(method, MHD_HTTP_METHOD_GET) then
+      Exit(MHD_NO); (* unexpected method *)
+    if @aptr <> ptr^ then
+    begin
+      (* do never respond on first call *)
+      ptr^ := @aptr;
+      Exit(MHD_YES);
+    end;
+    ptr^ := nil; (* reset when done *)
+    if (0 = FpStat(@url[1], buf)) and fpS_ISREG(buf.st_mode) then
+      &file := fopen(@url[1], fopenread)
+    else
+      &file := nil;
+    if &file = nil then
+    begin
+      response := MHD_create_response_from_buffer(strlen(PAGE), Pointer(PAGE),
+                    MHD_RESPMEM_PERSISTENT);
+      ret := MHD_queue_response(connection, MHD_HTTP_NOT_FOUND, response);
+      MHD_destroy_response(response);
+    end
+    else
+    begin
+      response := MHD_create_response_from_callback(buf.st_size, 32 * 1024, (* 32k page size *)
+                    @file_reader, &file, @free_callback);
+      if response = nil then
+      begin
+        fclose(&file);
+        Exit(MHD_NO);
+      end;
+      ret := MHD_queue_response(connection, MHD_HTTP_OK, response);
+      MHD_destroy_response(response);
+    end;
+    Result := ret;
+  end;
+
+var
+  d: PMHD_Daemon;
+  &end: time_t;
+  t: time_t;
+  tv: timeval;
+  rs: TFDSet;
+  ws: TFDSet;
+  es: TFDSet;
+  max: MHD_socket;
+  mhd_timeout: MHD_UNSIGNED_LONG_LONG;
+begin
+  if argc <> 3 then
+  begin
+    WriteLn(argv[0], ' PORT SECONDS-TO-RUN');
+    Halt(1);
+  end;
+  d := MHD_start_daemon(MHD_USE_DEBUG, StrToInt(argv[1]), nil, nil, @ahc_echo,
+         PAGE, MHD_OPTION_END);
+  if d = nil then
+    Halt(1);
+  &end := fptime + StrToInt(argv[2]);
+  while True do
+  begin
+    t := fptime;
+    if not (t < &end) then
+      Break;
+    tv.tv_sec := &end - t;
+    tv.tv_usec := 0;
+    max := 0;
+    fpFD_ZERO(rs);
+    fpFD_ZERO(ws);
+    fpFD_ZERO(es);
+    if MHD_YES <> MHD_get_fdset (d, @rs, @ws, @es, @max) then
+      Break; (* fatal internal error *)
+    if MHD_get_timeout(d, @mhd_timeout) = MHD_YES then
+    begin
+      if MHD_UNSIGNED_LONG_LONG(tv.tv_sec) < mhd_timeout div clonglong(1000) then
+      begin
+        tv.tv_sec := mhd_timeout div clonglong(1000);
+        tv.tv_usec := (mhd_timeout - (tv.tv_sec * clonglong(1000))) * clonglong(1000);
+      end;
+    end;
+    fpSelect(max + 1, @rs, @ws, @es, @tv);
+    MHD_run(d);
+  end;
+  MHD_stop_daemon(d);
+end.
+

+ 42 - 0
packages/libmicrohttpd/examples/hellobrowser.pp

@@ -0,0 +1,42 @@
+(* Feel free to use this example code in any way
+   you see fit (Public Domain) *)
+
+// Original example: https://gnunet.org/svn/libmicrohttpd/doc/examples/hellobrowser.c
+
+program hellobrowser;
+
+{$mode objfpc}{$H+}
+
+uses
+  libmicrohttpd;
+
+const
+  PORT = 8888;
+
+  function AnswerToConnection(ACls: Pointer; AConnection: PMHD_Connection;
+    AUrl: Pcchar; AMethod: Pcchar; AVersion: Pcchar; AUploadData: Pcchar;
+    AUploadDataSize: Psize_t; AConCls: PPointer): cint; cdecl;
+  const
+    PAGE: Pcchar = 'Hello world';
+  var
+    VReturn: cint;
+    VResponse: PMHD_Response;
+  begin
+    VResponse := MHD_create_response_from_buffer(Length(PAGE), Pointer(PAGE),
+      MHD_RESPMEM_PERSISTENT);
+    VReturn := MHD_queue_response(AConnection, MHD_HTTP_OK, VResponse);
+    MHD_destroy_response(VResponse);
+    Result := VReturn;
+  end;
+
+var
+  VDaemon: PMHD_Daemon;
+begin
+  VDaemon := MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, PORT, nil, nil,
+    @AnswerToConnection, nil, MHD_OPTION_END);
+  if not Assigned(VDaemon) then
+    Halt(1);
+  ReadLn;
+  MHD_stop_daemon(VDaemon)
+end.
+

+ 194 - 0
packages/libmicrohttpd/examples/https_fileserver_example.pp

@@ -0,0 +1,194 @@
+(*
+     This file is part of libmicrohttpd
+     Copyright (C) 2007, 2008 Christian Grothoff (and other contributing authors)
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*)
+(**
+ * @file https_fileserver_example.pp (Original: https_fileserver_example.c)
+ * @brief a simple HTTPS file server using TLS.
+ *
+ * Usage :
+ *
+ *  'https_fileserver_example HTTP-PORT'
+ *
+ * The certificate & key are required by the server to operate,  Omitting the
+ * path arguments will cause the server to use the hard coded example certificate & key.
+ *
+ * 'certtool' may be used to generate these if required.
+ *
+ * @author Sagie Amir / Silvio Clécio
+ *)
+
+program https_fileserver_example;
+
+{$mode objfpc}{$H+}
+
+uses
+  sysutils, BaseUnix, cutils, libmicrohttpd;
+
+const
+  BUF_SIZE = 1024;
+  MAX_URL_LEN = 255;
+
+  // TODO remove if unused
+  CAFILE: Pcchar = 'ca.pem';
+  CRLFILE: Pcchar = 'crl.pem';
+
+  EMPTY_PAGE: Pcchar = '<html><head><title>File not found</title></head><body>File not found</body></html>';
+
+  (* Test Certificate *)
+  cert_pem: array[0..980] of AnsiChar =
+    '-----BEGIN CERTIFICATE-----'#10+
+    'MIICpjCCAZCgAwIBAgIESEPtjjALBgkqhkiG9w0BAQUwADAeFw0wODA2MDIxMjU0'#10+
+    'MzhaFw0wOTA2MDIxMjU0NDZaMAAwggEfMAsGCSqGSIb3DQEBAQOCAQ4AMIIBCQKC'#10+
+    'AQC03TyUvK5HmUAirRp067taIEO4bibh5nqolUoUdo/LeblMQV+qnrv/RNAMTx5X'#10+
+    'fNLZ45/kbM9geF8qY0vsPyQvP4jumzK0LOJYuIwmHaUm9vbXnYieILiwCuTgjaud'#10+
+    '3VkZDoQ9fteIo+6we9UTpVqZpxpbLulBMh/VsvX0cPJ1VFC7rT59o9hAUlFf9jX/'#10+
+    'GmKdYI79MtgVx0OPBjmmSD6kicBBfmfgkO7bIGwlRtsIyMznxbHu6VuoX/eVxrTv'#10+
+    'rmCwgEXLWRZ6ru8MQl5YfqeGXXRVwMeXU961KefbuvmEPccgCxm8FZ1C1cnDHFXh'#10+
+    'siSgAzMBjC/b6KVhNQ4KnUdZAgMBAAGjLzAtMAwGA1UdEwEB/wQCMAAwHQYDVR0O'#10+
+    'BBYEFJcUvpjvE5fF/yzUshkWDpdYiQh/MAsGCSqGSIb3DQEBBQOCAQEARP7eKSB2'#10+
+    'RNd6XjEjK0SrxtoTnxS3nw9sfcS7/qD1+XHdObtDFqGNSjGYFB3Gpx8fpQhCXdoN'#10+
+    '8QUs3/5ZVa5yjZMQewWBgz8kNbnbH40F2y81MHITxxCe1Y+qqHWwVaYLsiOTqj2/'#10+
+    '0S3QjEJ9tvklmg7JX09HC4m5QRYfWBeQLD1u8ZjA1Sf1xJriomFVyRLI2VPO2bNe'#10+
+    'JDMXWuP+8kMC7gEvUnJ7A92Y2yrhu3QI3bjPk8uSpHea19Q77tul1UVBJ5g+zpH3'#10+
+    'OsF5p0MyaVf09GTzcLds5nE/osTdXGUyHJapWReVmPm3Zn6gqYlnzD99z+DPIgIV'#10+
+    'RhZvQx74NQnS6g=='#10+
+    '-----END CERTIFICATE-----'#10;
+
+  key_pem: array[0..1674] of AnsiChar =
+    '-----BEGIN RSA PRIVATE KEY-----'#10+
+    'MIIEowIBAAKCAQEAtN08lLyuR5lAIq0adOu7WiBDuG4m4eZ6qJVKFHaPy3m5TEFf'#10+
+    'qp67/0TQDE8eV3zS2eOf5GzPYHhfKmNL7D8kLz+I7psytCziWLiMJh2lJvb2152I'#10+
+    'niC4sArk4I2rnd1ZGQ6EPX7XiKPusHvVE6VamacaWy7pQTIf1bL19HDydVRQu60+'#10+
+    'faPYQFJRX/Y1/xpinWCO/TLYFcdDjwY5pkg+pInAQX5n4JDu2yBsJUbbCMjM58Wx'#10+
+    '7ulbqF/3lca0765gsIBFy1kWeq7vDEJeWH6nhl10VcDHl1PetSnn27r5hD3HIAsZ'#10+
+    'vBWdQtXJwxxV4bIkoAMzAYwv2+ilYTUOCp1HWQIDAQABAoIBAArOQv3R7gmqDspj'#10+
+    'lDaTFOz0C4e70QfjGMX0sWnakYnDGn6DU19iv3GnX1S072ejtgc9kcJ4e8VUO79R'#10+
+    'EmqpdRR7k8dJr3RTUCyjzf/C+qiCzcmhCFYGN3KRHA6MeEnkvRuBogX4i5EG1k5l'#10+
+    '/5t+YBTZBnqXKWlzQLKoUAiMLPg0eRWh+6q7H4N7kdWWBmTpako7TEqpIwuEnPGx'#10+
+    'u3EPuTR+LN6lF55WBePbCHccUHUQaXuav18NuDkcJmCiMArK9SKb+h0RqLD6oMI/'#10+
+    'dKD6n8cZXeMBkK+C8U/K0sN2hFHACsu30b9XfdnljgP9v+BP8GhnB0nCB6tNBCPo'#10+
+    '32srOwECgYEAxWh3iBT4lWqL6bZavVbnhmvtif4nHv2t2/hOs/CAq8iLAw0oWGZc'#10+
+    '+JEZTUDMvFRlulr0kcaWra+4fN3OmJnjeuFXZq52lfMgXBIKBmoSaZpIh2aDY1Rd'#10+
+    'RbEse7nQl9hTEPmYspiXLGtnAXW7HuWqVfFFP3ya8rUS3t4d07Hig8ECgYEA6ou6'#10+
+    'OHiBRTbtDqLIv8NghARc/AqwNWgEc9PelCPe5bdCOLBEyFjqKiT2MttnSSUc2Zob'#10+
+    'XhYkHC6zN1Mlq30N0e3Q61YK9LxMdU1vsluXxNq2rfK1Scb1oOlOOtlbV3zA3VRF'#10+
+    'hV3t1nOA9tFmUrwZi0CUMWJE/zbPAyhwWotKyZkCgYEAh0kFicPdbABdrCglXVae'#10+
+    'SnfSjVwYkVuGd5Ze0WADvjYsVkYBHTvhgRNnRJMg+/vWz3Sf4Ps4rgUbqK8Vc20b'#10+
+    'AU5G6H6tlCvPRGm0ZxrwTWDHTcuKRVs+pJE8C/qWoklE/AAhjluWVoGwUMbPGuiH'#10+
+    '6Gf1bgHF6oj/Sq7rv/VLZ8ECgYBeq7ml05YyLuJutuwa4yzQ/MXfghzv4aVyb0F3'#10+
+    'QCdXR6o2IYgR6jnSewrZKlA9aPqFJrwHNR6sNXlnSmt5Fcf/RWO/qgJQGLUv3+rG'#10+
+    '7kuLTNDR05azSdiZc7J89ID3Bkb+z2YkV+6JUiPq/Ei1+nDBEXb/m+/HqALU/nyj'#10+
+    'P3gXeQKBgBusb8Rbd+KgxSA0hwY6aoRTPRt8LNvXdsB9vRcKKHUFQvxUWiUSS+L9'#10+
+    '/Qu1sJbrUquKOHqksV5wCnWnAKyJNJlhHuBToqQTgKXjuNmVdYSe631saiI7PHyC'#10+
+    'eRJ6DxULPxABytJrYCRrNqmXi5TCiqR2mtfalEMOPxz8rUU8dYyx'#10+
+    '-----END RSA PRIVATE KEY-----'#10;
+
+  function file_reader(cls: Pointer; pos: cuint64; buf: Pcchar;
+    max: size_t): ssize_t; cdecl;
+  var
+    &file: FILEptr;
+  begin
+    &file := cls;
+    fseek(&file, pos, SEEK_SET);
+    Result := fread(buf, 1, max, &file);
+  end;
+
+  procedure file_free_callback(cls: Pointer); cdecl;
+  var
+    &file: FILEptr;
+  begin
+    &file := cls;
+    fclose(&file);
+  end;
+
+  function http_ahc(cls: Pointer; connection: PMHD_Connection; url: Pcchar;
+    method: Pcchar; version: Pcchar; upload_data: Pcchar;
+    upload_data_size: Psize_t; ptr: PPointer): cint; cdecl;
+  const
+    aptr: cint = 0;
+  var
+    response: PMHD_Response;
+    ret: cint;
+    &file: FILEptr;
+    buf: stat;
+  begin
+    if 0 <> strcomp(method, MHD_HTTP_METHOD_GET) then
+      Exit(MHD_NO); (* unexpected method *)
+    if @aptr <> ptr^ then
+    begin
+      (* do never respond on first call *)
+      ptr^ := @aptr;
+      Exit(MHD_YES);
+    end;
+    ptr^ := nil; (* reset when done *)
+    if (0 = FpStat(@url[1], buf)) and fpS_ISREG(buf.st_mode) then
+      &file := fopen(@url[1], fopenread)
+    else
+      &file := nil;
+    if &file = nil then
+    begin
+      response := MHD_create_response_from_buffer(strlen(EMPTY_PAGE),
+                    Pointer(EMPTY_PAGE), MHD_RESPMEM_PERSISTENT);
+      ret := MHD_queue_response(connection, MHD_HTTP_NOT_FOUND, response);
+      MHD_destroy_response(response);
+    end
+    else
+    begin
+      response := MHD_create_response_from_callback(buf.st_size, 32 * 1024, (* 32k page size *)
+                    @file_reader, &file, @file_free_callback);
+      if response = nil then
+      begin
+        fclose(&file);
+        Exit(MHD_NO);
+      end;
+      ret := MHD_queue_response(connection, MHD_HTTP_OK, response);
+      MHD_destroy_response(response);
+    end;
+    Result := ret;
+  end;
+
+var
+  TLS_daemon: PMHD_Daemon;
+begin
+  if argc = 2 then
+  begin
+    (* TODO check if this is truly necessary -  disallow usage of the blocking /dev/random *)
+    (* gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0); *)
+    TLS_daemon := MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION or
+                    MHD_USE_DEBUG or MHD_USE_SSL, StrToInt(argv[1]), nil, nil,
+                    @http_ahc, nil, MHD_OPTION_CONNECTION_TIMEOUT, 256,
+                    MHD_OPTION_HTTPS_MEM_KEY, key_pem,
+                    MHD_OPTION_HTTPS_MEM_CERT, cert_pem,
+                    MHD_OPTION_END);
+  end
+  else
+  begin
+    WriteLn(' Usage: ', argv[0], ' HTTP-PORT');
+    Halt(1);
+  end;
+  if TLS_daemon = nil then
+  begin
+    WriteLn(stderr, 'Error: failed to start TLS_daemon');
+    Halt(1);
+  end
+  else
+    WriteLn('MHD daemon listening on port ', argv[1]);
+  ReadLn;
+  MHD_stop_daemon(TLS_daemon);
+end.
+

+ 187 - 0
packages/libmicrohttpd/examples/largepost.pp

@@ -0,0 +1,187 @@
+(* Feel free to use this example code in any way
+   you see fit (Public Domain) *)
+
+// Original example: https://gnunet.org/svn/libmicrohttpd/doc/examples/largepost.c
+
+program largepost;
+
+{$mode objfpc}{$H+}
+
+uses
+  libmicrohttpd, SysUtils, cutils;
+
+type
+  TConnectionInfoStruct = record
+    ConnectionType: cint;
+    PostProcessor: PMHD_PostProcessor;
+    Fp: FILEptr;
+    AnswerString: Pcchar;
+    AnswerCode: cint;
+  end;
+  PConnectionInfoStruct = ^TConnectionInfoStruct;
+
+const
+  PORT = 8888;
+  POSTBUFFERSIZE = 512;
+  MAXCLIENTS = 2;
+  GET = 0;
+  POST = 1;
+
+var
+  NrOfUploadingClients: Cardinal;
+  AskPage: Pcchar =
+    '<html><body>'+#10+
+    'Upload a file, please!<br>'+#10+
+    'There are %d clients uploading at the moment.<br>'+#10+
+    '<form action="/filepost" method="post" enctype="multipart/form-data">'+#10+
+    '<input name="file" type="file">'+#10+
+    '<input type="submit" value="Send"></form>'+#10+
+    '</body></html>';
+  BusyPage: Pcchar = '<html><body>This server is busy, please try again later.</body></html>';
+  CompletePage: Pcchar = '<html><body>The upload has been completed.</body></html>';
+  ErrorPage: Pcchar = '<html><body>This doesn''t seem to be right.</body></html>';
+  ServerErrorPage: Pcchar = '<html><body>An internal server error has occured.</body></html>';
+  FileExistsPage: Pcchar = '<html><body>This file already exists.</body></html>';
+
+  function SendPage(AConnection: PMHD_Connection; APage: Pcchar; AStatusCode: cint): cint;
+  var
+    VRet: cint;
+    VResponse: PMHD_Response;
+  begin
+    VResponse := MHD_create_response_from_buffer(Length(APage),
+      Pointer(APage), MHD_RESPMEM_MUST_COPY);
+    if not Assigned(VResponse) then
+      Exit(MHD_NO);
+    MHD_add_response_header(VResponse, MHD_HTTP_HEADER_CONTENT_TYPE, 'text/html');
+    VRet := MHD_queue_response(AConnection, AStatusCode, VResponse);
+    MHD_destroy_response(VResponse);
+    Result := VRet;
+  end;
+
+  function IteratePost(AConInfoCls: Pointer; AKind: MHD_ValueKind; AKey: Pcchar;
+    AFileName: Pcchar; AContentType: Pcchar; ATransferEncoding: Pcchar;
+    AData: Pcchar; AOff: cuint64; ASize: size_t): cint; cdecl;
+  var
+    VConInfo: PConnectionInfoStruct;
+  begin
+    VConInfo := AConInfoCls;
+    VConInfo^.AnswerString := ServerErrorPage;
+    VConInfo^.AnswerCode := MHD_HTTP_INTERNAL_SERVER_ERROR;
+    if StrComp(AKey, 'file') <> 0 then
+      Exit(MHD_NO);
+    if not Assigned(VConInfo^.Fp) then
+    begin
+      if FileExists(AFileName) then
+      begin
+        VConInfo^.AnswerString := FileExistsPage;
+        VConInfo^.AnswerCode := MHD_HTTP_FORBIDDEN;
+        Exit(MHD_NO);
+      end;
+      VConInfo^.Fp := fopen(AFileName, fappendwrite);
+      if not Assigned(VConInfo^.Fp) then
+        Exit(MHD_NO);
+    end;
+    if ASize > 0 then
+      if fwrite(AData, ASize, SizeOf(AnsiChar), VConInfo^.Fp) = 0 then
+        Exit(MHD_NO);
+    VConInfo^.AnswerString := CompletePage;
+    VConInfo^.AnswerCode := MHD_HTTP_OK;
+    Result := MHD_YES;
+  end;
+
+  procedure RequestCompleted(ACls: Pointer; AConnection: PMHD_Connection;
+    AConCls: PPointer; AToe: MHD_RequestTerminationCode); cdecl;
+  var
+    VConInfo: PConnectionInfoStruct;
+  begin
+    VConInfo := AConCls^;
+    if not Assigned(VConInfo) then
+      Exit;
+    if VConInfo^.ConnectionType = POST then
+    begin
+      if Assigned(VConInfo^.PostProcessor) then
+      begin
+        MHD_destroy_post_processor(VConInfo^.PostProcessor);
+        Dec(NrOfUploadingClients);
+      end;
+      if Assigned(VConInfo^.Fp) then
+        fclose(VConInfo^.Fp);
+    end;
+    FreeMem(VConInfo);
+    AConCls^ := nil;
+  end;
+
+  function AnswerToConnection(ACls: Pointer; AConnection: PMHD_Connection;
+    AUrl: Pcchar; AMethod: Pcchar; AVersion: Pcchar; AUploadData: Pcchar;
+    AUploadDataSize: Psize_t; AConCls: PPointer): cint; cdecl;
+  var
+    VBuffer: array[0..1024] of AnsiChar;
+    VConInfo: PConnectionInfoStruct;
+  begin
+    if not Assigned(AConCls^) then
+    begin
+      if NrOfUploadingClients >= MAXCLIENTS then
+        Exit(SendPage(AConnection, BusyPage, MHD_HTTP_SERVICE_UNAVAILABLE));
+      VConInfo := AllocMem(SizeOf(TConnectionInfoStruct));
+      if not Assigned(VConInfo) then
+        Exit(MHD_NO);
+      VConInfo^.Fp := nil;
+      if StrComp(AMethod, 'POST') = 0 then
+      begin
+        VConInfo^.PostProcessor := MHD_create_post_processor(AConnection,
+          POSTBUFFERSIZE, @IteratePost, VConInfo);
+        if not Assigned(VConInfo^.PostProcessor) then
+        begin
+          FreeMem(VConInfo);
+          Exit(MHD_NO);
+        end;
+        Inc(NrOfUploadingClients);
+        VConInfo^.ConnectionType := POST;
+        VConInfo^.AnswerCode := MHD_HTTP_OK;
+        VConInfo^.AnswerString := CompletePage;
+      end
+      else
+        VConInfo^.ConnectionType := GET;
+      AConCls^ := VConInfo;
+      Exit(MHD_YES);
+    end;
+    if StrComp(AMethod, 'GET') = 0 then
+    begin
+      StrLFmt(VBuffer, SizeOf(VBuffer), AskPage, [NrOfUploadingClients]);
+      Exit(SendPage(AConnection, VBuffer, MHD_HTTP_OK));
+    end;
+    if StrComp(AMethod, 'POST') = 0 then
+    begin
+      VConInfo := AConCls^;
+      if AUploadDataSize^ <> 0 then
+      begin
+        MHD_post_process(VConInfo^.PostProcessor, AUploadData, AUploadDataSize^);
+        AUploadDataSize^ := 0;
+        Exit(MHD_YES);
+      end
+      else
+      begin
+        if Assigned(VConInfo^.Fp) then
+        begin
+          fclose(VConInfo^.Fp);
+          VConInfo^.Fp := nil;
+        end;
+        (* Now it is safe to open and inspect the file before calling send_page with a response *)
+        Exit(SendPage(AConnection, VConInfo^.AnswerString, VConInfo^.AnswerCode));
+      end;
+    end;
+    Result := SendPage(AConnection, ErrorPage, MHD_HTTP_BAD_REQUEST);
+  end;
+
+var
+  VDaemon: PMHD_Daemon;
+begin
+  VDaemon := MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, PORT, nil, nil,
+    @AnswerToConnection, nil, MHD_OPTION_NOTIFY_COMPLETED, @RequestCompleted,
+      nil, MHD_OPTION_END);
+  if not Assigned(VDaemon) then
+    Halt(1);
+  ReadLn;
+  MHD_stop_daemon(VDaemon);
+end.
+

+ 43 - 0
packages/libmicrohttpd/examples/logging.pp

@@ -0,0 +1,43 @@
+(* Feel free to use this example code in any way
+   you see fit (Public Domain) *)
+
+// Original example: https://gnunet.org/svn/libmicrohttpd/doc/examples/logging.c
+
+program logging;
+
+{$mode objfpc}{$H+}
+
+uses
+  libmicrohttpd, sysutils;
+
+const
+  PORT = 8888;
+
+  function PrintOutKey(ACls: Pointer; AKind: MHD_ValueKind; AKey: Pcchar;
+    AValue: Pcchar): cint; cdecl;
+  begin
+    WriteLn(Format('%s: %s', [AKey, AValue]));
+    Result := MHD_YES;
+  end;
+
+  function AnswerToConnection(ACls: Pointer; AConnection: PMHD_Connection;
+    AUrl: Pcchar; AMethod: Pcchar; AVersion: Pcchar; AUploadData: Pcchar;
+    AUploadDataSize: Psize_t; AConCls: PPointer): cint; cdecl;
+  begin
+    WriteLn(Format('New %s request for %s using version %s',
+      [AMethod, AUrl, AVersion]));
+    MHD_get_connection_values(AConnection, MHD_HEADER_KIND, @PrintOutKey, nil);
+    Result := MHD_NO;
+  end;
+
+var
+  VDaemon: PMHD_Daemon;
+begin
+  VDaemon := MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, PORT, nil, nil,
+    @AnswerToConnection, nil, MHD_OPTION_END);
+  if not Assigned(VDaemon) then
+    Halt(1);
+  ReadLn;
+  MHD_stop_daemon(VDaemon)
+end.
+

+ 15 - 0
packages/libmicrohttpd/examples/magic.inc

@@ -0,0 +1,15 @@
+{$PACKRECORDS C}
+
+  magic_set = record
+  end;
+
+  magic_t = ^magic_set;
+
+const
+  LIB_NAME = 'magic';
+  MAGIC_MIME_TYPE = $000010;
+
+function magic_open(flags: cint): magic_t; cdecl; external LIB_NAME name 'magic_open';
+procedure magic_close(cookie: magic_t); cdecl; external LIB_NAME name 'magic_close';
+function magic_load(cookie: magic_t; filename: Pcchar): cint; cdecl; external LIB_NAME name 'magic_load';
+function magic_buffer(cookie: magic_t; buffer: Pointer; length: size_t): Pcchar; cdecl; external LIB_NAME name 'magic_buffer';

+ 82 - 0
packages/libmicrohttpd/examples/minimal_example.pp

@@ -0,0 +1,82 @@
+(*
+     This file is part of libmicrohttpd
+     Copyright (C) 2007 Christian Grothoff (and other contributing authors)
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*)
+(**
+ * @file minimal_example.pp (Original: minimal_example.c)
+ * @brief minimal example for how to use libmicrohttpd
+ * @author Christian Grothoff / Silvio Clécio
+ *)
+
+program minimal_example;
+
+{$mode objfpc}{$H+}
+
+uses
+  sysutils, cutils, libmicrohttpd;
+
+const
+  PAGE: Pcchar = '<html><head><title>libmicrohttpd demo</title></head><body>libmicrohttpd demo</body></html>';
+
+  function ahc_echo(cls:  Pointer; connection: PMHD_Connection; url: Pcchar;
+    method: Pcchar; version: Pcchar; upload_data: Pcchar;
+    upload_data_size: Psize_t; ptr: PPointer): cint; cdecl;
+  const
+    aptr: cint = 0;
+  var
+    me: Pcchar;
+    response: PMHD_Response;
+    ret: cint;
+  begin
+    me := cls;
+    if 0 <> strcomp(method, 'GET') then
+      Exit(MHD_NO);
+    if @aptr <> ptr^ then
+    begin
+      ptr^ := @aptr;
+      Exit(MHD_YES);
+    end;
+    ptr^ := nil;
+    response := MHD_create_response_from_buffer(strlen(me), Pointer(me),
+      MHD_RESPMEM_PERSISTENT);
+    ret := MHD_queue_response(connection, MHD_HTTP_OK, response);
+    MHD_destroy_response(response);
+    Result := ret;
+  end;
+
+var
+  d: PMHD_Daemon;
+begin
+  if argc <> 2 then
+  begin
+    WriteLn(argv[0], ' PORT');
+    Halt(1);
+  end;
+  d := MHD_start_daemon(// MHD_USE_SELECT_INTERNALLY or MHD_USE_DEBUG or MHD_USE_POLL,
+         MHD_USE_SELECT_INTERNALLY or MHD_USE_DEBUG,
+         // MHD_USE_THREAD_PER_CONNECTION or MHD_USE_DEBUG or MHD_USE_POLL,
+         // MHD_USE_THREAD_PER_CONNECTION or MHD_USE_DEBUG,
+         StrToInt(argv[1]),
+         nil, nil, @ahc_echo, PAGE,
+         MHD_OPTION_CONNECTION_TIMEOUT, cuint(120),
+         MHD_OPTION_END);
+  if d = nil then
+    Halt(1);
+  ReadLn;
+  MHD_stop_daemon(d);
+end.
+

+ 81 - 0
packages/libmicrohttpd/examples/minimal_example_comet.pp

@@ -0,0 +1,81 @@
+(*
+     This file is part of libmicrohttpd
+     Copyright (C) 2007, 2008 Christian Grothoff (and other contributing authors)
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*)
+(**
+ * @file minimal_example.pp (original: minimal_example.c)
+ * @brief minimal example for how to generate an infinite stream with libmicrohttpd
+ * @author Christian Grothoff / Silvio Clécio / Gilson Nunes
+ *)
+
+program minimal_example_comet;
+
+{$mode objfpc}{$H+}
+
+uses
+  sysutils, cutils, libmicrohttpd;
+
+  function data_generator(cls: Pointer; pos: cuint64; buf: Pcchar;
+    max: size_t): ssize_t; cdecl;
+  begin
+    if max < 80 then
+      Exit(0);
+    memset(buf, Ord('A'), max - 1);
+    buf[79] := #10;
+    Exit(80);
+  end;
+
+  function ahc_echo(cls:  Pointer; connection: PMHD_Connection; url: Pcchar;
+    method: Pcchar; version: Pcchar; upload_data: Pcchar;
+    upload_data_size: Psize_t; ptr: PPointer): cint; cdecl;
+  const
+    aptr: cint = 0;
+  var
+    response: PMHD_Response;
+    ret: cint;
+  begin
+    if 0 <> strcomp(method, 'GET') then
+      Exit(MHD_NO);
+    if @aptr <> ptr^ then
+    begin
+      ptr^ := @aptr;
+      Exit(MHD_YES);
+    end;
+    ptr^ := nil;
+    response := MHD_create_response_from_callback(UInt64(MHD_SIZE_UNKNOWN), 80,
+      @data_generator, nil, nil);
+    ret := MHD_queue_response(connection, MHD_HTTP_OK, response);
+    MHD_destroy_response(response);
+    Result := ret;
+  end;
+
+var
+  d: PMHD_Daemon;
+begin
+  if argc <> 2 then
+  begin
+    WriteLn(argv[0], ' PORT');
+    Halt(1);
+  end;
+  d := MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION or MHD_USE_DEBUG,
+         StrToInt(argv[1]), nil, nil, @ahc_echo, nil, MHD_OPTION_END);
+  if d = nil then
+    Halt(1);
+  ReadLn;
+  MHD_stop_daemon(d);
+end.
+

+ 640 - 0
packages/libmicrohttpd/examples/post_example.pp

@@ -0,0 +1,640 @@
+(*
+     This file is part of libmicrohttpd
+     Copyright (C) 2011 Christian Grothoff (and other contributing authors)
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*)
+(**
+ * @file post_example.pp (Original: post_example.c)
+ * @brief example for processing POST requests using libmicrohttpd
+ * @author Christian Grothoff / Silvio Clécio
+ *)
+
+program post_example;
+
+{$mode objfpc}{$H+}
+
+uses
+  SysUtils, BaseUnix, cmem, cutils, libmicrohttpd;
+
+const
+  (**
+   * Invalid method page.
+   *)
+  METHOD_ERROR = '<html><head><title>Illegal request</title></head><body>Go away.</body></html>';
+
+  (**
+   * Invalid URL page.
+   *)
+  NOT_FOUND_ERROR = '<html><head><title>Not found</title></head><body>Go away.</body></html>';
+
+  (**
+   * Front page. (/)
+   *)
+  MAIN_PAGE = '<html><head><title>Welcome</title></head><body><form action="/2" method="post">What is your name? <input type="text" name="v1" value="%s" /><input type="submit" value="Next" /></body></html>';
+
+  (**
+   * Second page. (/2)
+   *)
+  SECOND_PAGE = '<html><head><title>Tell me more</title></head><body><a href="/">previous</a> <form action="/S" method="post">%s, what is your job? <input type="text" name="v2" value="%s" /><input type="submit" value="Next" /></body></html>';
+
+  (**
+   * Second page (/S)
+   *)
+  SUBMIT_PAGE = '<html><head><title>Ready to submit?</title></head><body><form action="/F" method="post"><a href="/2">previous </a> <input type="hidden" name="DONE" value="yes" /><input type="submit" value="Submit" /></body></html>';
+
+  (**
+   * Last page.
+   *)
+  LAST_PAGE = '<html><head><title>Thank you</title></head><body>Thank you.</body></html>';
+
+  (**
+   * Name of our cookie.
+   *)
+  COOKIE_NAME = 'session';
+
+type
+  (**
+   * State we keep for each user/session/browser.
+   *)
+  PSession = ^TSession;
+  TSession = packed record
+    (**
+     * We keep all sessions in a linked list.
+     *)
+    next: PSession;
+
+    (**
+     * Unique ID for this session.
+     *)
+    sid: array[0..33] of Char;
+
+    (**
+     * Reference counter giving the number of connections
+     * currently using this session.
+     *)
+    rc: cint;
+
+    (**
+     * Time when this session was last active.
+     *)
+    start: time_t;
+
+    (**
+     * String submitted via form.
+     *)
+    value_1: array[0..64] of Char;
+
+    (**
+     * Another value submitted via form.
+     *)
+    value_2: array[0..64] of Char;
+  end;
+
+  (**
+   * Data kept per request.
+   *)
+  TRequest = packed record
+
+    (**
+     * Associated session.
+     *)
+    session: PSession;
+
+    (**
+     * Post processor handling form data (IF this is
+     * a POST request).
+     *)
+    pp: PMHD_PostProcessor;
+
+    (**
+     * URL to serve in response to this POST (if this request
+     * was a 'POST')
+     *)
+    post_url: pcchar;
+
+  end;
+  PRequest = ^TRequest;
+
+var
+  (**
+   * Linked list of all active sessions.  Yes, O(n) but a
+   * hash table would be overkill for a simple example...
+   *)
+  _sessions: PSession;
+
+  (**
+   * Return the session handle for this connection, or
+   * create one if this is a new user.
+   *)
+  function get_session(connection: PMHD_Connection): PSession;
+  var
+    ret: PSession;
+    cookie: pcchar;
+  begin
+    cookie := MHD_lookup_connection_value(connection, MHD_COOKIE_KIND, COOKIE_NAME);
+    if cookie <> nil then
+    begin
+      (* find existing session *)
+      ret := _sessions;
+      while nil <> ret do
+      begin
+        if StrComp(cookie, ret^.sid) = 0 then
+          Break;
+        ret := ret^.next;
+      end;
+      if nil <> ret then
+      begin
+        Inc(ret^.rc);
+        Exit(ret);
+      end;
+    end;
+    (* create fresh session *)
+    ret := CAlloc(1, SizeOf(TSession));
+    if nil = ret then
+    begin
+      WriteLn(stderr, 'calloc error: ', strerror(errno^));
+      Exit(nil);
+    end;
+    (* not a super-secure way to generate a random session ID,
+       but should do for a simple example... *)
+    snprintf(ret^.sid, SizeOf(ret^.sid), '%X%X%X%X', Cardinal(rand),
+      Cardinal(rand), Cardinal(rand), Cardinal(rand));
+    Inc(ret^.rc);
+    ret^.start := FpTime;
+    ret^.next := _sessions;
+    _sessions := ret;
+    Result := ret;
+  end;
+
+(**
+ * Type of handler that generates a reply.
+ *
+ * @param cls content for the page (handler-specific)
+ * @param mime mime type to use
+ * @param session session information
+ * @param connection connection to process
+ * @param MHD_YES on success, MHD_NO on failure
+ *)
+type
+  TPageHandler = function(cls: Pointer; mime: Pcchar; session: PSession;
+    connection: PMHD_Connection): LongInt; cdecl;
+
+  (**
+   * Entry we generate for each page served.
+   *)
+  TPage = packed record
+    (**
+     * Acceptable URL for this page.
+     *)
+    url: Pcchar;
+
+    (**
+     * Mime type to set for the page.
+     *)
+    mime: Pcchar;
+
+    (**
+     * Handler to call to generate response.
+     *)
+    handler: TPageHandler;
+
+    (**
+     * Extra argument to handler.
+     *)
+    handler_cls: Pcchar;
+  end;
+
+  (**
+   * Add header to response to set a session cookie.
+   *
+   * @param session session to use
+   * @param response response to modify
+   *)
+  procedure add_session_cookie(session: PSession; response: PMHD_Response);
+  var
+    cstr: array[0..256] of Char;
+  begin
+    snprintf(cstr, SizeOf(cstr), '%s=%s', COOKIE_NAME, session^.sid);
+    if MHD_NO =
+      MHD_add_response_header(response, MHD_HTTP_HEADER_SET_COOKIE, cstr) then
+      WriteLn(stderr, 'Failed to set session cookie header!');
+  end;
+
+  (**
+   * Handler that returns a simple static HTTP page that
+   * is passed in via 'cls'.
+   *
+   * @param cls a 'const char *' with the HTML webpage to return
+   * @param mime mime type to use
+   * @param session session handle
+   * @param connection connection to use
+   *)
+  function serve_simple_form(cls: Pointer; mime: Pcchar; session: PSession;
+    connection: PMHD_Connection): cint; cdecl;
+  var
+    ret: cint;
+    form: Pcchar;
+    response: PMHD_Response;
+  begin
+    form := cls;
+    (* return static form *)
+    response := MHD_create_response_from_buffer(Length(form), Pointer(form),
+      MHD_RESPMEM_PERSISTENT);
+    add_session_cookie(session, response);
+    MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_ENCODING, mime);
+    ret := MHD_queue_response(connection, MHD_HTTP_OK, response);
+    MHD_destroy_response(response);
+    Result := ret;
+  end;
+
+  (**
+   * Handler that adds the 'v1' value to the given HTML code.
+   *
+   * @param cls unused
+   * @param mime mime type to use
+   * @param session session handle
+   * @param connection connection to use
+   *)
+  function fill_v1_form(cls: Pointer; mime: Pcchar; session: PSession;
+    connection: PMHD_Connection): cint; cdecl;
+  var
+    ret: cint;
+    reply: Pcchar;
+    response: PMHD_Response;
+  begin
+    reply := Malloc(strlen(MAIN_PAGE) + strlen(session^.value_1) + 1);
+    if nil = reply then
+      Exit(MHD_NO);
+    snprintf (reply, strlen(MAIN_PAGE) + strlen(session^.value_1) + 1,
+      MAIN_PAGE, session^.value_1);
+    (* return static form *)
+    response := MHD_create_response_from_buffer (strlen(reply), Pointer(reply),
+                  MHD_RESPMEM_MUST_FREE);
+    if nil = response then
+      Exit(MHD_NO);
+    add_session_cookie(session, response);
+    MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_ENCODING, mime);
+    ret := MHD_queue_response (connection, MHD_HTTP_OK, response);
+    MHD_destroy_response(response);
+    Result := ret;
+  end;
+
+  (**
+   * Handler that adds the 'v1' and 'v2' values to the given HTML code.
+   *
+   * @param cls unused
+   * @param mime mime type to use
+   * @param session session handle
+   * @param connection connection to use
+   *)
+  function fill_v1_v2_form(cls: Pointer; mime: Pcchar; session: PSession;
+    connection: PMHD_Connection): cint; cdecl;
+  var
+    ret: cint;
+    reply: Pcchar;
+    response: PMHD_Response;
+  begin
+    reply := Malloc(strlen(SECOND_PAGE) + strlen(session^.value_1) +
+               strlen(session^.value_2) + 1);
+    if nil = reply then
+      Exit(MHD_NO);
+    snprintf(reply, strlen(SECOND_PAGE) + strlen(session^.value_1) +
+      strlen(session^.value_2) + 1, SECOND_PAGE, session^.value_1,
+      session^.value_2);
+    (* return static form *)
+    response := MHD_create_response_from_buffer(strlen(reply), Pointer(reply),
+                  MHD_RESPMEM_MUST_FREE);
+    if nil = response then
+      Exit(MHD_NO);
+    add_session_cookie(session, response);
+    MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_ENCODING, mime);
+    ret := MHD_queue_response (connection, MHD_HTTP_OK, response);
+    MHD_destroy_response(response);
+    Result := ret;
+  end;
+
+  (**
+   * Handler used to generate a 404 reply.
+   *
+   * @param cls a 'const char *' with the HTML webpage to return
+   * @param mime mime type to use
+   * @param session session handle
+   * @param connection connection to use
+   *)
+  function not_found_page(cls: Pointer; mime: Pcchar; session: PSession;
+    connection: PMHD_Connection): cint; cdecl;
+  var
+    ret: cint;
+    response: PMHD_Response;
+  begin
+    (* unsupported HTTP method *)
+    response := MHD_create_response_from_buffer(Length(NOT_FOUND_ERROR),
+      Pcchar(NOT_FOUND_ERROR), MHD_RESPMEM_PERSISTENT);
+    ret := MHD_queue_response(connection, MHD_HTTP_NOT_FOUND, response);
+    MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_ENCODING, mime);
+    MHD_destroy_response(response);
+    Result := ret;
+  end;
+
+const
+  (**
+   * List of all pages served by this HTTP server.
+   *)
+  pages: array[0..4] of TPage = (
+    (url: '/';  mime: 'text/html'; handler: @fill_v1_form; handler_cls: nil),
+    (url: '/2'; mime: 'text/html'; handler: @fill_v1_v2_form; handler_cls: nil),
+    (url: '/S'; mime: 'text/html'; handler: @serve_simple_form; handler_cls: SUBMIT_PAGE),
+    (url: '/F'; mime: 'text/html'; handler: @serve_simple_form; handler_cls: LAST_PAGE),
+    (url: nil; mime: nil; handler: @not_found_page; handler_cls: nil) (* 404 *)
+  );
+
+  (**
+   * Iterator over key-value pairs where the value
+   * maybe made available in increments and/or may
+   * not be zero-terminated.  Used for processing
+   * POST data.
+   *
+   * @param cls user-specified closure
+   * @param kind type of the value
+   * @param key 0-terminated key for the value
+   * @param filename name of the uploaded file, NULL if not known
+   * @param content_type mime-type of the data, NULL if not known
+   * @param transfer_encoding encoding of the data, NULL if not known
+   * @param data pointer to size bytes of data at the
+   *              specified offset
+   * @param off offset of data in the overall value
+   * @param size number of bytes in data available
+   * @return MHD_YES to continue iterating,
+   *         MHD_NO to abort the iteration
+   *)
+  function post_iterator(cls: Pointer; kind: MHD_ValueKind; key: Pcchar;
+    filename: Pcchar; content_type: Pcchar; transfer_encoding: Pcchar;
+    data: Pcchar; off: cuint64; size: size_t): cint; cdecl;
+  var
+    request: PRequest;
+    session: PSession;
+  begin
+    request := cls;
+    session := request^.session;
+    if StrComp('DONE', key) = 0 then
+    begin
+      WriteLn(stdout, Format('Session `%s'' submitted `%s'', `%s''', [
+        session^.sid, session^.value_1, session^.value_2]));
+      Exit(MHD_YES);
+    end;
+    if StrComp('v1', key) = 0 then
+    begin
+      if (size + off) > SizeOf(session^.value_1) then
+        size := SizeOf(session^.value_1) - off - 1;
+      Move(data^, session^.value_1[off], size);
+      if (size + off) < SizeOf(session^.value_1) then
+        session^.value_1[size + off] := #0;
+      Exit(MHD_YES);
+    end;
+    if StrComp('v2', key) = 0 then
+    begin
+      if (size + off) > SizeOf(session^.value_2) then
+        size := SizeOf(session^.value_2) - off - 1;
+      Move(data^, session^.value_2[off], size);
+      if (size + off) < SizeOf(session^.value_2) then
+        session^.value_2[size + off] := #0;
+      Exit(MHD_YES);
+    end;
+    WriteLn(stderr, Format('Unsupported form value `%s''', [key]));
+    Result := MHD_YES;
+  end;
+
+  (**
+   * Main MHD callback for handling requests.
+   *
+   *
+   * @param cls argument given together with the function
+   *        pointer when the handler was registered with MHD
+   * @param connection handle to connection which is being processed
+   * @param url the requested url
+   * @param method the HTTP method used ("GET", "PUT", etc.)
+   * @param version the HTTP version string (i.e. "HTTP/1.1")
+   * @param upload_data the data being uploaded (excluding HEADERS,
+   *        for a POST that fits into memory and that is encoded
+   *        with a supported encoding, the POST data will NOT be
+   *        given in upload_data and is instead available as
+   *        part of MHD_get_connection_values; very large POST
+   *        data *will* be made available incrementally in
+   *        upload_data)
+   * @param upload_data_size set initially to the size of the
+   *        upload_data provided; the method must update this
+   *        value to the number of bytes NOT processed;
+   * @param ptr pointer that the callback can set to some
+   *        address and that will be preserved by MHD for future
+   *        calls for this request; since the access handler may
+   *        be called many times (i.e., for a PUT/POST operation
+   *        with plenty of upload data) this allows the application
+   *        to easily associate some request-specific state.
+   *        If necessary, this state can be cleaned up in the
+   *        global "MHD_RequestCompleted" callback (which
+   *        can be set with the MHD_OPTION_NOTIFY_COMPLETED).
+   *        Initially, <tt>*con_cls</tt> will be NULL.
+   * @return MHS_YES if the connection was handled successfully,
+   *         MHS_NO if the socket must be closed due to a serios
+   *         error while handling the request
+   *)
+  function create_response(cls: Pointer; connection: PMHD_Connection;
+    url: Pcchar; method: Pcchar; version: Pcchar; upload_data: Pcchar;
+    upload_data_size: Psize_t; ptr: PPointer): cint; cdecl;
+  var
+    response: PMHD_Response;
+    request: PRequest;
+    session: PSession;
+    ret: cint;
+    i: Cardinal;
+  begin
+    request := ptr^;
+    if nil = request then
+    begin
+      request := CAlloc(1, SizeOf(TRequest));
+      if nil = request then
+      begin
+        WriteLn(stderr, 'calloc error: ', strerror(errno^));
+        Exit(MHD_NO);
+      end;
+      ptr^ := request;
+      if StrComp(method, MHD_HTTP_METHOD_POST) = 0 then
+      begin
+        request^.pp := MHD_create_post_processor(connection, 1024,
+          @post_iterator, request);
+        if nil = request^.pp then
+        begin
+          WriteLn(stderr, Format('Failed to setup post processor for `%s''',
+            [url]));
+          Exit(MHD_NO); (* internal error *)
+        end;
+      end;
+      Exit(MHD_YES);
+    end;
+    if nil = request^.session then
+    begin
+      request^.session := get_session(connection);
+      if nil = request^.session then
+      begin
+        WriteLn(stderr, Format('Failed to setup session for `%s''', [url]));
+        Exit(MHD_NO); (* internal error *)
+      end;
+    end;
+    session := request^.session;
+    session^.start := FpTime;
+    if StrComp(method, MHD_HTTP_METHOD_POST) = 0 then
+    begin
+      (* evaluate POST data *)
+      MHD_post_process(request^.pp, upload_data, upload_data_size^);
+      if upload_data_size^ <> 0 then
+      begin
+        upload_data_size^ := 0;
+        Exit(MHD_YES);
+      end;
+      (* done with POST data, serve response *)
+      MHD_destroy_post_processor(request^.pp);
+      request^.pp := nil;
+      method := MHD_HTTP_METHOD_GET; (* fake 'GET' *)
+      if nil <> request^.post_url then
+        url := request^.post_url;
+    end;
+    if (StrComp(method, MHD_HTTP_METHOD_GET) = 0) or
+      (StrComp(method, MHD_HTTP_METHOD_HEAD) = 0) then
+    begin
+      (* find out which page to serve *)
+      i := 0;
+      while (pages[i].url <> nil) and (StrComp(pages[i].url, url) <> 0) do
+        Inc(i);
+      ret := pages[i].handler(pages[i].handler_cls, pages[i].mime, session,
+        connection);
+      if ret <> MHD_YES then
+        WriteLn(stderr, Format('Failed to create page for `%s''', [url]));
+      Exit(ret);
+    end;
+    (* unsupported HTTP method *)
+    response := MHD_create_response_from_buffer(Length(METHOD_ERROR),
+      Pcchar(METHOD_ERROR), MHD_RESPMEM_PERSISTENT);
+    ret := MHD_queue_response(connection, MHD_HTTP_NOT_ACCEPTABLE, response);
+    MHD_destroy_response(response);
+    Result := ret;
+  end;
+
+  (**
+   * Callback called upon completion of a request.
+   * Decrements session reference counter.
+   *
+   * @param cls not used
+   * @param connection connection that completed
+   * @param con_cls session handle
+   * @param toe status code
+   *)
+  procedure request_completed_callback(cls: Pointer; connection: PMHD_Connection;
+    con_cls: PPointer; toe: MHD_RequestTerminationCode);
+  var
+    request: PRequest;
+  begin
+    request := con_cls^;
+    if nil = request then
+      Exit;
+    if nil <> request^.session then
+      Dec(request^.session^.rc);
+    if nil <> request^.pp then
+      MHD_destroy_post_processor(request^.pp);
+    Free(request);
+  end;
+
+  (**
+   * Clean up handles of sessions that have been idle for
+   * too long.
+   *)
+  procedure expire_sessions;
+  var
+    pos: PSession;
+    prev: PSession;
+    next: PSession;
+    now: time_t;
+  begin
+    now := FpTime;
+    prev := nil;
+    pos := _sessions;
+    while nil <> pos do
+    begin
+      next := pos^.next;
+      if (now - pos^.start) > (60 * 60) then
+      begin
+        (* expire sessions after 1h *)
+        if nil = prev then
+          _sessions := pos^.next
+        else
+          prev^.next := next;
+        Free(pos);
+      end
+      else
+        prev := pos;
+      pos := next;
+    end;
+  end;
+
+(**
+ * Call with the port number as the only argument.
+ * Never terminates (other than by signals, such as CTRL-C).
+ *)
+var
+  d: PMHD_Daemon;
+  tv: timeval;
+  tvp: ptimeval;
+  rs: TFDSet;
+  ws: TFDSet;
+  es: TFDSet;
+  max: cint;
+  mhd_timeout: MHD_UNSIGNED_LONG_LONG;
+begin
+  if argc <> 2 then
+  begin
+    WriteLn(argv[0], ' PORT');
+    Halt(1);
+  end;
+  (* initialize PRNG *)
+  Randomize;
+
+  d := MHD_start_daemon(MHD_USE_DEBUG, StrToInt(argv[1]), nil, nil,
+    @create_response, nil, MHD_OPTION_CONNECTION_TIMEOUT, cuint(15),
+    MHD_OPTION_NOTIFY_COMPLETED, @request_completed_callback, nil, MHD_OPTION_END);
+  if nil = d then
+    Halt(1);
+
+  while True do
+  begin
+    expire_sessions;
+    max := 0;
+    fpFD_ZERO(rs);
+    fpFD_ZERO(ws);
+    fpFD_ZERO(es);
+    if MHD_YES <> MHD_get_fdset(d, @rs, @ws, @es, @max) then
+      Break; (* fatal internal error *)
+    if MHD_get_timeout(d, @mhd_timeout) = MHD_YES then
+    begin
+      tv.tv_sec := mhd_timeout div 1000;
+      tv.tv_usec := (mhd_timeout - (tv.tv_sec * 1000)) * 1000;
+      tvp := @tv;
+    end
+    else
+      tvp := nil;
+    fpSelect(max + 1, @rs, @ws, @es, tvp);
+    MHD_run(d);
+  end;
+  MHD_stop_daemon(d);
+end.

+ 89 - 0
packages/libmicrohttpd/examples/querystring_example.pp

@@ -0,0 +1,89 @@
+(*
+     This file is part of libmicrohttpd
+     Copyright (C) 2007, 2008 Christian Grothoff (and other contributing authors)
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*)
+(**
+ * @file querystring_example.pp (Original: querystring_example.c)
+ * @brief example for how to get the query string from libmicrohttpd
+ *        Call with an URI ending with something like "?q=QUERY"
+ * @author Christian Grothoff / Silvio Clécio
+ *)
+
+program querystring_example;
+
+{$mode objfpc}{$H+}
+
+uses
+  sysutils, cmem, ctypes, cutils, libmicrohttpd;
+
+const
+  PAGE: Pcchar = '<html><head><title>libmicrohttpd demo</title></head><body>Query string for &quot;%s&quot; was &quot;%s&quot;</body></html>';
+
+  function ahc_echo(cls:  Pointer; connection: PMHD_Connection; url: Pcchar;
+    method: Pcchar; version: Pcchar; upload_data: Pcchar;
+    upload_data_size: Psize_t; ptr: PPointer): cint; cdecl;
+  const
+    aptr: cint = 0;
+  var
+    fmt: Pcchar;
+    val: Pcchar;
+    me: Pcchar;
+    response: PMHD_Response;
+    ret: cint;
+  begin
+    fmt := cls;
+    if 0 <> strcomp(method, 'GET') then
+      Exit(MHD_NO);
+    if @aptr <> ptr^ then
+    begin
+      ptr^ := @aptr;
+      Exit(MHD_YES);
+    end;
+    ptr^ := nil;
+    val := MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, 'q');
+    me := Malloc(snprintf(nil, 0, fmt, Pcchar('q'), val) + 1);
+    if me = nil then
+      Exit(MHD_NO);
+    sprintf(me, fmt, Pcchar('q'), val);
+    response := MHD_create_response_from_buffer(strlen(me), Pointer(me),
+      MHD_RESPMEM_MUST_FREE);
+    if response = nil then
+    begin
+      Free(me);
+      Exit(MHD_NO);
+    end;
+    ret := MHD_queue_response(connection, MHD_HTTP_OK, response);
+    MHD_destroy_response(response);
+    Result := ret;
+  end;
+
+var
+  d: PMHD_Daemon;
+begin
+  if argc <> 2 then
+  begin
+    WriteLn(argv[0], ' PORT');
+    Halt(1);
+  end;
+  d := MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION or MHD_USE_DEBUG,
+         StrToInt(argv[1]), nil, nil, @ahc_echo, PAGE, MHD_OPTION_END);
+  if d = nil then
+    Halt(1);
+  ReadLn;
+  MHD_stop_daemon(d);
+end.
+

+ 94 - 0
packages/libmicrohttpd/examples/refuse_post_example.pp

@@ -0,0 +1,94 @@
+(*
+     This file is part of libmicrohttpd
+     Copyright (C) 2007, 2008 Christian Grothoff (and other contributing authors)
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*)
+(**
+ * @file refuse_post_example.pp (Original: refuse_post_example.c)
+ * @brief example for how to refuse a POST request properly
+ * @author Christian Grothoff, Sebastian Gerhardt and Silvio Clécio
+ *)
+
+program refuse_post_example;
+
+{$mode objfpc}{$H+}
+
+uses
+  sysutils, libmicrohttpd;
+
+const
+  askpage: Pcchar =
+    '<html><body>'#10+
+    'Upload a file, please!<br>'#10+
+    '<form action="/filepost" method="post" enctype="multipart/form-data">'#10+
+    '<input name="file" type="file">'#10+
+    '<input type="submit" value=" Send "></form>'#10+
+    '</body></html>';
+
+  BUSYPAGE: Pcchar = '<html><head><title>Webserver busy</title></head><body>We are too busy to process POSTs right now.</body></html>';
+
+  function ahc_echo(cls:  Pointer; connection: PMHD_Connection; url: Pcchar;
+    method: Pcchar; version: Pcchar; upload_data: Pcchar;
+    upload_data_size: Psize_t; ptr: PPointer): cint; cdecl;
+  const
+    aptr: cint = 0;
+  var
+    me: Pcchar;
+    response: PMHD_Response;
+    ret: cint;
+  begin
+    me := cls;
+    if (0 <> strcomp(method, 'GET')) and (0 <> strcomp(method, 'POST')) then
+      Exit(MHD_NO); (* unexpected method *)
+    if @aptr <> ptr^ then
+    begin
+      ptr^ := @aptr;
+      (* always to busy for POST requests *)
+      if 0 = strcomp(method, 'POST') then
+      begin
+        response := MHD_create_response_from_buffer(strlen(BUSYPAGE),
+                      Pointer(BUSYPAGE), MHD_RESPMEM_PERSISTENT);
+        ret := MHD_queue_response (connection, MHD_HTTP_SERVICE_UNAVAILABLE,
+                 response);
+        MHD_destroy_response (response);
+        Exit(ret);
+      end;
+    end;
+    ptr^ := nil; (* reset when done *)
+    response := MHD_create_response_from_buffer(strlen(me), Pointer(me),
+      MHD_RESPMEM_PERSISTENT);
+    ret := MHD_queue_response(connection, MHD_HTTP_OK, response);
+    MHD_destroy_response(response);
+    Result := ret;
+  end;
+
+var
+  d: PMHD_Daemon;
+begin
+  if argc <> 2 then
+  begin
+    WriteLn(argv[0], ' PORT');
+    Halt(1);
+  end;
+  d := MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION or MHD_USE_DEBUG,
+         StrToInt(argv[1]), nil, nil, @ahc_echo, Pointer(askpage),
+         MHD_OPTION_END);
+  if d = nil then
+    Halt(1);
+  ReadLn;
+  MHD_stop_daemon(d);
+end.
+

+ 66 - 0
packages/libmicrohttpd/examples/responseheaders.pp

@@ -0,0 +1,66 @@
+(* Feel free to use this example code in any way
+   you see fit (Public Domain) *)
+
+// Original example: https://gnunet.org/svn/libmicrohttpd/doc/examples/responseheaders.c
+
+program responseheaders;
+
+{$mode objfpc}{$H+}
+
+uses
+  BaseUnix, SysUtils, libmicrohttpd;
+
+const
+  PORT = 8888;
+  FILENAME = 'picture.png';
+  MIMETYPE = 'image/png';
+
+  function AnswerToConnection(ACls: Pointer; AConnection: PMHD_Connection;
+    AUrl: Pcchar; AMethod: Pcchar; AVersion: Pcchar; AUploadData: Pcchar;
+    AUploadDataSize: Psize_t; AConCls: PPointer): cint; cdecl;
+  const
+    errorstr: Pcchar = '<html><body>An internal server error has occured!</body></html>';
+  var
+    VFd: cint;
+    VReturn: cint;
+    VResponse: PMHD_Response;
+    VSbuf: TStat;
+  begin
+    if StrComp(AMethod, 'GET') <> 0 then
+      Exit(MHD_NO);
+    VFd := FpOpen(FILENAME, O_RDONLY);
+    VSbuf := Default(TStat);
+    if (VFd = -1) or (FpFStat(VFd, VSbuf) <> 0) then
+    begin
+      (* error accessing file *)
+      if VFd <> -1 then
+        FpClose(VFd);
+      VResponse := MHD_create_response_from_buffer(Length(errorstr),
+        Pointer(errorstr), MHD_RESPMEM_PERSISTENT);
+      if Assigned(VResponse) then
+      begin
+        VReturn := MHD_queue_response(AConnection,
+          MHD_HTTP_INTERNAL_SERVER_ERROR, VResponse);
+        MHD_destroy_response(VResponse);
+        Exit(VReturn);
+      end
+      else
+        Exit(MHD_NO);
+    end;
+    VResponse := MHD_create_response_from_fd_at_offset64(VSbuf.st_size, VFd, 0);
+    MHD_add_response_header(VResponse, 'Content-Type', MIMETYPE);
+    VReturn := MHD_queue_response(AConnection, MHD_HTTP_OK, VResponse);
+    MHD_destroy_response(VResponse);
+    Result := VReturn;
+  end;
+
+var
+  VDaemon: PMHD_Daemon;
+begin
+  VDaemon := MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, PORT, nil,
+    nil, @AnswerToConnection, nil, MHD_OPTION_END);
+  if not Assigned(VDaemon) then
+    Halt(1);
+  ReadLn;
+  MHD_stop_daemon(VDaemon);
+end.

+ 623 - 0
packages/libmicrohttpd/examples/sessions.pp

@@ -0,0 +1,623 @@
+(* Feel free to use this example code in any way
+   you see fit (Public Domain) *)
+
+// Original example: https://gnunet.org/svn/libmicrohttpd/doc/examples/sessions.c
+
+program sessions;
+
+{$mode objfpc}{$H+}
+
+uses
+  SysUtils, BaseUnix, cmem, cutils, libmicrohttpd;
+
+const
+  (**
+   * Invalid method page.
+   *)
+  METHOD_ERROR = '<html><head><title>Illegal request</title></head><body>Go away.</body></html>';
+
+  (**
+   * Invalid URL page.
+   *)
+  NOT_FOUND_ERROR = '<html><head><title>Not found</title></head><body>Go away.</body></html>';
+
+  (**
+   * Front page. (/)
+   *)
+  MAIN_PAGE = '<html><head><title>Welcome</title></head><body><form action="/2" method="post">What is your name? <input type="text" name="v1" value="%s" /><input type="submit" value="Next" /></body></html>';
+
+  (**
+   * Second page. (/2)
+   *)
+  SECOND_PAGE = '<html><head><title>Tell me more</title></head><body><a href="/">previous</a> <form action="/S" method="post">%s, what is your job? <input type="text" name="v2" value="%s" /><input type="submit" value="Next" /></body></html>';
+
+  (**
+   * Second page (/S)
+   *)
+  SUBMIT_PAGE = '<html><head><title>Ready to submit?</title></head><body><form action="/F" method="post"><a href="/2">previous </a> <input type="hidden" name="DONE" value="yes" /><input type="submit" value="Submit" /></body></html>';
+
+  (**
+   * Last page.
+   *)
+  LAST_PAGE = '<html><head><title>Thank you</title></head><body>Thank you.</body></html>';
+
+  (**
+   * Name of our cookie.
+   *)
+  COOKIE_NAME = 'session';
+
+type
+  (**
+   * State we keep for each user/session/browser.
+   *)
+  PSession = ^TSession;
+  TSession = packed record
+    (**
+     * We keep all sessions in a linked list.
+     *)
+    next: PSession;
+
+    (**
+     * Unique ID for this session.
+     *)
+    sid: array[0..33] of Char;
+
+    (**
+     * Reference counter giving the number of connections
+     * currently using this session.
+     *)
+    rc: cint;
+
+    (**
+     * Time when this session was last active.
+     *)
+    start: time_t;
+
+    (**
+     * String submitted via form.
+     *)
+    value_1: array[0..64] of Char;
+
+    (**
+     * Another value submitted via form.
+     *)
+    value_2: array[0..64] of Char;
+  end;
+
+  (**
+   * Data kept per request.
+   *)
+  TRequest = packed record
+
+    (**
+     * Associated session.
+     *)
+    session: PSession;
+
+    (**
+     * Post processor handling form data (IF this is
+     * a POST request).
+     *)
+    pp: PMHD_PostProcessor;
+
+    (**
+     * URL to serve in response to this POST (if this request
+     * was a 'POST')
+     *)
+    post_url: pcchar;
+
+  end;
+  PRequest = ^TRequest;
+
+var
+  (**
+   * Linked list of all active sessions.  Yes, O(n) but a
+   * hash table would be overkill for a simple example...
+   *)
+  _sessions: PSession;
+
+  (**
+   * Return the session handle for this connection, or
+   * create one if this is a new user.
+   *)
+  function get_session(connection: PMHD_Connection): PSession;
+  var
+    ret: PSession;
+    cookie: pcchar;
+  begin
+    cookie := MHD_lookup_connection_value(connection, MHD_COOKIE_KIND, COOKIE_NAME);
+    if cookie <> nil then
+    begin
+      (* find existing session *)
+      ret := _sessions;
+      while nil <> ret do
+      begin
+        if StrComp(cookie, ret^.sid) = 0 then
+          Break;
+        ret := ret^.next;
+      end;
+      if nil <> ret then
+      begin
+        Inc(ret^.rc);
+        Exit(ret);
+      end;
+    end;
+    (* create fresh session *)
+    ret := CAlloc(1, SizeOf(TSession));
+    if nil = ret then
+    begin
+      WriteLn(stderr, 'calloc error: ', strerror(errno^));
+      Exit(nil);
+    end;
+    (* not a super-secure way to generate a random session ID,
+       but should do for a simple example... *)
+    snprintf(ret^.sid, SizeOf(ret^.sid), '%X%X%X%X', Cardinal(rand),
+      Cardinal(rand), Cardinal(rand), Cardinal(rand));
+    Inc(ret^.rc);
+    ret^.start := FpTime;
+    ret^.next := _sessions;
+    _sessions := ret;
+    Result := ret;
+  end;
+
+(**
+ * Type of handler that generates a reply.
+ *
+ * @param cls content for the page (handler-specific)
+ * @param mime mime type to use
+ * @param session session information
+ * @param connection connection to process
+ * @param MHD_YES on success, MHD_NO on failure
+ *)
+type
+  TPageHandler = function(cls: Pointer; mime: Pcchar; session: PSession;
+    connection: PMHD_Connection): LongInt; cdecl;
+
+  (**
+   * Entry we generate for each page served.
+   *)
+
+  { TPage }
+
+  TPage = packed record
+    (**
+     * Acceptable URL for this page.
+     *)
+    url: Pcchar;
+
+    (**
+     * Mime type to set for the page.
+     *)
+    mime: Pcchar;
+
+    (**
+     * Handler to call to generate response.
+     *)
+    handler: TPageHandler;
+
+    (**
+     * Extra argument to handler.
+     *)
+    handler_cls: Pcchar;
+  end;
+
+  (**
+   * Add header to response to set a session cookie.
+   *
+   * @param session session to use
+   * @param response response to modify
+   *)
+  procedure add_session_cookie(session: PSession; response: PMHD_Response);
+  var
+    cstr: array[0..256] of Char;
+  begin
+    snprintf(cstr, SizeOf(cstr), '%s=%s', COOKIE_NAME, session^.sid);
+    if MHD_NO =
+      MHD_add_response_header(response, MHD_HTTP_HEADER_SET_COOKIE, cstr) then
+      WriteLn(stderr, 'Failed to set session cookie header!');
+  end;
+
+  (**
+   * Handler that returns a simple static HTTP page that
+   * is passed in via 'cls'.
+   *
+   * @param cls a 'const char *' with the HTML webpage to return
+   * @param mime mime type to use
+   * @param session session handle
+   * @param connection connection to use
+   *)
+  function serve_simple_form(cls: Pointer; mime: Pcchar; session: PSession;
+    connection: PMHD_Connection): cint; cdecl;
+  var
+    ret: cint;
+    form: Pcchar;
+    response: PMHD_Response;
+  begin
+    form := cls;
+    (* return static form *)
+    response := MHD_create_response_from_buffer(Length(form), Pointer(form),
+      MHD_RESPMEM_PERSISTENT);
+    add_session_cookie(session, response);
+    MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_ENCODING, mime);
+    ret := MHD_queue_response(connection, MHD_HTTP_OK, response);
+    MHD_destroy_response(response);
+    Result := ret;
+  end;
+
+  (**
+   * Handler that adds the 'v1' value to the given HTML code.
+   *
+   * @param cls a 'const char *' with the HTML webpage to return
+   * @param mime mime type to use
+   * @param session session handle
+   * @param connection connection to use
+   *)
+  function fill_v1_form(cls: Pointer; mime: Pcchar; session: PSession;
+    connection: PMHD_Connection): cint; cdecl;
+  var
+    ret: cint;
+    form: Pcchar;
+    reply: Pcchar;
+    response: PMHD_Response;
+  begin
+    form := cls;
+    if asprintf(@reply, form, session^.value_1) = -1 then
+      (* oops *)
+      Exit(MHD_NO);
+    (* return static form *)
+    response := MHD_create_response_from_buffer(Length(reply), Pointer(reply),
+      MHD_RESPMEM_MUST_FREE);
+    add_session_cookie(session, response);
+    MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_ENCODING, mime);
+    ret := MHD_queue_response(connection, MHD_HTTP_OK, response);
+    MHD_destroy_response(response);
+    Result := ret;
+  end;
+
+  (**
+   * Handler that adds the 'v1' and 'v2' values to the given HTML code.
+   *
+   * @param cls a 'const char *' with the HTML webpage to return
+   * @param mime mime type to use
+   * @param session session handle
+   * @param connection connection to use
+   *)
+  function fill_v1_v2_form(cls: Pointer; mime: Pcchar; session: PSession;
+    connection: PMHD_Connection): cint; cdecl;
+  var
+    ret: cint;
+    form: Pcchar;
+    reply: Pcchar;
+    response: PMHD_Response;
+  begin
+    form := cls;
+    if asprintf(@reply, form, session^.value_1, session^.value_2) = -1 then
+      (* oops *)
+      Exit(MHD_NO);
+    (* return static form *)
+    response := MHD_create_response_from_buffer(Length(reply), Pointer(reply),
+      MHD_RESPMEM_MUST_FREE);
+    add_session_cookie(session, response);
+    MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_ENCODING, mime);
+    ret := MHD_queue_response(connection, MHD_HTTP_OK, response);
+    MHD_destroy_response(response);
+    Result := ret;
+  end;
+
+  (**
+   * Handler used to generate a 404 reply.
+   *
+   * @param cls a 'const char *' with the HTML webpage to return
+   * @param mime mime type to use
+   * @param session session handle
+   * @param connection connection to use
+   *)
+  function not_found_page(cls: Pointer; mime: Pcchar; session: PSession;
+    connection: PMHD_Connection): cint; cdecl;
+  var
+    ret: cint;
+    response: PMHD_Response;
+  begin
+    (* unsupported HTTP method *)
+    response := MHD_create_response_from_buffer(Length(NOT_FOUND_ERROR),
+      Pcchar(NOT_FOUND_ERROR), MHD_RESPMEM_PERSISTENT);
+    ret := MHD_queue_response(connection, MHD_HTTP_NOT_FOUND, response);
+    MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_ENCODING, mime);
+    MHD_destroy_response(response);
+    Result := ret;
+  end;
+
+const
+  (**
+   * List of all pages served by this HTTP server.
+   *)
+  pages: array[0..4] of TPage = (
+    (url: '/';  mime: 'text/html'; handler: @fill_v1_form; handler_cls: MAIN_PAGE),
+    (url: '/2'; mime: 'text/html'; handler: @fill_v1_v2_form; handler_cls: SECOND_PAGE),
+    (url: '/S'; mime: 'text/html'; handler: @serve_simple_form; handler_cls: SUBMIT_PAGE),
+    (url: '/F'; mime: 'text/html'; handler: @serve_simple_form; handler_cls: LAST_PAGE),
+    (url: nil; mime: nil; handler: @not_found_page; handler_cls: nil) (* 404 *)
+  );
+
+  (**
+   * Iterator over key-value pairs where the value
+   * maybe made available in increments and/or may
+   * not be zero-terminated.  Used for processing
+   * POST data.
+   *
+   * @param cls user-specified closure
+   * @param kind type of the value
+   * @param key 0-terminated key for the value
+   * @param filename name of the uploaded file, NULL if not known
+   * @param content_type mime-type of the data, NULL if not known
+   * @param transfer_encoding encoding of the data, NULL if not known
+   * @param data pointer to size bytes of data at the
+   *              specified offset
+   * @param off offset of data in the overall value
+   * @param size number of bytes in data available
+   * @return MHD_YES to continue iterating,
+   *         MHD_NO to abort the iteration
+   *)
+  function post_iterator(cls: Pointer; kind: MHD_ValueKind; key: Pcchar;
+    filename: Pcchar; content_type: Pcchar; transfer_encoding: Pcchar;
+    data: Pcchar; off: cuint64; size: size_t): cint; cdecl;
+  var
+    request: PRequest;
+    session: PSession;
+  begin
+    request := cls;
+    session := request^.session;
+    if StrComp('DONE', key) = 0 then
+    begin
+      WriteLn(stdout, Format('Session `%s'' submitted `%s'', `%s''', [
+        session^.sid, session^.value_1, session^.value_2]));
+      Exit(MHD_YES);
+    end;
+    if StrComp('v1', key) = 0 then
+    begin
+      if (size + off) > SizeOf(session^.value_1) then
+        size := SizeOf(session^.value_1) - off;
+      Move(data^, session^.value_1[off], size);
+      if (size + off) < SizeOf(session^.value_1) then
+        session^.value_1[size + off] := #0;
+      Exit(MHD_YES);
+    end;
+    if StrComp('v2', key) = 0 then
+    begin
+      if (size + off) > SizeOf(session^.value_2) then
+        size := SizeOf(session^.value_2) - off;
+      Move(data^, session^.value_2[off], size);
+      if (size + off) < SizeOf(session^.value_2) then
+        session^.value_2[size + off] := #0;
+      Exit(MHD_YES);
+    end;
+    WriteLn(stderr, Format('Unsupported form value `%s''', [key]));
+    Result := MHD_YES;
+  end;
+
+  (**
+   * Main MHD callback for handling requests.
+   *
+   *
+   * @param cls argument given together with the function
+   *        pointer when the handler was registered with MHD
+   * @param connection handle to connection which is being processed
+   * @param url the requested url
+   * @param method the HTTP method used ("GET", "PUT", etc.)
+   * @param version the HTTP version string (i.e. "HTTP/1.1")
+   * @param upload_data the data being uploaded (excluding HEADERS,
+   *        for a POST that fits into memory and that is encoded
+   *        with a supported encoding, the POST data will NOT be
+   *        given in upload_data and is instead available as
+   *        part of MHD_get_connection_values; very large POST
+   *        data *will* be made available incrementally in
+   *        upload_data)
+   * @param upload_data_size set initially to the size of the
+   *        upload_data provided; the method must update this
+   *        value to the number of bytes NOT processed;
+   * @param ptr pointer that the callback can set to some
+   *        address and that will be preserved by MHD for future
+   *        calls for this request; since the access handler may
+   *        be called many times (i.e., for a PUT/POST operation
+   *        with plenty of upload data) this allows the application
+   *        to easily associate some request-specific state.
+   *        If necessary, this state can be cleaned up in the
+   *        global "MHD_RequestCompleted" callback (which
+   *        can be set with the MHD_OPTION_NOTIFY_COMPLETED).
+   *        Initially, <tt>*con_cls</tt> will be NULL.
+   * @return MHS_YES if the connection was handled successfully,
+   *         MHS_NO if the socket must be closed due to a serios
+   *         error while handling the request
+   *)
+  function create_response(cls: Pointer; connection: PMHD_Connection;
+    url: Pcchar; method: Pcchar; version: Pcchar; upload_data: Pcchar;
+    upload_data_size: Psize_t; ptr: PPointer): cint; cdecl;
+  var
+    response: PMHD_Response;
+    request: PRequest;
+    session: PSession;
+    ret: cint;
+    i: Cardinal;
+  begin
+    request := ptr^;
+    if nil = request then
+    begin
+      request := CAlloc(1, SizeOf(TRequest));
+      if nil = request then
+      begin
+        WriteLn(stderr, 'calloc error: ', strerror(errno^));
+        Exit(MHD_NO);
+      end;
+      ptr^ := request;
+      if StrComp(method, MHD_HTTP_METHOD_POST) = 0 then
+      begin
+        request^.pp := MHD_create_post_processor(connection, 1024,
+          @post_iterator, request);
+        if nil = request^.pp then
+        begin
+          WriteLn(stderr, Format('Failed to setup post processor for `%s''',
+            [url]));
+          Exit(MHD_NO); (* internal error *)
+        end;
+      end;
+      Exit(MHD_YES);
+    end;
+    if nil = request^.session then
+    begin
+      request^.session := get_session(connection);
+      if nil = request^.session then
+      begin
+        WriteLn(stderr, Format('Failed to setup session for `%s''', [url]));
+        Exit(MHD_NO); (* internal error *)
+      end;
+    end;
+    session := request^.session;
+    session^.start := FpTime;
+    if StrComp(method, MHD_HTTP_METHOD_POST) = 0 then
+    begin
+      (* evaluate POST data *)
+      MHD_post_process(request^.pp, upload_data, upload_data_size^);
+      if upload_data_size^ <> 0 then
+      begin
+        upload_data_size^ := 0;
+        Exit(MHD_YES);
+      end;
+      (* done with POST data, serve response *)
+      MHD_destroy_post_processor(request^.pp);
+      request^.pp := nil;
+      method := MHD_HTTP_METHOD_GET; (* fake 'GET' *)
+      if nil <> request^.post_url then
+        url := request^.post_url;
+    end;
+    if (StrComp(method, MHD_HTTP_METHOD_GET) = 0) or
+      (StrComp(method, MHD_HTTP_METHOD_HEAD) = 0) then
+    begin
+      (* find out which page to serve *)
+      i := 0;
+      while (pages[i].url <> nil) and (StrComp(pages[i].url, url) <> 0) do
+        Inc(i);
+      ret := pages[i].handler(pages[i].handler_cls, pages[i].mime, session,
+        connection);
+      if ret <> MHD_YES then
+        WriteLn(stderr, Format('Failed to create page for `%s''', [url]));
+      Exit(ret);
+    end;
+    (* unsupported HTTP method *)
+    response := MHD_create_response_from_buffer(Length(METHOD_ERROR),
+      Pcchar(METHOD_ERROR), MHD_RESPMEM_PERSISTENT);
+    ret := MHD_queue_response(connection, MHD_HTTP_NOT_ACCEPTABLE, response);
+    MHD_destroy_response(response);
+    Result := ret;
+  end;
+
+  (**
+   * Callback called upon completion of a request.
+   * Decrements session reference counter.
+   *
+   * @param cls not used
+   * @param connection connection that completed
+   * @param con_cls session handle
+   * @param toe status code
+   *)
+  procedure request_completed_callback(cls: Pointer; connection: PMHD_Connection;
+    con_cls: PPointer; toe: MHD_RequestTerminationCode);
+  var
+    request: PRequest;
+  begin
+    request := con_cls^;
+    if nil = request then
+      Exit;
+    if nil <> request^.session then
+      Dec(request^.session^.rc);
+    if nil <> request^.pp then
+      MHD_destroy_post_processor(request^.pp);
+    Free(request);
+  end;
+
+  (**
+   * Clean up handles of sessions that have been idle for
+   * too long.
+   *)
+  procedure expire_sessions;
+  var
+    pos: PSession;
+    prev: PSession;
+    next: PSession;
+    now: time_t;
+  begin
+    now := FpTime;
+    prev := nil;
+    pos := _sessions;
+    while nil <> pos do
+    begin
+      next := pos^.next;
+      if (now - pos^.start) > (60 * 60) then
+      begin
+        (* expire sessions after 1h *)
+        if nil = prev then
+          _sessions := pos^.next
+        else
+          prev^.next := next;
+        Free(pos);
+      end
+      else
+        prev := pos;
+      pos := next;
+    end;
+  end;
+
+(**
+ * Call with the port number as the only argument.
+ * Never terminates (other than by signals, such as CTRL-C).
+ *)
+var
+  d: PMHD_Daemon;
+  tv: timeval;
+  tvp: ptimeval;
+  rs: TFDSet;
+  ws: TFDSet;
+  es: TFDSet;
+  max: cint;
+  mhd_timeout: MHD_UNSIGNED_LONG_LONG;
+begin
+  if argc <> 2 then
+  begin
+    WriteLn(argv[0], ' PORT');
+    Halt(1);
+  end;
+  (* initialize PRNG *)
+  Randomize;
+
+  d := MHD_start_daemon(MHD_USE_DEBUG, StrToInt(argv[1]), nil, nil,
+    @create_response, nil, MHD_OPTION_CONNECTION_TIMEOUT, cuint(15),
+    MHD_OPTION_NOTIFY_COMPLETED, @request_completed_callback, nil, MHD_OPTION_END);
+  if nil = d then
+    Halt(1);
+
+  while True do
+  begin
+    expire_sessions;
+    max := 0;
+    fpFD_ZERO(rs);
+    fpFD_ZERO(ws);
+    fpFD_ZERO(es);
+    if MHD_YES <> MHD_get_fdset(d, @rs, @ws, @es, @max) then
+      Break; (* fatal internal error *)
+    if MHD_get_timeout(d, @mhd_timeout) = MHD_YES then
+    begin
+      tv.tv_sec := mhd_timeout div 1000;
+      tv.tv_usec := (mhd_timeout - (tv.tv_sec * 1000)) * 1000;
+      tvp := @tv;
+    end
+    else
+      tvp := nil;
+    if -1 = fpSelect(max + 1, @rs, @ws, @es, tvp) then
+    begin
+      if (ESysEINTR <> errno^) then
+        WriteLn(stderr, 'Aborting due to error during select: ', strerror(errno^));
+      Break;
+    end;
+    MHD_run(d);
+  end;
+  MHD_stop_daemon(d);
+end.

+ 155 - 0
packages/libmicrohttpd/examples/simplepost.pp

@@ -0,0 +1,155 @@
+(* Feel free to use this example code in any way
+   you see fit (Public Domain) *)
+
+// Original example: https://gnunet.org/svn/libmicrohttpd/doc/examples/simplepost.c
+
+program simplepost;
+
+{$mode objfpc}{$H+}
+
+uses
+  SysUtils, cmem, cutils, libmicrohttpd;
+
+const
+  PORT = 8888;
+  POSTBUFFERSIZE = 512;
+  MAXNAMESIZE = 20;
+  MAXANSWERSIZE = 512;
+  GET = 0;
+  POST = 1;
+
+  askpage: Pcchar =
+    '<html><body>'+
+    'What''s your name, Sir?<br>'+
+    '<form action="/namepost" method="post">'+
+    '<input name="name" type="text">'+
+    '<input type="submit" value=" Send "></form>'+
+    '</body></html>';
+
+  greetingpage: Pcchar = '<html><body><h1>Welcome, %s!</center></h1></body></html>';
+
+  errorpage: Pcchar = '<html><body>This doesn''t seem to be right.</body></html>';
+
+type
+  Tconnection_info_struct = packed record
+    connectiontype: cint;
+    answerstring: Pcchar;
+    postprocessor: PMHD_PostProcessor;
+  end;
+  Pconnection_info_struct = ^Tconnection_info_struct;
+
+  function send_page(connection: PMHD_Connection; page: Pcchar): cint; cdecl;
+  var
+    ret: cint;
+    response: PMHD_Response;
+  begin
+    response := MHD_create_response_from_buffer(Length(page),
+      Pointer(page), MHD_RESPMEM_PERSISTENT);
+    if not Assigned(response) then
+      Exit(MHD_NO);
+    ret := MHD_queue_response(connection, MHD_HTTP_OK, response);
+    MHD_destroy_response(response);
+    Result := ret;
+  end;
+
+  function iterate_post(coninfo_cls: Pointer; kind: MHD_ValueKind;
+    key: Pcchar; filename: Pcchar; content_type: Pcchar; transfer_encoding: Pcchar;
+    Data: Pcchar; off: cuint64; size: size_t): cint; cdecl;
+  var
+    con_info: Pconnection_info_struct;
+    answerstring: Pcchar;
+  begin
+    con_info := coninfo_cls;
+    if 0 = strcomp(key, 'name') then
+    begin
+      if (size > 0) and (size <= MAXNAMESIZE) then
+      begin
+        answerstring := Malloc(MAXANSWERSIZE);
+        if not Assigned(answerstring) then
+          Exit(MHD_NO);
+        snprintf(answerstring, MAXANSWERSIZE, greetingpage, Data);
+        con_info^.answerstring := answerstring;
+      end
+      else
+        con_info^.answerstring := nil;
+      Exit(MHD_NO);
+    end;
+    Result := MHD_YES;
+  end;
+
+  procedure request_completed(cls: Pointer; connection: PMHD_Connection;
+    con_cls: PPointer; toe: MHD_RequestTerminationCode); cdecl;
+  var
+    con_info: Pconnection_info_struct;
+  begin
+    con_info := con_cls^;
+    if nil = con_info then
+      Exit;
+    if con_info^.connectiontype = POST then
+    begin
+      MHD_destroy_post_processor(con_info^.postprocessor);
+      if Assigned(con_info^.answerstring) then
+        Free(con_info^.answerstring);
+    end;
+    Free(con_info);
+    con_cls^ := nil;
+  end;
+
+  function answer_to_connection(cls: Pointer; connection: PMHD_Connection;
+    url: Pcchar; method: Pcchar; version: Pcchar; upload_data: Pcchar;
+    upload_data_size: Psize_t; con_cls: PPointer): cint; cdecl;
+  var
+    con_info: Pconnection_info_struct;
+  begin
+    if nil = con_cls^ then
+    begin
+      con_info := Malloc(SizeOf(Tconnection_info_struct));
+      if nil = con_info then
+        Exit(MHD_NO);
+      con_info^.answerstring := nil;
+      if 0 = strcomp(method, 'POST') then
+      begin
+        con_info^.postprocessor :=
+          MHD_create_post_processor(connection, POSTBUFFERSIZE,
+          @iterate_post, Pointer(con_info));
+        if nil = con_info^.postprocessor then
+        begin
+          Free(con_info);
+          Exit(MHD_NO);
+        end;
+        con_info^.connectiontype := POST;
+      end
+      else
+        con_info^.connectiontype := GET;
+      con_cls^ := Pointer(con_info);
+      Exit(MHD_YES);
+    end;
+    if 0 = strcomp(method, 'GET') then
+      Exit(send_page(connection, askpage));
+    if 0 = strcomp(method, 'POST') then
+    begin
+      con_info := con_cls^;
+      if upload_data_size^ <> 0 then
+      begin
+        MHD_post_process(con_info^.postprocessor, upload_data, upload_data_size^);
+        upload_data_size^ := 0;
+        Exit(MHD_YES);
+      end
+      else
+      if nil <> con_info^.answerstring then
+        Exit(send_page(connection, con_info^.answerstring));
+    end;
+    Result := send_page(connection, errorpage);
+  end;
+
+var
+  daemon: PMHD_Daemon;
+begin
+  daemon := MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, PORT, nil, nil,
+    @answer_to_connection, nil, MHD_OPTION_NOTIFY_COMPLETED, @request_completed,
+    nil, MHD_OPTION_END);
+  if nil = daemon then
+    Halt(1);
+  ReadLn;
+  MHD_stop_daemon(daemon);
+end.

+ 234 - 0
packages/libmicrohttpd/examples/tlsauthentication.pp

@@ -0,0 +1,234 @@
+(* Feel free to use this example code in any way
+   you see fit (Public Domain) *)
+
+// Original example: https://gnunet.org/svn/libmicrohttpd/doc/examples/tlsauthentication.c
+
+(*
+ * Generate PEM files for test this example:
+ *
+ * openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem
+ *
+ * or
+ *
+ * openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout server.key -out server.pem
+ *)
+
+program tlsauthentication;
+
+{$mode objfpc}{$H+}
+
+uses
+  SysUtils, ctypes, cmem, cutils, libmicrohttpd;
+
+const
+  PORT = 8888;
+  REALM = '"Maintenance"';
+  USER = 'a legitimate user';
+  PASSWORD = 'and his password';
+
+  SERVERKEYFILE = 'server.key';
+  SERVERCERTFILE = 'server.pem';
+
+  function iif(c: cbool; t, f: culong): culong;
+  begin
+    if c then
+      Result := t
+    else
+      Result := f;
+  end;
+
+  function string_to_base64(message: Pcchar): Pcchar;
+  var
+    lookup: Pcchar = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+    l: culong;
+    i: cint;
+    tmp: Pcchar;
+    len: SizeInt;
+  begin
+    len := strlen(message);
+    tmp := Malloc(len * 2);
+    if nil = tmp then
+      Exit(tmp);
+    tmp[0] := #0;
+    i := 0;
+    while i < len do
+    begin
+      l := (culong(message[i]) shl 16)
+        or iif((i + 1) < len, culong(message[i + 1]) shl 8, 0)
+        or iif((i + 2) < len, culong(message[i + 2]), 0);
+      strncat(tmp, @lookup[(l shr 18) and $3F], 1);
+      strncat(tmp, @lookup[(l shr 12) and $3F], 1);
+      if i + 1 < len then
+        strncat(tmp, @lookup[(l shr 6) and $3F], 1);
+      if i + 2 < len then
+        strncat(tmp, @lookup[l and $3F], 1);
+      i += 3;
+    end;
+    if (len mod 3 = 1) then
+      strncat(tmp, '===', 3 - len mod 3);
+    Result := tmp;
+  end;
+
+  function get_file_size(filename: Pcchar): clong;
+  var
+    fp: FILEptr;
+    size: clong;
+  begin
+    fp := fopen(filename, fopenread);
+    if Assigned(fp) then
+    begin
+      if 0 <> fseek(fp, 0, SEEK_END) then
+        size := 0;
+      size := ftell(fp);
+      if -1 = size then
+        size := 0;
+      fclose(fp);
+      Result := size;
+    end
+    else
+      Result := 0;
+  end;
+
+  function load_file(filename: Pcchar): Pcchar;
+  var
+    fp: FILEptr;
+    buffer: Pcchar;
+    size: clong;
+  begin
+    size := get_file_size(filename);
+    if size = 0 then
+      Exit(nil);
+    fp := fopen(filename, fopenread);
+    if not Assigned(fp) then
+      Exit(nil);
+    buffer := Malloc(size);
+    if not Assigned(buffer) then
+    begin
+      fclose(fp);
+      Exit(nil);
+    end;
+    if size <> fread(buffer, 1, size, fp) then
+    begin
+      free(buffer);
+      buffer := nil;
+    end;
+    fclose(fp);
+    Result := buffer;
+  end;
+
+  function ask_for_authentication(connection: PMHD_Connection;
+    realm: Pcchar): cint; cdecl;
+  var
+    ret: cint;
+    response: PMHD_Response;
+    headervalue: Pcchar;
+    strbase: Pcchar = 'Basic realm=';
+  begin
+    response := MHD_create_response_from_buffer(0, nil, MHD_RESPMEM_PERSISTENT);
+    if not Assigned(response) then
+      Exit(MHD_NO);
+    headervalue := Malloc(strlen(strbase) + strlen(realm) + 1);
+    if not Assigned(headervalue) then
+      Exit(MHD_NO);
+    strcpy(headervalue, strbase);
+    strcat(headervalue, realm);
+    ret := MHD_add_response_header(response, 'WWW-Authenticate', headervalue);
+    Free(headervalue);
+    if ret <> 1 then
+    begin
+      MHD_destroy_response(response);
+      Exit(MHD_NO);
+    end;
+    ret := MHD_queue_response(connection, MHD_HTTP_UNAUTHORIZED, response);
+    MHD_destroy_response(response);
+    Result := ret;
+  end;
+
+  function is_authenticated(connection: PMHD_Connection;
+    username, password: Pcchar): cint; cdecl;
+  var
+    headervalue: Pcchar;
+    expected_b64, expected: Pcchar;
+    strbase: Pcchar = 'Basic ';
+    authenticated: cint;
+  begin
+    headervalue := MHD_lookup_connection_value(connection, MHD_HEADER_KIND,
+      'Authorization');
+    if nil = headervalue then
+      Exit(0);
+    if 0 <> strncmp(headervalue, strbase, strlen(strbase)) then
+      Exit(0);
+    expected := malloc(strlen(username) + 1 + strlen(password) + 1);
+    if nil = expected then
+      Exit(0);
+    strcpy(expected, username);
+    strcat(expected, ':');
+    strcat(expected, password);
+    expected_b64 := string_to_base64(expected);
+    free(expected);
+    if nil = expected_b64 then
+      Exit(0);
+    authenticated := cint(strcomp(headervalue + strlen(strbase), expected_b64) = 0);
+    Free(expected_b64);
+    Result := authenticated;
+  end;
+
+  function secret_page(connection: PMHD_Connection): cint; cdecl;
+  var
+    ret: cint;
+    response: PMHD_Response;
+    page: Pcchar = '<html><body>A secret.</body></html>';
+  begin
+    response := MHD_create_response_from_buffer(strlen(page), Pointer(page),
+      MHD_RESPMEM_PERSISTENT);
+    if not Assigned(response) then
+      Exit(MHD_NO);
+    ret := MHD_queue_response(connection, MHD_HTTP_OK, response);
+    MHD_destroy_response(response);
+    Result := ret;
+  end;
+
+  function answer_to_connection(cls: Pointer; connection: PMHD_Connection;
+    url: Pcchar; method: Pcchar; version: Pcchar; upload_data: Pcchar;
+    upload_data_size: Psize_t; con_cls: PPointer): cint; cdecl;
+  begin
+    if 0 <> strcomp(method, 'GET') then
+      Exit(MHD_NO);
+    if nil = con_cls^ then
+    begin
+      con_cls^ := connection;
+      Exit(MHD_YES);
+    end;
+    if is_authenticated(connection, USER, PASSWORD) <> 1 then
+      Exit(ask_for_authentication(connection, REALM));
+    Result := secret_page(connection);
+  end;
+
+var
+  daemon: PMHD_Daemon;
+  key_pem: Pcchar;
+  cert_pem: Pcchar;
+begin
+  key_pem := load_file(SERVERKEYFILE);
+  cert_pem := load_file(SERVERCERTFILE);
+  if (key_pem = nil) or (cert_pem = nil) then
+  begin
+    WriteLn('The key/certificate files could not be read.');
+    Halt(1);
+  end;
+  daemon := MHD_start_daemon(MHD_USE_SELECT_INTERNALLY or MHD_USE_SSL, PORT,
+    nil, nil, @answer_to_connection, nil, MHD_OPTION_HTTPS_MEM_KEY, key_pem,
+    MHD_OPTION_HTTPS_MEM_CERT, cert_pem, MHD_OPTION_END);
+  if nil = daemon then
+  begin
+    WriteLn(cert_pem);
+    Free(key_pem);
+    Free(cert_pem);
+    Halt(1);
+  end;
+  ReadLn;
+  MHD_stop_daemon(daemon);
+  Free(key_pem);
+  Free(cert_pem);
+end.
+

+ 59 - 0
packages/libmicrohttpd/fpmake.pp

@@ -0,0 +1,59 @@
+{$ifndef ALLPACKAGES}
+{$mode objfpc}{$H+}
+program fpmake;
+
+uses fpmkunit;
+
+Var
+  P : TPackage;
+  T : TTarget;
+begin
+  With Installer do
+    begin
+{$endif ALLPACKAGES}
+
+    P:=AddPackage('libmicrohttpd');
+{$ifdef ALLPACKAGES}
+    P.Directory:=ADirectory;
+{$endif ALLPACKAGES}
+    P.Version:='3.1.1';
+    P.Author := 'Library: GNU foundation, header: Silvio Clecio)';
+    P.License := 'Library: LGPL or later, header: LGPL with modification, ';
+    P.HomepageURL := 'www.gnu.org';
+    P.Email := '';
+    P.Description := 'Event based micro-http server library interface';
+    P.NeedLibC:= true;
+    P.OSes := [win32,win64,linux];
+    P.SourcePath.Add('src');
+    P.IncludePath.Add('src');
+    T:=P.Targets.AddUnit('libmicrohttpd.pp');
+    P.ExamplePath.Add('examples');
+    T:=P.Targets.AddExampleProgram('basicauthentication.pp');
+    T:=P.Targets.AddExampleProgram('benchmark_https.pp');
+    T:=P.Targets.AddExampleProgram('benchmark.pp');
+    T:=P.Targets.AddExampleProgram('chunked_example.pp');
+    T:=P.Targets.AddExampleProgram('demo_https.pp');
+    T:=P.Targets.AddExampleProgram('demo.pp');
+    T:=P.Targets.AddExampleProgram('digest_auth_example.pp');
+    T:=P.Targets.AddExampleProgram('dual_stack_example.pp');
+    T:=P.Targets.AddExampleProgram('fileserver_example_dirs.pp');
+    T:=P.Targets.AddExampleProgram('fileserver_example_external_select.pp');
+    T:=P.Targets.AddExampleProgram('fileserver_example.pp');
+    T:=P.Targets.AddExampleProgram('hellobrowser.pp');
+    T:=P.Targets.AddExampleProgram('https_fileserver_example.pp');
+    T:=P.Targets.AddExampleProgram('largepost.pp');
+    T:=P.Targets.AddExampleProgram('logging.pp');
+    T:=P.Targets.AddExampleProgram('minimal_example_comet.pp');
+    T:=P.Targets.AddExampleProgram('minimal_example.pp');
+    T:=P.Targets.AddExampleProgram('post_example.pp');
+    T:=P.Targets.AddExampleProgram('querystring_example.pp');
+    T:=P.Targets.AddExampleProgram('refuse_post_example.pp');
+    T:=P.Targets.AddExampleProgram('responseheaders.pp');
+    T:=P.Targets.AddExampleProgram('sessions.pp');
+    T:=P.Targets.AddExampleProgram('simplepost.pp');
+    T:=P.Targets.AddExampleProgram('tlsauthentication.pp');
+{$ifndef ALLPACKAGES}
+    Run;
+    end;
+end.
+{$endif ALLPACKAGES}

+ 485 - 0
packages/libmicrohttpd/src/libmicrohttpd.pp

@@ -0,0 +1,485 @@
+{
+    This file is part of the Free Pascal packages
+    Copyright (c) 2015 by Silvio Clecio, Gilson Nunes and Joao Morais
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************
+
+   The GNU libmicrohttpd library is governed by GNU copyright, see the
+   GNU libmicrohttpd website for this:
+
+   https://www.gnu.org/software/libmicrohttpd/
+}
+
+unit libmicrohttpd;
+
+interface
+
+uses
+{$IFDEF MSWINDOWS}
+  WinSock2,
+{$ENDIF}
+{$IFDEF FPC}
+  {$IFDEF UNIX}BaseUnix, Unix,{$ENDIF}CTypes, Sockets
+{$ELSE}
+  WinTypes
+{$ENDIF};
+
+const
+  MHD_LIB_NAME = {$IFDEF MSWINDOWS}'libmicrohttpd-10'{$ELSE}'microhttpd'{$ENDIF};
+
+{$IFDEF FPC}
+  {$PACKRECORDS C}
+{$ENDIF}
+
+{$IFDEF UNIX}
+  FD_SETSIZE = 64;
+{$ENDIF}
+{$IFDEF UINT64_MAX}
+  MHD_SIZE_UNKNOWN = UINT64_MAX;
+{$ELSE}
+  MHD_SIZE_UNKNOWN = -1;
+{$ENDIF}
+{$IFDEF SIZE_MAX}
+  MHD_CONTENT_READER_END_OF_STREAM = SIZE_MAX;
+  MHD_CONTENT_READER_END_WITH_ERROR = SIZE_MAX - 1;
+{$ELSE}
+  MHD_CONTENT_READER_END_OF_STREAM = -1;
+  MHD_CONTENT_READER_END_WITH_ERROR = -2;
+{$ENDIF}
+{$IFNDEF MHD_SOCKET_DEFINED}
+  {$IF NOT DEFINED(WIN32) OR DEFINED(_SYS_TYPES_FD_SET)}
+  MHD_POSIX_SOCKETS = 1;
+  MHD_INVALID_SOCKET = -1;
+  {$ELSE}
+  MHD_WINSOCK_SOCKETS = 1;
+  MHD_INVALID_SOCKET = INVALID_SOCKET;
+  {$ENDIF}
+  MHD_SOCKET_DEFINED = 1;
+{$ENDIF}
+  MHD_VERSION = $00094300;
+  MHD_YES = 1;
+  MHD_NO = 0;
+  MHD_INVALID_NONCE = -1;
+  MHD_ICY_FLAG = -2147483648;
+  MHD_UNSIGNED_LONG_LONG_PRINTF = '%llu';
+
+  // HTTP codes
+  MHD_HTTP_CONTINUE = 100;
+  MHD_HTTP_SWITCHING_PROTOCOLS = 101;
+  MHD_HTTP_PROCESSING = 102;
+  MHD_HTTP_OK = 200;
+  MHD_HTTP_CREATED = 201;
+  MHD_HTTP_ACCEPTED = 202;
+  MHD_HTTP_NON_AUTHORITATIVE_INFORMATION = 203;
+  MHD_HTTP_NO_CONTENT = 204;
+  MHD_HTTP_RESET_CONTENT = 205;
+  MHD_HTTP_PARTIAL_CONTENT = 206;
+  MHD_HTTP_MULTI_STATUS = 207;
+  MHD_HTTP_MULTIPLE_CHOICES = 300;
+  MHD_HTTP_MOVED_PERMANENTLY = 301;
+  MHD_HTTP_FOUND = 302;
+  MHD_HTTP_SEE_OTHER = 303;
+  MHD_HTTP_NOT_MODIFIED = 304;
+  MHD_HTTP_USE_PROXY = 305;
+  MHD_HTTP_SWITCH_PROXY = 306;
+  MHD_HTTP_TEMPORARY_REDIRECT = 307;
+  MHD_HTTP_BAD_REQUEST = 400;
+  MHD_HTTP_UNAUTHORIZED = 401;
+  MHD_HTTP_PAYMENT_REQUIRED = 402;
+  MHD_HTTP_FORBIDDEN = 403;
+  MHD_HTTP_NOT_FOUND = 404;
+  MHD_HTTP_METHOD_NOT_ALLOWED = 405;
+  MHD_HTTP_NOT_ACCEPTABLE = 406;
+  MHD_HTTP_PROXY_AUTHENTICATION_REQUIRED = 407;
+  MHD_HTTP_REQUEST_TIMEOUT = 408;
+  MHD_HTTP_CONFLICT = 409;
+  MHD_HTTP_GONE = 410;
+  MHD_HTTP_LENGTH_REQUIRED = 411;
+  MHD_HTTP_PRECONDITION_FAILED = 412;
+  MHD_HTTP_REQUEST_ENTITY_TOO_LARGE = 413;
+  MHD_HTTP_REQUEST_URI_TOO_LONG = 414;
+  MHD_HTTP_UNSUPPORTED_MEDIA_TYPE = 415;
+  MHD_HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
+  MHD_HTTP_EXPECTATION_FAILED = 417;
+  MHD_HTTP_UNPROCESSABLE_ENTITY = 422;
+  MHD_HTTP_LOCKED = 423;
+  MHD_HTTP_FAILED_DEPENDENCY = 424;
+  MHD_HTTP_UNORDERED_COLLECTION = 425;
+  MHD_HTTP_UPGRADE_REQUIRED = 426;
+  MHD_HTTP_NO_RESPONSE = 444;
+  MHD_HTTP_RETRY_WITH = 449;
+  MHD_HTTP_BLOCKED_BY_WINDOWS_PARENTAL_CONTROLS = 450;
+  MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451;
+  MHD_HTTP_INTERNAL_SERVER_ERROR = 500;
+  MHD_HTTP_NOT_IMPLEMENTED = 501;
+  MHD_HTTP_BAD_GATEWAY = 502;
+  MHD_HTTP_SERVICE_UNAVAILABLE = 503;
+  MHD_HTTP_GATEWAY_TIMEOUT = 504;
+  MHD_HTTP_HTTP_VERSION_NOT_SUPPORTED = 505;
+  MHD_HTTP_VARIANT_ALSO_NEGOTIATES = 506;
+  MHD_HTTP_INSUFFICIENT_STORAGE = 507;
+  MHD_HTTP_BANDWIDTH_LIMIT_EXCEEDED = 509;
+  MHD_HTTP_NOT_EXTENDED = 510;
+
+  // HTTP headers
+  MHD_HTTP_HEADER_ACCEPT = 'Accept';
+  MHD_HTTP_HEADER_ACCEPT_CHARSET = 'Accept-Charset';
+  MHD_HTTP_HEADER_ACCEPT_ENCODING = 'Accept-Encoding';
+  MHD_HTTP_HEADER_ACCEPT_LANGUAGE = 'Accept-Language';
+  MHD_HTTP_HEADER_ACCEPT_RANGES = 'Accept-Ranges';
+  MHD_HTTP_HEADER_AGE = 'Age';
+  MHD_HTTP_HEADER_ALLOW = 'Allow';
+  MHD_HTTP_HEADER_AUTHORIZATION = 'Authorization';
+  MHD_HTTP_HEADER_CACHE_CONTROL = 'Cache-Control';
+  MHD_HTTP_HEADER_CONNECTION = 'Connection';
+  MHD_HTTP_HEADER_CONTENT_ENCODING = 'Content-Encoding';
+  MHD_HTTP_HEADER_CONTENT_LANGUAGE = 'Content-Language';
+  MHD_HTTP_HEADER_CONTENT_LENGTH = 'Content-Length';
+  MHD_HTTP_HEADER_CONTENT_LOCATION = 'Content-Location';
+  MHD_HTTP_HEADER_CONTENT_MD5 = 'Content-MD5';
+  MHD_HTTP_HEADER_CONTENT_RANGE = 'Content-Range';
+  MHD_HTTP_HEADER_CONTENT_TYPE = 'Content-Type';
+  MHD_HTTP_HEADER_COOKIE = 'Cookie';
+  MHD_HTTP_HEADER_DATE = 'Date';
+  MHD_HTTP_HEADER_ETAG = 'ETag';
+  MHD_HTTP_HEADER_EXPECT = 'Expect';
+  MHD_HTTP_HEADER_EXPIRES = 'Expires';
+  MHD_HTTP_HEADER_FROM = 'From';
+  MHD_HTTP_HEADER_HOST = 'Host';
+  MHD_HTTP_HEADER_IF_MATCH = 'If-Match';
+  MHD_HTTP_HEADER_IF_MODIFIED_SINCE = 'If-Modified-Since';
+  MHD_HTTP_HEADER_IF_NONE_MATCH = 'If-None-Match';
+  MHD_HTTP_HEADER_IF_RANGE = 'If-Range';
+  MHD_HTTP_HEADER_IF_UNMODIFIED_SINCE = 'If-Unmodified-Since';
+  MHD_HTTP_HEADER_LAST_MODIFIED = 'Last-Modified';
+  MHD_HTTP_HEADER_LOCATION = 'Location';
+  MHD_HTTP_HEADER_MAX_FORWARDS = 'Max-Forwards';
+  MHD_HTTP_HEADER_PRAGMA = 'Pragma';
+  MHD_HTTP_HEADER_PROXY_AUTHENTICATE = 'Proxy-Authenticate';
+  MHD_HTTP_HEADER_PROXY_AUTHORIZATION = 'Proxy-Authorization';
+  MHD_HTTP_HEADER_RANGE = 'Range';
+  MHD_HTTP_HEADER_REFERER = 'Referer';
+  MHD_HTTP_HEADER_RETRY_AFTER = 'Retry-After';
+  MHD_HTTP_HEADER_SERVER = 'Server';
+  MHD_HTTP_HEADER_SET_COOKIE = 'Set-Cookie';
+  MHD_HTTP_HEADER_SET_COOKIE2 = 'Set-Cookie2';
+  MHD_HTTP_HEADER_TE = 'TE';
+  MHD_HTTP_HEADER_TRAILER = 'Trailer';
+  MHD_HTTP_HEADER_TRANSFER_ENCODING = 'Transfer-Encoding';
+  MHD_HTTP_HEADER_UPGRADE = 'Upgrade';
+  MHD_HTTP_HEADER_USER_AGENT = 'User-Agent';
+  MHD_HTTP_HEADER_VARY = 'Vary';
+  MHD_HTTP_HEADER_VIA = 'Via';
+  MHD_HTTP_HEADER_WARNING = 'Warning';
+  MHD_HTTP_HEADER_WWW_AUTHENTICATE = 'WWW-Authenticate';
+  MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN = 'Access-Control-Allow-Origin';
+  MHD_HTTP_HEADER_CONTENT_DISPOSITION = 'Content-Disposition';
+  MHD_HTTP_VERSION_1_0 = 'HTTP/1.0';
+  MHD_HTTP_VERSION_1_1 = 'HTTP/1.1';
+  MHD_HTTP_METHOD_CONNECT = 'CONNECT';
+  MHD_HTTP_METHOD_DELETE = 'DELETE';
+  MHD_HTTP_METHOD_GET = 'GET';
+  MHD_HTTP_METHOD_HEAD = 'HEAD';
+  MHD_HTTP_METHOD_OPTIONS = 'OPTIONS';
+  MHD_HTTP_METHOD_POST = 'POST';
+  MHD_HTTP_METHOD_PUT = 'PUT';
+  MHD_HTTP_METHOD_PATCH = 'PATCH';
+  MHD_HTTP_METHOD_TRACE = 'TRACE';
+  MHD_HTTP_POST_ENCODING_FORM_URLENCODED = 'application/x-www-form-urlencoded';
+  MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA = 'multipart/form-data';
+
+  // MHD_ValueKind enum items
+  MHD_RESPONSE_HEADER_KIND = 0;
+  MHD_HEADER_KIND = 1;
+  MHD_COOKIE_KIND = 2;
+  MHD_POSTDATA_KIND = 4;
+  MHD_GET_ARGUMENT_KIND = 8;
+  MHD_FOOTER_KIND = 16;
+
+  // MHD_FLAG enum items
+  MHD_NO_FLAG = 0;
+  MHD_USE_DEBUG = 1;
+  MHD_USE_SSL = 2;
+  MHD_USE_THREAD_PER_CONNECTION = 4;
+  MHD_USE_SELECT_INTERNALLY = 8;
+  MHD_USE_IPv6 = 16;
+  MHD_USE_PEDANTIC_CHECKS = 32;
+  MHD_USE_POLL = 64;
+  MHD_USE_POLL_INTERNALLY = MHD_USE_SELECT_INTERNALLY or MHD_USE_POLL;
+  MHD_SUPPRESS_DATE_NO_CLOCK = 128;
+  MHD_USE_NO_LISTEN_SOCKET = 256;
+  MHD_USE_EPOLL_LINUX_ONLY = 512;
+  MHD_USE_EPOLL_INTERNALLY_LINUX_ONLY = MHD_USE_SELECT_INTERNALLY or MHD_USE_EPOLL_LINUX_ONLY;
+  MHD_USE_PIPE_FOR_SHUTDOWN = 1024;
+  MHD_USE_DUAL_STACK = MHD_USE_IPv6 or 2048;
+  MHD_USE_EPOLL_TURBO = 4096;
+  MHD_USE_SUSPEND_RESUME = 8192 or MHD_USE_PIPE_FOR_SHUTDOWN;
+  MHD_USE_TCP_FASTOPEN = 16384;
+
+  // MHD_OPTION enum items
+  MHD_OPTION_END = 0;
+  MHD_OPTION_CONNECTION_MEMORY_LIMIT = 1;
+  MHD_OPTION_CONNECTION_LIMIT = 2;
+  MHD_OPTION_CONNECTION_TIMEOUT = 3;
+  MHD_OPTION_NOTIFY_COMPLETED = 4;
+  MHD_OPTION_PER_IP_CONNECTION_LIMIT = 5;
+  MHD_OPTION_SOCK_ADDR = 6;
+  MHD_OPTION_URI_LOG_CALLBACK = 7;
+  MHD_OPTION_HTTPS_MEM_KEY = 8;
+  MHD_OPTION_HTTPS_MEM_CERT = 9;
+  MHD_OPTION_HTTPS_CRED_TYPE = 10;
+  MHD_OPTION_HTTPS_PRIORITIES = 11;
+  MHD_OPTION_LISTEN_SOCKET = 12;
+  MHD_OPTION_EXTERNAL_LOGGER = 13;
+  MHD_OPTION_THREAD_POOL_SIZE = 14;
+  MHD_OPTION_ARRAY = 15;
+  MHD_OPTION_UNESCAPE_CALLBACK = 16;
+  MHD_OPTION_DIGEST_AUTH_RANDOM = 17;
+  MHD_OPTION_NONCE_NC_SIZE = 18;
+  MHD_OPTION_THREAD_STACK_SIZE = 19;
+  MHD_OPTION_HTTPS_MEM_TRUST = 20;
+  MHD_OPTION_CONNECTION_MEMORY_INCREMENT = 21;
+  MHD_OPTION_HTTPS_CERT_CALLBACK = 22;
+  MHD_OPTION_TCP_FASTOPEN_QUEUE_SIZE = 23;
+  MHD_OPTION_HTTPS_MEM_DHPARAMS = 24;
+  MHD_OPTION_LISTENING_ADDRESS_REUSE = 25;
+  MHD_OPTION_HTTPS_KEY_PASSWORD = 26;
+  MHD_OPTION_NOTIFY_CONNECTION = 27;
+
+  // MHD_RequestTerminationCode enum items
+  MHD_REQUEST_TERMINATED_COMPLETED_OK = 0;
+  MHD_REQUEST_TERMINATED_WITH_ERROR = 1;
+  MHD_REQUEST_TERMINATED_TIMEOUT_REACHED = 2;
+  MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN = 3;
+  MHD_REQUEST_TERMINATED_READ_ERROR = 4;
+  MHD_REQUEST_TERMINATED_CLIENT_ABORT = 5;
+
+  // MHD_ConnectionNotificationCode enum items
+  MHD_CONNECTION_NOTIFY_STARTED = 0;
+  MHD_CONNECTION_NOTIFY_CLOSED = 1;
+
+  // MHD_ConnectionInfoType enum items
+  MHD_CONNECTION_INFO_CIPHER_ALGO = 0;
+  MHD_CONNECTION_INFO_PROTOCOL = 1;
+  MHD_CONNECTION_INFO_CLIENT_ADDRESS = 2;
+  MHD_CONNECTION_INFO_GNUTLS_SESSION = 3;
+  MHD_CONNECTION_INFO_GNUTLS_CLIENT_CERT = 4;
+  MHD_CONNECTION_INFO_DAEMON = 5;
+  MHD_CONNECTION_INFO_CONNECTION_FD = 6;
+  MHD_CONNECTION_INFO_SOCKET_CONTEXT = 7;
+
+  // MHD_DaemonInfoType enum items
+  MHD_DAEMON_INFO_KEY_SIZE = 0;
+  MHD_DAEMON_INFO_MAC_KEY_SIZE = 1;
+  MHD_DAEMON_INFO_LISTEN_FD = 2;
+  MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY = 3;
+  MHD_DAEMON_INFO_CURRENT_CONNECTIONS = 4;
+
+  // MHD_ResponseFlags enum items
+  MHD_RF_NONE = 0;
+  MHD_RF_HTTP_VERSION_1_0_ONLY = 1;
+
+  // MHD_ResponseOptions enum items
+  MHD_RO_END = 0;
+
+  // MHD_ResponseMemoryMode enum items
+  MHD_RESPMEM_PERSISTENT = 0;
+  MHD_RESPMEM_MUST_FREE = 1;
+  MHD_RESPMEM_MUST_COPY = 2;
+
+  // MHD_CONNECTION_OPTION enum items
+  MHD_CONNECTION_OPTION_TIMEOUT = 0;
+
+  // MHD_FEATURE enum items
+  MHD_FEATURE_MESSGES = 1;
+  MHD_FEATURE_SSL = 2;
+  MHD_FEATURE_HTTPS_CERT_CALLBACK = 3;
+  MHD_FEATURE_IPv6 = 4;
+  MHD_FEATURE_IPv6_ONLY = 5;
+  MHD_FEATURE_POLL = 6;
+  MHD_FEATURE_EPOLL = 7;
+  MHD_FEATURE_SHUTDOWN_LISTEN_SOCKET = 8;
+  MHD_FEATURE_SOCKETPAIR = 9;
+  MHD_FEATURE_TCP_FASTOPEN = 10;
+  MHD_FEATURE_BASIC_AUTH = 11;
+  MHD_FEATURE_DIGEST_AUTH = 12;
+  MHD_FEATURE_POSTPROCESSOR = 13;
+  MHD_FEATURE_HTTPS_KEY_PASSWORD = 14;
+  MHD_FEATURE_LARGE_FILE = 15;
+
+type
+  Pcchar = PAnsiChar;
+  Ppcchar = ^Pcchar;
+  va_list = Pointer;
+{$IFDEF FPC}
+  cint = CTypes.cint;
+  cuint = CTypes.cuint;
+  cuint16 = CTypes.cuint16;
+  cuint64 = CTypes.cuint64;
+  culonglong = CTypes.culonglong;
+  socklen_t = {$IFDEF UNIX}BaseUnix.socklen_t{$ELSE}LongInt{$ENDIF};
+  size_t = {$IFDEF UNIX}BaseUnix{$ELSE}Sockets{$ENDIF}.size_t;
+  Psize_t = {$IFDEF UNIX}BaseUnix.pSize_t{$ELSE}^Sockets.size_t{$ENDIF};
+  Pfd_set = {$IFDEF UNIX}BaseUnix.pFDSet{$ELSE}WinSock2.PFDSet{$ENDIF};
+  ssize_t = {$IFDEF UNIX}BaseUnix{$ELSE}Sockets{$ENDIF}.ssize_t;
+  psockaddr = Sockets.psockaddr;
+{$ELSE}
+  cint = LongInt;
+  cuint = LongWord;
+  cuint16 = Word;
+  cuint64 = UInt64;
+  culonglong = UInt64;
+  socklen_t = LongInt;
+  size_t = WinTypes.SIZE_T;
+  Psize_t = WinTypes.PSIZE_T;
+  Pfd_set = WinSock2.PFdSet;
+  ssize_t = WinTypes.SSIZE_T;
+  psockaddr = WinSock2.PSockAddr;
+{$ENDIF}
+{$IFNDEF MHD_SOCKET_DEFINED}
+  PMHD_socket = ^MHD_socket;
+  {$IF NOT DEFINED(WIN32) OR DEFINED(_SYS_TYPES_FD_SET)}
+  MHD_socket = cint;
+  {$ELSE}
+  MHD_socket = TSocket;
+  {$ENDIF}
+{$ENDIF}
+  MHD_UNSIGNED_LONG_LONG = culonglong;
+  PMHD_UNSIGNED_LONG_LONG = ^MHD_UNSIGNED_LONG_LONG;
+
+  // enums
+  MHD_ValueKind = LongInt;
+
+  MHD_FLAG = LongInt;
+
+  MHD_OPTION = LongInt;
+
+  MHD_RequestTerminationCode = LongInt;
+
+  MHD_ConnectionNotificationCode = LongInt;
+
+  MHD_ConnectionInfoType = LongInt;
+
+  MHD_DaemonInfoType = LongInt;
+
+  MHD_ResponseFlags = LongInt;
+
+  MHD_ResponseOptions = LongInt;
+
+  MHD_ResponseMemoryMode =  LongInt;
+
+  MHD_CONNECTION_OPTION = LongInt;
+
+  MHD_FEATURE =  LongInt;
+
+  MHD_Daemon = record
+  end;
+  PMHD_Daemon = ^MHD_Daemon;
+
+  MHD_Connection = record
+  end;
+  PMHD_Connection = ^MHD_Connection;
+
+  MHD_Response = record
+  end;
+  PMHD_Response = ^MHD_Response;
+
+  MHD_PostProcessor = record
+  end;
+  PMHD_PostProcessor = ^MHD_PostProcessor;
+
+  MHD_OptionItem = record
+    option: MHD_OPTION;
+    value: ssize_t;
+    ptr_value: Pointer;
+  end;
+  PMHD_OptionItem = ^MHD_OptionItem;
+
+  MHD_ConnectionInfo = record
+  case LongInt of
+    0: (cipher_algorithm: cint);
+    1: (protocol: cint);
+    2: (connect_fd: MHD_socket);
+    3: (tls_session: Pointer);
+    4: (client_cert: Pointer);
+    5: (client_addr: psockaddr);
+    6: (daemon: PMHD_Daemon);
+    7: (socket_context: ^Pointer);
+  end;
+  PMHD_ConnectionInfo = ^MHD_ConnectionInfo;
+
+  MHD_DaemonInfo = record
+  case LongInt of
+    0: (key_size: size_t);
+    1: (mac_key_size: size_t);
+    2: (listen_fd: MHD_socket);
+    3: (num_connections: cuint);
+  end;
+  PMHD_DaemonInfo = ^MHD_DaemonInfo;
+
+  MHD_LogCallback = procedure(cls: Pointer; fm: Pcchar; ap: va_list); cdecl;
+  MHD_PanicCallback = procedure(cls: Pointer; &file: Pcchar; line: cuint; reason: Pcchar); cdecl;
+  MHD_AcceptPolicyCallback = function(cls: Pointer; addr: psockaddr; addrlen: socklen_t): cint; cdecl;
+  MHD_AccessHandlerCallback = function(cls: Pointer; connection: PMHD_Connection; url: Pcchar; method: Pcchar; version: Pcchar; upload_data: Pcchar; upload_data_size: pSize_t; con_cls: PPointer): cint; cdecl;
+  MHD_RequestCompletedCallback = procedure(cls: Pointer; connection: PMHD_Connection; con_cls: PPointer; toe: MHD_RequestTerminationCode); cdecl;
+  MHD_NotifyConnectionCallback = procedure(cls: Pointer; connection: PMHD_Connection; socket_context: PPointer; toe: MHD_ConnectionNotificationCode); cdecl;
+  MHD_KeyValueIterator = function(cls: Pointer; kind: MHD_ValueKind; key: Pcchar; value: Pcchar): cint; cdecl;
+  MHD_ContentReaderCallback = function(cls: pointer; pos: cuint64; buf: Pcchar; max: size_t): ssize_t; cdecl;
+  MHD_ContentReaderFreeCallback = procedure(cls: Pointer); cdecl;
+  MHD_PostDataIterator = function(cls: Pointer; kind: MHD_ValueKind; key: Pcchar; filename: Pcchar; content_type: Pcchar; transfer_encoding: Pcchar; data: Pcchar; off: cuint64; size: size_t): cint; cdecl;
+
+  function MHD_get_reason_phrase_for(code: cuint): Pcchar; cdecl; external MHD_LIB_NAME name 'MHD_get_reason_phrase_for';
+  function MHD_start_daemon_va(flags: cuint; port: cuint16; apc: MHD_AcceptPolicyCallback; apc_cls: Pointer; dh: MHD_AccessHandlerCallback; dh_cls: Pointer; ap: va_list): PMHD_Daemon; cdecl; external MHD_LIB_NAME name 'MHD_start_daemon_va';
+  function MHD_start_daemon(flags: cuint; port: cuint16; apc: MHD_AcceptPolicyCallback; apc_cls: Pointer; dh: MHD_AccessHandlerCallback; dh_cls: Pointer): PMHD_Daemon; cdecl; varargs; external MHD_LIB_NAME name 'MHD_start_daemon';
+  function MHD_quiesce_daemon(daemon: PMHD_Daemon): MHD_socket; cdecl; external MHD_LIB_NAME name 'MHD_quiesce_daemon';
+  procedure MHD_stop_daemon(daemon: PMHD_Daemon); cdecl; external MHD_LIB_NAME name 'MHD_stop_daemon';
+  function MHD_add_connection(daemon: PMHD_Daemon; client_socket: MHD_socket; addr: psockaddr; addrlen: socklen_t): cint; cdecl; external MHD_LIB_NAME name 'MHD_add_connection';
+  function MHD_get_fdset(daemon: PMHD_Daemon; read_fd_set: Pfd_set; write_fd_set: Pfd_set; except_fd_set: Pfd_set; max_fd: PMHD_socket): cint; cdecl; external MHD_LIB_NAME name 'MHD_get_fdset';
+  function MHD_get_fdset2(daemon: PMHD_Daemon; read_fd_set: Pfd_set; write_fd_set: Pfd_set; except_fd_set: Pfd_set; max_fd: PMHD_socket; fd_setsize: cuint): cint; cdecl; external MHD_LIB_NAME name 'MHD_get_fdset2';
+  function MHD_get_timeout(daemon: PMHD_Daemon; timeout: PMHD_UNSIGNED_LONG_LONG): cint; cdecl; external MHD_LIB_NAME name 'MHD_get_timeout';
+  function MHD_run(daemon: PMHD_Daemon): cint; cdecl; external MHD_LIB_NAME name 'MHD_run';
+  function MHD_run_from_select(daemon: PMHD_Daemon; read_fd_set: Pfd_set; write_fd_set: Pfd_set; except_fd_set: Pfd_set): cint; cdecl; external MHD_LIB_NAME name 'MHD_run_from_select';
+  function MHD_get_connection_values(connection: PMHD_Connection; kind: MHD_ValueKind; iterator: MHD_KeyValueIterator; iterator_cls: pointer): cint; cdecl; external MHD_LIB_NAME name 'MHD_get_connection_values';
+  function MHD_set_connection_value(connection: PMHD_Connection; kind: MHD_ValueKind; key: Pcchar; value: Pcchar): cint; cdecl; external MHD_LIB_NAME name 'MHD_set_connection_value';
+  procedure MHD_set_panic_func(cb: MHD_PanicCallback; cls: Pointer); cdecl; external MHD_LIB_NAME name 'MHD_set_panic_func';
+  function MHD_http_unescape(val: Pcchar): size_t; cdecl; external MHD_LIB_NAME name 'MHD_http_unescape';
+  function MHD_lookup_connection_value(connection: PMHD_Connection; kind: MHD_ValueKind; key: Pcchar): Pcchar; cdecl; external MHD_LIB_NAME name 'MHD_lookup_connection_value';
+  function MHD_queue_response(connection: PMHD_Connection; status_code: cuint; response: PMHD_Response): cint; cdecl; external MHD_LIB_NAME name 'MHD_queue_response';
+  procedure MHD_suspend_connection(connection: PMHD_Connection); cdecl; external MHD_LIB_NAME name 'MHD_suspend_connection';
+  procedure MHD_resume_connection(connection: PMHD_Connection); cdecl; external MHD_LIB_NAME name 'MHD_resume_connection';
+  function MHD_set_response_options(response: PMHD_Response; flags: MHD_ResponseFlags): cint; cdecl; varargs; external MHD_LIB_NAME name 'MHD_set_response_options';
+  function MHD_create_response_from_callback(size: cuint64; block_size: size_t; crc: MHD_ContentReaderCallback; crc_cls: pointer; crfc: MHD_ContentReaderFreeCallback): PMHD_Response; cdecl; external MHD_LIB_NAME name 'MHD_create_response_from_callback';
+  function MHD_create_response_from_buffer(size: size_t; buffer: Pointer; mode: MHD_ResponseMemoryMode): PMHD_Response; cdecl; external MHD_LIB_NAME name 'MHD_create_response_from_buffer';
+  function MHD_create_response_from_fd(size: size_t; fd: cint): PMHD_Response; cdecl; external MHD_LIB_NAME name 'MHD_create_response_from_fd';
+  function MHD_create_response_from_fd64(size: cuint64; fd: cint): PMHD_Response; cdecl; external MHD_LIB_NAME name 'MHD_create_response_from_fd64';
+  function MHD_create_response_from_fd_at_offset64(size: cuint64; fd: cint; offset: cuint64): PMHD_Response;cdecl;external MHD_LIB_NAME name 'MHD_create_response_from_fd_at_offset64';
+  procedure MHD_destroy_response(response: PMHD_Response); cdecl; external MHD_LIB_NAME name 'MHD_destroy_response';
+  function MHD_add_response_header(response: PMHD_Response; header: Pcchar; content: Pcchar): cint; cdecl; external MHD_LIB_NAME name 'MHD_add_response_header';
+  function MHD_add_response_footer(response: PMHD_Response; footer: Pcchar; content: Pcchar): cint; cdecl; external MHD_LIB_NAME name 'MHD_add_response_footer';
+  function MHD_del_response_header(response: PMHD_Response; header: Pcchar; content: Pcchar): cint; cdecl; external MHD_LIB_NAME name 'MHD_del_response_header';
+  function MHD_get_response_headers(response: PMHD_Response; iterator: MHD_KeyValueIterator; iterator_cls: Pointer): cint; cdecl; external MHD_LIB_NAME name 'MHD_get_response_headers';
+  function MHD_get_response_header(response: PMHD_Response; key: Pcchar): Pcchar; cdecl; external MHD_LIB_NAME name 'MHD_get_response_header';
+  function MHD_create_post_processor(connection: PMHD_Connection; buffer_size: size_t; iter: MHD_PostDataIterator; iter_cls: pointer): PMHD_PostProcessor; cdecl; external MHD_LIB_NAME name 'MHD_create_post_processor';
+  function MHD_post_process(pp: PMHD_PostProcessor; post_data: Pcchar; post_data_len: size_t): cint; cdecl; external MHD_LIB_NAME name 'MHD_post_process';
+  function MHD_destroy_post_processor(pp: PMHD_PostProcessor): cint; cdecl; external MHD_LIB_NAME name 'MHD_destroy_post_processor';
+  function MHD_digest_auth_get_username(connection: PMHD_Connection): Pcchar; cdecl; external MHD_LIB_NAME name 'MHD_digest_auth_get_username';
+  function MHD_digest_auth_check(connection: PMHD_Connection; realm: Pcchar; username: Pcchar; password: Pcchar; nonce_timeout: cuint): cint; cdecl; external MHD_LIB_NAME name 'MHD_digest_auth_check';
+  function MHD_queue_auth_fail_response(connection: PMHD_Connection; realm: Pcchar; opaque: Pcchar; response: PMHD_Response; signal_stale: cint): cint; cdecl; external MHD_LIB_NAME name 'MHD_queue_auth_fail_response';
+  function MHD_basic_auth_get_username_password(connection: PMHD_Connection; password: PPcchar): Pcchar; cdecl; external MHD_LIB_NAME name 'MHD_basic_auth_get_username_password';
+  function MHD_queue_basic_auth_fail_response(connection: PMHD_Connection; realm: Pcchar; response: PMHD_Response): cint; cdecl; external MHD_LIB_NAME name 'MHD_queue_basic_auth_fail_response';
+  function MHD_get_connection_info(connection: PMHD_Connection; info_type: MHD_ConnectionInfoType): PMHD_ConnectionInfo; cdecl; varargs; external MHD_LIB_NAME name 'MHD_get_connection_info';
+  function MHD_set_connection_option(connection: PMHD_Connection; option: MHD_CONNECTION_OPTION): cint; cdecl; varargs; external MHD_LIB_NAME name 'MHD_set_connection_option';
+  function MHD_get_daemon_info(daemon: PMHD_Daemon; info_type: MHD_DaemonInfoType): PMHD_DaemonInfo; cdecl; varargs; external MHD_LIB_NAME name 'MHD_get_daemon_info';
+  function MHD_get_version: Pcchar; cdecl; external MHD_LIB_NAME name 'MHD_get_version';
+  function MHD_is_feature_supported(feature: MHD_FEATURE): cint; cdecl; external MHD_LIB_NAME name 'MHD_is_feature_supported';
+
+implementation
+
+end.