summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormarco <marco@3ad0048d-3df7-0310-abae-a5850022a9f2>2016-05-25 19:56:31 +0000
committermarco <marco@3ad0048d-3df7-0310-abae-a5850022a9f2>2016-05-25 19:56:31 +0000
commit24f58bedad8a59d94912ab64df5212d289c352ee (patch)
treeef44a3026a3f0cf5564bff822c77f8f9049fff01
parentbd3edbb5a969eead8f1d54e8095140c6f58615b8 (diff)
downloadfpc-24f58bedad8a59d94912ab64df5212d289c352ee.tar.gz
# revisions: 32067
git-svn-id: http://svn.freepascal.org/svn/fpc/branches/fixes_3_0@33795 3ad0048d-3df7-0310-abae-a5850022a9f2
-rw-r--r--packages/fpmake_add.inc1
-rw-r--r--packages/fpmake_proc.inc5
-rw-r--r--packages/libmicrohttpd/Makefile1873
-rw-r--r--packages/libmicrohttpd/Makefile.fpc102
-rw-r--r--packages/libmicrohttpd/examples/basicauthentication.pp70
-rw-r--r--packages/libmicrohttpd/examples/benchmark.pp131
-rw-r--r--packages/libmicrohttpd/examples/benchmark_https.pp182
-rw-r--r--packages/libmicrohttpd/examples/chunked_example.pp81
-rw-r--r--packages/libmicrohttpd/examples/cutils.pas225
-rw-r--r--packages/libmicrohttpd/examples/demo.pp811
-rw-r--r--packages/libmicrohttpd/examples/demo_https.pp865
-rw-r--r--packages/libmicrohttpd/examples/digest_auth_example.pp127
-rw-r--r--packages/libmicrohttpd/examples/dual_stack_example.pp78
-rw-r--r--packages/libmicrohttpd/examples/fileserver_example.pp115
-rw-r--r--packages/libmicrohttpd/examples/fileserver_example_dirs.pp167
-rw-r--r--packages/libmicrohttpd/examples/fileserver_example_external_select.pp146
-rw-r--r--packages/libmicrohttpd/examples/hellobrowser.pp42
-rw-r--r--packages/libmicrohttpd/examples/https_fileserver_example.pp194
-rw-r--r--packages/libmicrohttpd/examples/largepost.pp187
-rw-r--r--packages/libmicrohttpd/examples/logging.pp43
-rw-r--r--packages/libmicrohttpd/examples/magic.inc15
-rw-r--r--packages/libmicrohttpd/examples/minimal_example.pp82
-rw-r--r--packages/libmicrohttpd/examples/minimal_example_comet.pp81
-rw-r--r--packages/libmicrohttpd/examples/post_example.pp640
-rw-r--r--packages/libmicrohttpd/examples/querystring_example.pp89
-rw-r--r--packages/libmicrohttpd/examples/refuse_post_example.pp94
-rw-r--r--packages/libmicrohttpd/examples/responseheaders.pp66
-rw-r--r--packages/libmicrohttpd/examples/sessions.pp623
-rw-r--r--packages/libmicrohttpd/examples/simplepost.pp155
-rw-r--r--packages/libmicrohttpd/examples/tlsauthentication.pp234
-rw-r--r--packages/libmicrohttpd/fpmake.pp59
-rw-r--r--packages/libmicrohttpd/src/libmicrohttpd.pp485
32 files changed, 8068 insertions, 0 deletions
diff --git a/packages/fpmake_add.inc b/packages/fpmake_add.inc
index 8e3260357f..e8c6406207 100644
--- a/packages/fpmake_add.inc
+++ b/packages/fpmake_add.inc
@@ -60,6 +60,7 @@
add_ldap(ADirectory+IncludeTrailingPathDelimiter('ldap'));
add_libc(ADirectory+IncludeTrailingPathDelimiter('libc'));
add_libcurl(ADirectory+IncludeTrailingPathDelimiter('libcurl'));
+ add_libmicrohttpd(ADirectory+IncludeTrailingPathDelimiter('libmicrohttpd'));
add_libgbafpc(ADirectory+IncludeTrailingPathDelimiter('libgbafpc'));
add_libgd(ADirectory+IncludeTrailingPathDelimiter('libgd'));
add_libndsfpc(ADirectory+IncludeTrailingPathDelimiter('libndsfpc'));
diff --git a/packages/fpmake_proc.inc b/packages/fpmake_proc.inc
index 89a699e142..88f34aff2b 100644
--- a/packages/fpmake_proc.inc
+++ b/packages/fpmake_proc.inc
@@ -403,6 +403,11 @@ begin
with Installer do
{$include libvlc/fpmake.pp}
end;
+procedure add_libmicrohttpd(const ADirectory: string);
+begin
+ with Installer do
+{$include libmicrohttpd/fpmake.pp}
+end;
procedure add_libxml(const ADirectory: string);
begin
diff --git a/packages/libmicrohttpd/Makefile b/packages/libmicrohttpd/Makefile
new file mode 100644
index 0000000000..19f55dc6b0
--- /dev/null
+++ b/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
diff --git a/packages/libmicrohttpd/Makefile.fpc b/packages/libmicrohttpd/Makefile.fpc
new file mode 100644
index 0000000000..bd1f51ae09
--- /dev/null
+++ b/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
diff --git a/packages/libmicrohttpd/examples/basicauthentication.pp b/packages/libmicrohttpd/examples/basicauthentication.pp
new file mode 100644
index 0000000000..2ab0b7446f
--- /dev/null
+++ b/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.
diff --git a/packages/libmicrohttpd/examples/benchmark.pp b/packages/libmicrohttpd/examples/benchmark.pp
new file mode 100644
index 0000000000..1cbe6e8928
--- /dev/null
+++ b/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.
+
diff --git a/packages/libmicrohttpd/examples/benchmark_https.pp b/packages/libmicrohttpd/examples/benchmark_https.pp
new file mode 100644
index 0000000000..32496255c0
--- /dev/null
+++ b/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.
+
diff --git a/packages/libmicrohttpd/examples/chunked_example.pp b/packages/libmicrohttpd/examples/chunked_example.pp
new file mode 100644
index 0000000000..338c5272f1
--- /dev/null
+++ b/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.
+
diff --git a/packages/libmicrohttpd/examples/cutils.pas b/packages/libmicrohttpd/examples/cutils.pas
new file mode 100644
index 0000000000..ab80880afc
--- /dev/null
+++ b/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.
diff --git a/packages/libmicrohttpd/examples/demo.pp b/packages/libmicrohttpd/examples/demo.pp
new file mode 100644
index 0000000000..f327473297
--- /dev/null
+++ b/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.
+
diff --git a/packages/libmicrohttpd/examples/demo_https.pp b/packages/libmicrohttpd/examples/demo_https.pp
new file mode 100644
index 0000000000..c4fd089903
--- /dev/null
+++ b/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.
+
diff --git a/packages/libmicrohttpd/examples/digest_auth_example.pp b/packages/libmicrohttpd/examples/digest_auth_example.pp
new file mode 100644
index 0000000000..cb92d36852
--- /dev/null
+++ b/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 = 'test@example.com';
+ 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.
+
diff --git a/packages/libmicrohttpd/examples/dual_stack_example.pp b/packages/libmicrohttpd/examples/dual_stack_example.pp
new file mode 100644
index 0000000000..a55635c6e0
--- /dev/null
+++ b/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.
+
diff --git a/packages/libmicrohttpd/examples/fileserver_example.pp b/packages/libmicrohttpd/examples/fileserver_example.pp
new file mode 100644
index 0000000000..b4a08f8cf1
--- /dev/null
+++ b/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.
+
diff --git a/packages/libmicrohttpd/examples/fileserver_example_dirs.pp b/packages/libmicrohttpd/examples/fileserver_example_dirs.pp
new file mode 100644
index 0000000000..bc06b38c22
--- /dev/null
+++ b/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.
+
diff --git a/packages/libmicrohttpd/examples/fileserver_example_external_select.pp b/packages/libmicrohttpd/examples/fileserver_example_external_select.pp
new file mode 100644
index 0000000000..e19ce9f80b
--- /dev/null
+++ b/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.
+
diff --git a/packages/libmicrohttpd/examples/hellobrowser.pp b/packages/libmicrohttpd/examples/hellobrowser.pp
new file mode 100644
index 0000000000..fa7d05cc54
--- /dev/null
+++ b/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.
+
diff --git a/packages/libmicrohttpd/examples/https_fileserver_example.pp b/packages/libmicrohttpd/examples/https_fileserver_example.pp
new file mode 100644
index 0000000000..502428ae74
--- /dev/null
+++ b/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.
+
diff --git a/packages/libmicrohttpd/examples/largepost.pp b/packages/libmicrohttpd/examples/largepost.pp
new file mode 100644
index 0000000000..6293899ed5
--- /dev/null
+++ b/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.
+
diff --git a/packages/libmicrohttpd/examples/logging.pp b/packages/libmicrohttpd/examples/logging.pp
new file mode 100644
index 0000000000..cb8e47a838
--- /dev/null
+++ b/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.
+
diff --git a/packages/libmicrohttpd/examples/magic.inc b/packages/libmicrohttpd/examples/magic.inc
new file mode 100644
index 0000000000..b4a5f4e9f1
--- /dev/null
+++ b/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';
diff --git a/packages/libmicrohttpd/examples/minimal_example.pp b/packages/libmicrohttpd/examples/minimal_example.pp
new file mode 100644
index 0000000000..ec78f0ab77
--- /dev/null
+++ b/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.
+
diff --git a/packages/libmicrohttpd/examples/minimal_example_comet.pp b/packages/libmicrohttpd/examples/minimal_example_comet.pp
new file mode 100644
index 0000000000..292ca09a02
--- /dev/null
+++ b/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.
+
diff --git a/packages/libmicrohttpd/examples/post_example.pp b/packages/libmicrohttpd/examples/post_example.pp
new file mode 100644
index 0000000000..1bb88b6e61
--- /dev/null
+++ b/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.
diff --git a/packages/libmicrohttpd/examples/querystring_example.pp b/packages/libmicrohttpd/examples/querystring_example.pp
new file mode 100644
index 0000000000..e95f4e96d9
--- /dev/null
+++ b/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.
+
diff --git a/packages/libmicrohttpd/examples/refuse_post_example.pp b/packages/libmicrohttpd/examples/refuse_post_example.pp
new file mode 100644
index 0000000000..1bad4f6f64
--- /dev/null
+++ b/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.
+
diff --git a/packages/libmicrohttpd/examples/responseheaders.pp b/packages/libmicrohttpd/examples/responseheaders.pp
new file mode 100644
index 0000000000..e7fc0ca566
--- /dev/null
+++ b/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.
diff --git a/packages/libmicrohttpd/examples/sessions.pp b/packages/libmicrohttpd/examples/sessions.pp
new file mode 100644
index 0000000000..0539b6703b
--- /dev/null
+++ b/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.
diff --git a/packages/libmicrohttpd/examples/simplepost.pp b/packages/libmicrohttpd/examples/simplepost.pp
new file mode 100644
index 0000000000..5693283e3e
--- /dev/null
+++ b/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.
diff --git a/packages/libmicrohttpd/examples/tlsauthentication.pp b/packages/libmicrohttpd/examples/tlsauthentication.pp
new file mode 100644
index 0000000000..8ecd0c133a
--- /dev/null
+++ b/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.
+
diff --git a/packages/libmicrohttpd/fpmake.pp b/packages/libmicrohttpd/fpmake.pp
new file mode 100644
index 0000000000..8d13e0bd9e
--- /dev/null
+++ b/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}
diff --git a/packages/libmicrohttpd/src/libmicrohttpd.pp b/packages/libmicrohttpd/src/libmicrohttpd.pp
new file mode 100644
index 0000000000..eb9e95de34
--- /dev/null
+++ b/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.