pax_global_header 0000666 0000000 0000000 00000000064 14154204040 0014504 g ustar 00root root 0000000 0000000 52 comment=a57875390601b0b986046af96013ad83ae02ebf7
ulfius-2.7.7/ 0000775 0000000 0000000 00000000000 14154204040 0013030 5 ustar 00root root 0000000 0000000 ulfius-2.7.7/.github/ 0000775 0000000 0000000 00000000000 14154204040 0014370 5 ustar 00root root 0000000 0000000 ulfius-2.7.7/.github/ISSUE_TEMPLATE/ 0000775 0000000 0000000 00000000000 14154204040 0016553 5 ustar 00root root 0000000 0000000 ulfius-2.7.7/.github/ISSUE_TEMPLATE/ulfius-bug-report.md 0000664 0000000 0000000 00000001556 14154204040 0022477 0 ustar 00root root 0000000 0000000 ---
name: Ulfius bug report
about: Create a report to help improve Ulfius
title: "[Issue]"
labels: ''
assignees: ''
---
**Describe the issue**
A clear and concise description of what the issue is, including a clear and concise title.
**To Reproduce**
If possible, post a sample code to reproduce the issue.
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**System (please complete the following information):**
- OS/Environment [e.g. Debian Stretch, Ubuntu 19.04, MSVC]
- Ulfius Version [e.g. 2.5.4]
- Source installation [e.g. Distribution package, github package, build from source]
- If applicable, what option did you use to build Ulfius [e.g. disable GnuTLS, disable Websocket]
**Additional context**
Add any other context about the problem here.
ulfius-2.7.7/.github/ISSUE_TEMPLATE/ulfius-feature-request.md 0000664 0000000 0000000 00000001146 14154204040 0023525 0 ustar 00root root 0000000 0000000 ---
name: Ulfius feature request
about: Suggest an idea for this project
title: "[Feature request]"
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. It would be nive to have...
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
ulfius-2.7.7/.github/workflows/ 0000775 0000000 0000000 00000000000 14154204040 0016425 5 ustar 00root root 0000000 0000000 ulfius-2.7.7/.github/workflows/ccpp.yml 0000664 0000000 0000000 00000034404 14154204040 0020102 0 ustar 00root root 0000000 0000000 on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: install dependencies
run: |
sudo apt-get update
sudo apt-get install -y cmake pkg-config check libsubunit-dev cppcheck libsystemd-dev libmicrohttpd-dev libgnutls28-dev libjansson-dev libcurl4-gnutls-dev zlib1g-dev gnutls-bin
sudo sysctl -w net.ipv6.conf.all.disable_ipv6=0
sudo sysctl -w net.ipv6.conf.lo.disable_ipv6=0
- name: cppcheck
run: cppcheck --force --enable=warning,missingInclude --error-exitcode=1 .
- name: build
run: |
# prepare build folders
mkdir build
mkdir example_programs/build
# build ulfius, run tests, build package
cd build
cmake -DBUILD_ULFIUS_TESTING=on ..
ln -s ../test/cert/ .
./cert/create-cert.sh || (cat ../test/cert/certtool.log && false)
make test || (cat Testing/Temporary/LastTest.log && false)
make package
sudo make install
# build examples
cd ../example_programs/build
cmake ..
make
# test build options
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=off -DWITH_JOURNALD=off -DWITH_YDER=off -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=off -DWITH_JANSSON=off -DWITH_CURL=off ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=off -DWITH_JOURNALD=off -DWITH_YDER=off -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=off -DWITH_JANSSON=off -DWITH_CURL=on ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=off -DWITH_JOURNALD=off -DWITH_YDER=off -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=off -DWITH_JANSSON=on -DWITH_CURL=off ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=off -DWITH_JOURNALD=off -DWITH_YDER=off -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=off -DWITH_JANSSON=on -DWITH_CURL=on ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=off -DWITH_JOURNALD=off -DWITH_YDER=off -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=on -DWITH_JANSSON=off -DWITH_CURL=off ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=off -DWITH_JOURNALD=off -DWITH_YDER=off -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=on -DWITH_JANSSON=off -DWITH_CURL=on ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=off -DWITH_JOURNALD=off -DWITH_YDER=off -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=on -DWITH_JANSSON=on -DWITH_CURL=off ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=off -DWITH_JOURNALD=off -DWITH_YDER=off -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=on -DWITH_JANSSON=on -DWITH_CURL=on ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=off -DWITH_JOURNALD=off -DWITH_YDER=on -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=off -DWITH_JANSSON=off -DWITH_CURL=off ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=off -DWITH_JOURNALD=off -DWITH_YDER=on -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=off -DWITH_JANSSON=off -DWITH_CURL=on ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=off -DWITH_JOURNALD=off -DWITH_YDER=on -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=off -DWITH_JANSSON=on -DWITH_CURL=off ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=off -DWITH_JOURNALD=off -DWITH_YDER=on -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=off -DWITH_JANSSON=on -DWITH_CURL=on ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=off -DWITH_JOURNALD=off -DWITH_YDER=on -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=on -DWITH_JANSSON=off -DWITH_CURL=off ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=off -DWITH_JOURNALD=off -DWITH_YDER=on -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=on -DWITH_JANSSON=off -DWITH_CURL=on ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=off -DWITH_JOURNALD=off -DWITH_YDER=on -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=on -DWITH_JANSSON=on -DWITH_CURL=off ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=off -DWITH_JOURNALD=off -DWITH_YDER=on -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=on -DWITH_JANSSON=on -DWITH_CURL=on ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=on -DWITH_JOURNALD=off -DWITH_YDER=off -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=off -DWITH_JANSSON=off -DWITH_CURL=off ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=on -DWITH_JOURNALD=off -DWITH_YDER=off -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=off -DWITH_JANSSON=off -DWITH_CURL=on ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=on -DWITH_JOURNALD=off -DWITH_YDER=off -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=off -DWITH_JANSSON=on -DWITH_CURL=off ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=on -DWITH_JOURNALD=off -DWITH_YDER=off -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=off -DWITH_JANSSON=on -DWITH_CURL=on ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=on -DWITH_JOURNALD=off -DWITH_YDER=off -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=on -DWITH_JANSSON=off -DWITH_CURL=off ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=on -DWITH_JOURNALD=off -DWITH_YDER=off -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=on -DWITH_JANSSON=off -DWITH_CURL=on ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=on -DWITH_JOURNALD=off -DWITH_YDER=off -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=on -DWITH_JANSSON=on -DWITH_CURL=off ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=on -DWITH_JOURNALD=off -DWITH_YDER=off -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=on -DWITH_JANSSON=on -DWITH_CURL=on ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=on -DWITH_JOURNALD=off -DWITH_YDER=on -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=off -DWITH_JANSSON=off -DWITH_CURL=off ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=on -DWITH_JOURNALD=off -DWITH_YDER=on -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=off -DWITH_JANSSON=off -DWITH_CURL=on ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=on -DWITH_JOURNALD=off -DWITH_YDER=on -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=off -DWITH_JANSSON=on -DWITH_CURL=off ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=on -DWITH_JOURNALD=off -DWITH_YDER=on -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=off -DWITH_JANSSON=on -DWITH_CURL=on ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=on -DWITH_JOURNALD=off -DWITH_YDER=on -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=on -DWITH_JANSSON=off -DWITH_CURL=off ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=on -DWITH_JOURNALD=off -DWITH_YDER=on -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=on -DWITH_JANSSON=off -DWITH_CURL=on ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=on -DWITH_JOURNALD=off -DWITH_YDER=on -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=on -DWITH_JANSSON=on -DWITH_CURL=off ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
cd ../../build
sudo make uninstall && rm -rf *
cmake -DWITH_GNUTLS=on -DWITH_JOURNALD=off -DWITH_YDER=on -DBUILD_ULFIUS_TESTING=on -DWITH_WEBSOCKET=on -DWITH_JANSSON=on -DWITH_CURL=on ..
make package
sudo make install
cd ../example_programs/build
rm -rf *
cmake ..
make
# build with Makefile
cd ../../
make
make clean debug CURLFLAG=1 JANSSONFLAG=1 WEBSOCKETFLAG=1 YDERFLAG=1
make clean debug CURLFLAG=1 JANSSONFLAG=1 YDERFLAG=1
make clean debug CURLFLAG=1 WEBSOCKETFLAG=1 YDERFLAG=1
make clean debug CURLFLAG=1 YDERFLAG=1
make clean debug JANSSONFLAG=1 WEBSOCKETFLAG=1 YDERFLAG=1
make clean debug CURLFLAG=1 JANSSONFLAG=1 YDERFLAG=1
make clean debug CURLFLAG=1 WEBSOCKETFLAG=1 YDERFLAG=1
make clean debug CURLFLAG=1 YDERFLAG=1
make clean debug CURLFLAG=1 JANSSONFLAG=1 WEBSOCKETFLAG=1
make clean debug CURLFLAG=1 JANSSONFLAG=1
make clean debug CURLFLAG=1 WEBSOCKETFLAG=1
make clean debug CURLFLAG=1
make clean debug JANSSONFLAG=1 WEBSOCKETFLAG=1
make clean debug CURLFLAG=1 JANSSONFLAG=1
make clean debug CURLFLAG=1 WEBSOCKETFLAG=1
make clean debug CURLFLAG=1
make clean debug GNUTLSFLAG=1 CURLFLAG=1 JANSSONFLAG=1 WEBSOCKETFLAG=1 YDERFLAG=1
make clean debug GNUTLSFLAG=1 CURLFLAG=1 JANSSONFLAG=1 YDERFLAG=1
make clean debug GNUTLSFLAG=1 CURLFLAG=1 WEBSOCKETFLAG=1 YDERFLAG=1
make clean debug GNUTLSFLAG=1 CURLFLAG=1 YDERFLAG=1
make clean debug GNUTLSFLAG=1 JANSSONFLAG=1 WEBSOCKETFLAG=1 YDERFLAG=1
make clean debug GNUTLSFLAG=1 CURLFLAG=1 JANSSONFLAG=1 YDERFLAG=1
make clean debug GNUTLSFLAG=1 CURLFLAG=1 WEBSOCKETFLAG=1 YDERFLAG=1
make clean debug GNUTLSFLAG=1 CURLFLAG=1 YDERFLAG=1
make clean debug GNUTLSFLAG=1 CURLFLAG=1 JANSSONFLAG=1 WEBSOCKETFLAG=1
make clean debug GNUTLSFLAG=1 CURLFLAG=1 JANSSONFLAG=1
make clean debug GNUTLSFLAG=1 CURLFLAG=1 WEBSOCKETFLAG=1
make clean debug GNUTLSFLAG=1 CURLFLAG=1
make clean debug GNUTLSFLAG=1 JANSSONFLAG=1 WEBSOCKETFLAG=1
make clean debug GNUTLSFLAG=1 CURLFLAG=1 JANSSONFLAG=1
make clean debug GNUTLSFLAG=1 CURLFLAG=1 WEBSOCKETFLAG=1
make clean debug GNUTLSFLAG=1 CURLFLAG=1
make clean debug UWSCFLAG=1
make clean debug UWSCFLAG=1 CURLFLAG=1
make clean debug UWSCFLAG=1 CURLFLAG=1 WEBSOCKETFLAG=1
make clean debug UWSCFLAG=1 CURLFLAG=1 JANSSONFLAG=1
make clean debug UWSCFLAG=1 CURLFLAG=1 YDERFLAG=1
# run tests with Makefile
sudo ldconfig
make clean debug
ulfius-2.7.7/.github/workflows/codeql-analysis.yml 0000664 0000000 0000000 00000004234 14154204040 0022243 0 ustar 00root root 0000000 0000000 name: "CodeQL"
on:
push:
branches: [master, ]
pull_request:
# The branches below must be a subset of the branches above
branches: [master]
schedule:
- cron: '0 5 * * 0'
jobs:
analyse:
name: Analyse
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
# Override language selection by uncommenting this and choosing your languages
# with:
# languages: go, javascript, csharp, python, cpp, java
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
# - name: Autobuild
# uses: github/codeql-action/autobuild@v1
# âšī¸ Command-line programs to run using the OS shell.
# đ https://git.io/JvXDl
# âī¸ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
- run: |
sudo apt-get update
sudo apt-get install -y cmake pkg-config libsystemd-dev libmicrohttpd-dev libgnutls28-dev libjansson-dev libcurl4-gnutls-dev zlib1g-dev gnutls-bin doxygen
# prepare build folders
mkdir build
mkdir example_programs/build
# build ulfius, run tests, build package
cd build
cmake -DBUILD_ULFIUS_DOCUMENTATION=on ..
make
make doc
sudo make install
# build examples
cd ../example_programs/build
cmake ..
make
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
ulfius-2.7.7/.gitignore 0000664 0000000 0000000 00000001616 14154204040 0015024 0 ustar 00root root 0000000 0000000 *.o
*.so
*.so.*
*.a
*.pc
ulfius-cfg.h
example_programs/auth_example/auth_client
example_programs/auth_example/auth_server
example_programs/injection_example/injection_example
example_programs/proxy_example/proxy
example_programs/request_example/client
example_programs/request_example/mail
example_programs/request_example/server
example_programs/simple_example/simple_example
example_programs/stream_example/stream_example
example_programs/stream_example/stream_client
example_programs/test_u_map/test_u_map
example_programs/multiple_callbacks_example/multiple_callbacks_example
example_programs/sheep_counter/sheep_counter
example_programs/websocket_example/websocket_server
example_programs/websocket_example/websocket_client
example_programs/*/valgrind*.txt
test/valgrind*.txt
test/*.o
test/core
test/u_map
test/framework
test/websocket
tools/uwsc/uwsc
tools/uwsc/valgrind.txt
*.log
*.crt
*.key
doc/API.md
ulfius-2.7.7/API.md 0000664 0000000 0000000 00000376612 14154204040 0014002 0 ustar 00root root 0000000 0000000 # Ulfius API Documentation
- [Use Ulfius in a C program](#use-ulfius-in-a-c-program)
- [Header file](#header-file)
- [Build options](#build-options)
- [Return values](#return-values)
- [Memory management](#memory-management)
- [Webservice initialization](#webservice-initialization)
- [Instance structure](#instance-structure)
- [Endpoint structure](#endpoint-structure)
- [Multiple callback functions](#multiple-callback-functions)
- [Multiple URLs with similar pattern](#multiple-urls-with-similar-pattern)
- [Start and stop webservice](#start-and-stop-webservice)
- [Callback functions management](#callback-functions-management)
- [Request structure](#request-structure)
- [ulfius_set_request_properties](#ulfius_set_request_properties)
- [Response structure](#response-structure)
- [ulfius_set_response_properties](#ulfius_set_response_properties)
- [Callback functions return value](#callback-functions-return-value)
- [Use JSON in request and response body](#use-json-in-request-and-response-body)
- [Additional functions](#additional-functions)
- [Memory management](#memory-management)
- [Character encoding](#character-encoding)
- [Accessing POST parameters](#accessing-post-parameters)
- [Accessing query string and URL parameters](#accessing-query-string-and-url-parameters)
- [Accessing header parameters](#accessing-header-parameters)
- [Cookie management](#cookie-management)
- [File upload](#file-upload)
- [Streaming data](#streaming-data)
- [Websockets communication](#websockets-communication)
- [Websocket management](#websocket-management)
- [Messages manipulation](#messages-manipulation)
- [Server-side websocket](#server-side-websocket)
- [Open a websocket communication](#open-a-websocket-communication)
- [Advanced websocket extension](#advanced-websocket-extension)
- [Built-in server extension permessage-deflate](#built-in-server-extension-permessage-deflate)
- [Close a websocket communication](#close-a-websocket-communication)
- [Websocket status](#websocket-status)
- [Client-side websocket](#client-side-websocket)
- [Prepare the request](#prepare-the-request)
- [Built-in client extension permessage-deflate](#built-in-client-extension-permessage-deflate)
- [Open the websocket](#open-the-websocket)
- [Websocket status](#websocket-status-1)
- [Outgoing request functions](#outgoing-request-functions)
- [Send HTTP request API](#send-http-request-api)
- [Send SMTP request API](#send-http-request-api)
- [struct _u_map API](#struct-_u_map-api)
- [What's new in Ulfius 2.7?](#whats-new-in-ulfius-27)
- [What's new in Ulfius 2.6?](#whats-new-in-ulfius-26)
- [What's new in Ulfius 2.5?](#whats-new-in-ulfius-25)
- [What's new in Ulfius 2.4?](#whats-new-in-ulfius-24)
- [What's new in Ulfius 2.3?](#whats-new-in-ulfius-23)
- [What's new in Ulfius 2.2?](#whats-new-in-ulfius-22)
- [What's new in Ulfius 2.1?](#whats-new-in-ulfius-21)
- [What's new in Ulfius 2.0?](#whats-new-in-ulfius-20)
- [Multiple callback functions](#multiple-callback-functions-1)
- [Keep only binary_body in struct _u_request and struct _u_response](#keep-only-binary_body-in-struct-_u_request-and-struct-_u_response)
- [Websocket service](#websocket-service)
- [Remove libjansson and libcurl hard dependency](#remove-libjansson-and-libcurl-hard-dependency)
- [Ready-to-use callback functions](#ready-to-use-callback-functions)
- [Update existing programs from Ulfius 2.0 to 2.1](#update-existing-programs-from-ulfius-20-to-21)
- [Update existing programs from Ulfius 1.x to 2.0](#update-existing-programs-from-ulfius-1x-to-20)
## Use Ulfius in a C program
### Header file
Include file `ulfius.h` in your source file:
```C
#include
```
### Build options
You can use `pkg-config` to provide the compile and link options for Ulfius:
```shell
$ # compile flags
$ pkg-config --cflags libulfius
-I/usr/include
$ # linker flags
$ pkg-config --libs libulfius
-L/usr/lib -lulfius -lorcania -lyder
```
If you don't or can't have pkg-config for the build, you can set the linker options `-lulfius -lorcania -lyder`.
The options `-lorcania` and `-lyder` are not necessary if you don't directly use Orcania or Yder functions. But in doubt, add them anyway.
On your linker command, add Ulfius as a dependency library, e.g. `-lulfius` for gcc.
## Return values
When specified, some functions return `U_OK` on success, and other values otherwise. `U_OK` is 0, other values are non-0 values. The defined return value list is the following:
```C
#define U_OK 0 // No error
#define U_ERROR 1 // Error
#define U_ERROR_MEMORY 2 // Error in memory allocation
#define U_ERROR_PARAMS 3 // Error in input parameters
#define U_ERROR_LIBMHD 4 // Error in libmicrohttpd execution
#define U_ERROR_LIBCURL 5 // Error in libcurl execution
#define U_ERROR_NOT_FOUND 6 // Something was not found
```
## Memory management
Ulfius uses the memory allocation functions `malloc/realloc/calloc/free` by default, but you can overwrite this and use any other memory allocation functions of your choice. Use Orcania's functions `o_set_alloc_funcs` and `o_get_alloc_funcs` to set and get memory allocation functions.
```C
void o_set_alloc_funcs(o_malloc_t malloc_fn, o_realloc_t realloc_fn, o_free_t free_fn);
void o_get_alloc_funcs(o_malloc_t * malloc_fn, o_realloc_t * realloc_fn, o_free_t * free_fn);
```
Accessing those functions requires you to directly link your application also against the Orcania library. To do so, add `-lorcania` to your linking command.
If you use a version of `libmicrohttpd` older than `0.9.61`, you need to set the `mhd_response_copy_data = 1` in your `_u_instance` if you use a memory allocator whose allocated return values may not directly be passed to free() or if you want to make sure all free() will always go via your user-provided free callback.
Data structures allocated have their specific cleanup functions. To free pointer allocated, you should use the function `u_free` that is intended to use your memory management functions.
```c
/**
* ulfius_clean_instance
*
* Clean memory allocated by a struct _u_instance *
*/
void ulfius_clean_instance(struct _u_instance * u_instance);
/**
* ulfius_clean_request
* clean the specified request's inner elements
* user must free the parent pointer if needed after clean
* or use ulfius_clean_request_full
* return U_OK on success
*/
int ulfius_clean_request(struct _u_request * request);
/**
* ulfius_clean_response
* clean the specified response's inner elements
* user must free the parent pointer if needed after clean
* or use ulfius_clean_response_full
* return U_OK on success
*/
int ulfius_clean_response(struct _u_response * response);
/**
* free the struct _u_map's inner components
* return U_OK on success
*/
int u_map_clean(struct _u_map * u_map);
/**
* free data allocated by ulfius functions
*/
void u_free(void * data);
```
It's **recommended** to use `ulfius_global_init` and `ulfius_global_close` at the beginning and at the end of your program to initialize and cleanup internal values and settings. This will make outgoing requests faster, especially if you use lots of them, and dispatch your memory allocation functions in curl and Jansson if you changed them. These functions are **NOT** thread-safe, so you must use them in a single thread context.
```C
/**
* Initialize global parameters
* This function isn't thread-safe so it must be called once before any call to
* ulfius_send_http_request, ulfius_send_http_streaming_request, ulfius_send_smtp_email or ulfius_send_smtp_rich_email
* The function ulfius_send_request_close must be called when ulfius send request functions are no longer needed
* @return U_OK on success
*/
int ulfius_global_init();
/**
* Close global parameters
*/
void ulfius_global_close();
```
## Webservice initialization
Ulfius framework runs as an async task in the background. When initialized, a thread is executed in the background. This thread will listen to the specified port and dispatch the calls to the specified callback functions. Ulfius allows adding and removing new endpoints during the instance execution.
To run a webservice, you must initialize a `struct _u_instance` and add your endpoints.
### Instance structure
The `struct _u_instance` is defined as:
```C
/**
*
* Structure of an instance
*
* Contains the needed data for an ulfius instance to work
*
* mhd_daemon: pointer to the libmicrohttpd daemon
* status: status of the current instance, status are U_STATUS_STOP, U_STATUS_RUNNING or U_STATUS_ERROR
* port: port number to listen to
* network_type: Listen to ipv4 and or ipv6 connections, values available are U_USE_ALL, U_USE_IPV4 or U_USE_IPV6
* bind_address: ipv4 address to listen to (optional)
* bind_address6: ipv6 address to listen to (optional)
* timeout: Timeout to close the connection because of inactivity between the client and the server
* nb_endpoints: Number of available endpoints
* default_auth_realm: Default realm on authentication error
* endpoint_list: List of available endpoints
* default_endpoint: Default endpoint if no other endpoint match the current url
* default_headers: Default headers that will be added to all response->map_header
* max_post_param_size: maximum size for a post parameter, 0 means no limit, default 0
* max_post_body_size: maximum size for the entire post body, 0 means no limit, default 0
* websocket_handler: handler for the websocket structure
* file_upload_callback: callback function to manage file upload by blocks
* file_upload_cls: any pointer to pass to the file_upload_callback function
* mhd_response_copy_data: to choose between MHD_RESPMEM_MUST_COPY and MHD_RESPMEM_MUST_FREE, only if you use MHD < 0.9.61,
* otherwise this option is skipped because it's useless
* check_utf8: check that all parameters values in the request (url, header and post_body)
* are valid utf8 strings, if a parameter value has non utf8 character, the value
* will be ignored, default 1
* use_client_cert_auth: Internal variable use to indicate if the instance uses client certificate authentication
* Do not change this value, available only if websocket support is enabled
*
*/
struct _u_instance {
struct MHD_Daemon * mhd_daemon;
int status;
unsigned int port;
unsigned short network_type;
struct sockaddr_in * bind_address;
struct sockaddr_in6 * bind_address6;
unsigned int timeout;
int nb_endpoints;
char * default_auth_realm;
struct _u_endpoint * endpoint_list;
struct _u_endpoint * default_endpoint;
struct _u_map * default_headers;
size_t max_post_param_size;
size_t max_post_body_size;
void * websocket_handler;
int (* file_upload_callback) (const struct _u_request * request,
const char * key,
const char * filename,
const char * content_type,
const char * transfer_encoding,
const char * data,
uint64_t off,
size_t size,
void * cls);
void * file_upload_cls;
int mhd_response_copy_data;
int check_utf8;
#ifndef U_DISABLE_GNUTLS
int use_client_cert_auth;
#endif
};
```
In the `struct _u_instance` structure, the element `port` must be set to the port number you want to listen to, the element `bind_address` is used if you want to listen only to a specific IP address. The element `mhd_daemon` is used by the framework, don't modify it.
You can use the functions `ulfius_init_instance`, `ulfius_init_instance_ipv6` and `ulfius_clean_instance` to facilitate the manipulation of the structure:
```C
/**
* ulfius_init_instance
*
* Initialize a struct _u_instance * with default values
* Binds to IPV4 addresses only
* @param u_instance the ulfius instance to initialize
* @param port tcp port to bind to, must be between 1 and 65535
* @param bind_address IPv4 address to listen to, optional, the reference is borrowed, the structure isn't copied
* @param default_auth_realm default realm to send to the client on authentication error
* @return U_OK on success
*/
int ulfius_init_instance(struct _u_instance * u_instance, unsigned int port, struct sockaddr_in * bind_address, const char * default_auth_realm);
/**
* ulfius_init_instance_ipv6
*
* Initialize a struct _u_instance * with default values
* Binds to IPV6 and IPV4 addresses or IPV6 addresses only
* @param port tcp port to bind to, must be between 1 and 65535
* @param bind_address IPv6 address to listen to, optional, the reference is borrowed, the structure isn't copied
* @param network_type Type of network to listen to, values available are U_USE_IPV6 or U_USE_ALL
* @param default_auth_realm default realm to send to the client on authentication error
* @return U_OK on success
*/
int ulfius_init_instance_ipv6(struct _u_instance * u_instance, unsigned int port, struct sockaddr_in6 * bind_address, unsigned short network_type, const char * default_auth_realm);
/**
* ulfius_clean_instance
*
* Clean memory allocated by a struct _u_instance *
*/
void ulfius_clean_instance(struct _u_instance * u_instance);
```
Since Ulfius 2.6, you can bind to IPv4 connections, IPv6 or both. By default, `ulfius_init_instance` binds to IPv4 addresses only. If you want to bind to both IPv4 and IPv6 addresses, use `ulfius_init_instance_ipv6` with the value parameter `network_type` set to `U_USE_ALL`. If you want to bind to IPv6 addresses only, use `ulfius_init_instance_ipv6` with the value parameter `network_type` set to `U_USE_IPV6`.
If you bind your instance to an address, you **MUST** set the port number to `struct sockaddr_in.sport` because the `struct _u_instance.port` will be ignored.
### Endpoint structure
The `struct _u_endpoint` is defined as:
```C
/**
*
* Structure of an endpoint
*
* Contains all informations needed for an endpoint
* http_method: http verb (GET, POST, PUT, etc.) in upper case
* url_prefix: prefix for the url (optional)
* url_format: string used to define the endpoint format
* separate words with /
* to define a variable in the url, prefix it with @ or :
* example: /test/resource/:name/elements
* on an url_format that ends with '*', the rest of the url will not be tested
* priority: endpoint priority in descending order (0 is the higher priority)
* callback_function: a pointer to a function that will be executed each time the endpoint is called
* you must declare the function as described.
* user_data: a pointer to a data or a structure that will be available in callback_function
*
*/
struct _u_endpoint {
char * http_method;
char * url_prefix;
char * url_format;
unsigned int priority;
int (* callback_function)(const struct _u_request * request, // Input parameters (set by the framework)
struct _u_response * response, // Output parameters (set by the user)
void * user_data);
void * user_data;
};
```
Some functions help you facilitate endpoints manipulation:
```C
/**
* Add a struct _u_endpoint * to the specified u_instance
* Can be done during the execution of the webservice for injection
* u_instance: pointer to a struct _u_instance that describe its port and bind address
* u_endpoint: pointer to a struct _u_endpoint that will be copied in the u_instance endpoint_list
* return U_OK on success
*/
int ulfius_add_endpoint(struct _u_instance * u_instance, const struct _u_endpoint * u_endpoint);
/**
* Add a struct _u_endpoint * to the specified u_instance with its values specified
* Can be done during the execution of the webservice for injection
* u_instance: pointer to a struct _u_instance that describe its port and bind address
* http_method: http verb (GET, POST, PUT, etc.) in upper case
* url_prefix: prefix for the url (optional)
* url_format: string used to define the endpoint format
* separate words with /
* to define a variable in the url, prefix it with @ or :
* example: /test/resource/:name/elements
* on an url_format that ends with '*', the rest of the url will not be tested
* priority: endpoint priority in descending order (0 is the higher priority)
* callback_function: a pointer to a function that will be executed each time the endpoint is called
* you must declare the function as described.
* user_data: a pointer to a data or a structure that will be available in callback_function
* return U_OK on success
*/
int ulfius_add_endpoint_by_val(struct _u_instance * u_instance,
const char * http_method,
const char * url_prefix,
const char * url_format,
uint priority,
int (* callback_function)(const struct _u_request * request, // Input parameters (set by the framework)
struct _u_response * response, // Output parameters (set by the user)
void * user_data),
void * user_data);
/**
* Add a struct _u_endpoint * list to the specified u_instance
* Can be done during the execution of the webservice for injection
* u_instance: pointer to a struct _u_instance that describe its port and bind address
* u_endpoint_list: pointer to an array of struct _u_endpoint ending with a ulfius_empty_endpoint() that will be copied in the u_instance endpoint_list
* return U_OK on success
*/
int ulfius_add_endpoint_list(struct _u_instance * u_instance, const struct _u_endpoint ** u_endpoint_list);
/**
* Remove a struct _u_endpoint * from the specified u_instance
* Can be done during the execution of the webservice for injection
* u_instance: pointer to a struct _u_instance that describe its port and bind address
* u_endpoint: pointer to a struct _u_endpoint that will be removed in the u_instance endpoint_list
* The parameters _u_endpoint.http_method, _u_endpoint.url_prefix and _u_endpoint.url_format are strictly compared for the match
* If no endpoint is found, return U_ERROR_NOT_FOUND
* return U_OK on success
*/
int ulfius_remove_endpoint(struct _u_instance * u_instance, const struct _u_endpoint * u_endpoint);
/**
* Remove a struct _u_endpoint * from the specified u_instance
* using the specified values used to identify an endpoint
* Can be done during the execution of the webservice for injection
* u_instance: pointer to a struct _u_instance that describe its port and bind address
* http_method: http_method used by the endpoint
* url_prefix: url_prefix used by the endpoint
* url_format: url_format used by the endpoint
* The parameters _u_endpoint.http_method, _u_endpoint.url_prefix and _u_endpoint.url_format are strictly compared for the match
* If no endpoint is found, return U_ERROR_NOT_FOUND
* return U_OK on success
*/
int ulfius_remove_endpoint_by_val(struct _u_instance * u_instance, const char * http_method, const char * url_prefix, const char * url_format);
/**
* ulfius_set_default_callback_function
* Set the default callback function
* This callback will be called if no endpoint match the url called
* callback_function: a pointer to a function that will be executed each time the endpoint is called
* you must declare the function as described.
* user_data: a pointer to a data or a structure that will be available in the callback function
* to remove a default callback function, call ulfius_set_default_callback_function with NULL parameter for callback_function
* return U_OK on success
*/
int ulfius_set_default_callback_function(struct _u_instance * u_instance,
int (* callback_function)(const struct _u_request * request, struct _u_response * response, void * user_data),
void * user_data);
```
HTTP Method can be an existing or not existing method, or `*` for any method. You must specify a url_prefix, a url_format or both, callback_function is mandatory, user_data is optional.
If you fill your array of endpoints manually, your `struct _u_endpoint` array **MUST** end with an empty `struct _u_endpoint`.
You can manually declare an endpoint or use the dedicated functions as `int ulfius_add_endpoint` or `int ulfius_add_endpoint_by_val`. It's recommended to use the dedicated functions to fill this array though.
If you manipulate the attribute `u_instance.endpoint_list`, you must end the list with an empty endpoint (see `const struct _u_endpoint * ulfius_empty_endpoint()`), and you must set the attribute `u_instance.nb_endpoints` accordingly. Also, you must use dynamically allocated values (`malloc`) for attributes `http_method`, `url_prefix` and `url_format`.
### Multiple callback functions
Ulfius allows multiple callbacks for the same endpoint. This is helpful when you need to execute several actions in sequence, for example check authentication, get resource, set cookie, then gzip response body. That's also why a priority must be set for each callback.
The priority is in descending order, which means that it starts with 0 (highest priority) and priority decreases when priority number increases. There is no more signification to the priority number, which means you can use any increments of your choice.
`Warning`: Having 2 callback functions with the same priority number will result in an undefined execution order result.
To help passing parameters between callback functions of the same request, the value `struct _u_response.shared_data` can be used. It's recommended to use the function `ulfius_set_response_shared_data` with a pointer to a free function for `shared_data`, therefore the framework will automatically clean `struct _u_response.shared_data` at the end of the callback list.
### Multiple URLs with similar pattern
If you need to differentiate multiple URLs with similar pattern, you can use priorities among multiple callback function.
For example, if you have 2 endpoints with the following patterns:
1- `/example/:id`
2- `/example/findByStatus`
You'll probably need the callback referred in 2- to be called and the callback referred in 1- not when the URL called is the exact pattern as in 2-. Nevertheless, you'll need callback referred in 1- in all the other cases.
In that case, you'll have to set a higher priority to the endpoint with the URL 2- and return its callback function with the value `U_CALLBACK_COMPLETE`. Remember, if the first callback returns `U_CALLBACK_CONTINUE`, the second callback will be called afterwards.
```C
int callback_example_find_by_status(const struct _u_request * request, struct _u_response * response, void * user_data) {
/* do something here... */
return U_CALLBACK_COMPLETE;
}
int callback_example_by_id(const struct _u_request * request, struct _u_response * response, void * user_data) {
/* do something else there... */
return U_CALLBACK_CONTINUE;
}
int main() {
/* initialize program and instance */
ulfius_add_endpoint_by_val(instance, "GET", NULL, "/example/:id", 1, &callback_example_by_id, my_user_data);
ulfius_add_endpoint_by_val(instance, "GET", NULL, "/example/findByStatus", 0, &callback_example_find_by_status, my_user_data);
/* start instance and run program */
}
```
## Start and stop webservice
### Start webservice
The starting point function are `ulfius_start_framework`, `ulfius_start_secure_framework`, `ulfius_start_secure_ca_trust_framework` or `ulfius_start_framework_with_mhd_options`:
```C
/**
* ulfius_start_framework
* Initializes the framework and run the webservice based on the parameters given
* return truze if no error
*
* u_instance: pointer to a struct _u_instance that describe its port and bind address
* return U_OK on success
*/
int ulfius_start_framework(struct _u_instance * u_instance);
/**
* ulfius_start_secure_framework
* Initializes the framework and run the webservice based on the parameters given using an HTTPS connection
*
* u_instance: pointer to a struct _u_instance that describe its port and bind address
* key_pem: private key for the server
* cert_pem: server certificate
* return U_OK on success
*/
int ulfius_start_secure_framework(struct _u_instance * u_instance, const char * key_pem, const char * cert_pem);
/**
* ulfius_start_secure_ca_trust_framework
* Initializes the framework and run the webservice based on the parameters given using an HTTPS connection
* And using a root server to authenticate client connections
*
* u_instance: pointer to a struct _u_instance that describe its port and bind address
* key_pem: private key for the server
* cert_pem: server certificate
* root_ca_pem: client root CA you're willing to trust for this instance
* return U_OK on success
*/
int ulfius_start_secure_ca_trust_framework(struct _u_instance * u_instance, const char * key_pem, const char * cert_pem, const char * root_ca_pem);
/**
* ulfius_start_framework_with_mhd_options
* Initializes the framework and run the webservice based on the specified MHD options table given in parameter
* Read https://www.gnu.org/software/libmicrohttpd/tutorial.html for more information
* This is for user who know what they do, Ulfius' options used in other `ulfius_start_framework_*`
* are good for most use cases where you need a multi-threaded HTTP webservice
* Some struct MHD_OptionItem may cause unexpected problems with Ulfius API
* If you find an unresolved issue with this function you can open an issue in GitHub
* But some issues may not be solvable if fixing them would break Ulfius API or philosophy
* i.e.: you're on your own
* @param u_instance pointer to a struct _u_instance that describe its port and bind address
* @param mhd_flags OR-ed combination of MHD_FLAG values
* @param mhd_ops struct MHD_OptionItem * options table,
* - MUST contain an option with the fllowing value: {.option = MHD_OPTION_NOTIFY_COMPLETED; .value = (intptr_t)mhd_request_completed; .ptr_value = NULL;}
* - MUST contain an option with the fllowing value: {.option = MHD_OPTION_URI_LOG_CALLBACK; .value = (intptr_t)ulfius_uri_logger; .ptr_value = NULL;}
* - MUST end with a terminal struct MHD_OptionItem: {.option = MHD_OPTION_END; .value = 0; .ptr_value = NULL;}
* @return U_OK on success
*/
int ulfius_start_framework_with_mhd_options(struct _u_instance * u_instance, unsigned int mhd_flags, struct MHD_OptionItem * options);
```
In your program, where you want to start the web server, execute the function `ulfius_start_framework(struct _u_instance * u_instance)` for a non-secure http connection. Use the function `ulfius_start_secure_framework(struct _u_instance * u_instance, const char * key_pem, const char * cert_pem)` for a secure https connection, using a valid private key and a valid corresponding server certificate, see openssl documentation for certificate generation. Finally, use the function `int ulfius_start_secure_ca_trust_framework(struct _u_instance * u_instance, const char * key_pem, const char * cert_pem, const char * root_ca_pem)` to start a secure https connection and be able to authenticate clients with a certificate.
Those function accept the previously declared `instance` as first parameter. You can reuse the same callback function as much as you want for different endpoints. On success, these functions returns `U_OK`, otherwise an error code.
Note: for security concerns, after running `ulfius_start_secure_framework` or `ulfius_start_secure_ca_trust_framework`, you can free the parameters `key_pem`, `cert_pem` and `root_ca_pem` if you want to.
### Stop webservice
To stop the webservice, call the following function:
```C
/**
* ulfius_stop_framework
*
* Stop the webservice
* u_instance: pointer to a struct _u_instance that describe its port and bind address
* return U_OK on success
*/
int ulfius_stop_framework(struct _u_instance * u_instance);
```
## Callback functions management
The callback function is the function executed when a user calls an endpoint managed by your webservice (as defined in your `struct _u_endpoint` list).
The callback function has the following signature:
```C
int (* callback_function)(const struct _u_request * request, // Input parameters (set by the framework)
struct _u_response * response, // Output parameters (set by the user)
void * user_data);
```
In the callback function definition, the variables `request` and `response` will be initialized by the framework, and the `user_data` variable will be assigned to the user_data defined in your endpoint list definition.
### Request structure
The request variable is defined as:
```C
/**
*
* Structure of request parameters
*
* Contains request data
* http_protocol: http protocol used (1.0 or 1.1)
* http_verb: http method (GET, POST, PUT, DELETE, etc.)
* http_url: full url used to call this callback function or full url to call when used in a ulfius_send_http_request
* url_path: url path only used to call this callback function (ex, if http_url is /path/?param=1, url_path is /path/)
* proxy: proxy address to use for outgoing connections, used by ulfius_send_http_request
* network_type: Force connect to ipv4, ipv6 addresses or both, values available are U_USE_ALL, U_USE_IPV4 or U_USE_IPV6
* check_server_certificate: check server certificate and hostname, default true, used by ulfius_send_http_request
* check_server_certificate_flag: check certificate peer and or server hostname if check_server_certificate is enabled, values available are U_SSL_VERIFY_PEER, U_SSL_VERIFY_HOSTNAME or both
default value is both (U_SSL_VERIFY_PEER|U_SSL_VERIFY_HOSTNAME), used by ulfius_send_http_request
* check_proxy_certificate: check proxy certificate and hostname, default true, used by ulfius_send_http_request, requires libcurl >= 7.52
* check_proxy_certificate_flag: check certificate peer and or proxy hostname if check_proxy_certificate is enabled, values available are U_SSL_VERIFY_PEER, U_SSL_VERIFY_HOSTNAME or both
default value is both (U_SSL_VERIFY_PEER|U_SSL_VERIFY_HOSTNAME), used by ulfius_send_http_request, requires libcurl >= 7.52
* follow_redirect: follow url redirections, used by ulfius_send_http_request
* ca_path specify a path to CA certificates instead of system path, used by ulfius_send_http_request
* timeout connection timeout used by ulfius_send_http_request, default is 0
* client_address: IP address of the client
* auth_basic_user: basic authentication username
* auth_basic_password: basic authentication password
* map_url: map containing the url variables, both from the route and the ?key=value variables
* map_header: map containing the header variables
* map_cookie: map containing the cookie variables
* map_post_body: map containing the post body variables (if available)
* binary_body: pointer to raw body
* binary_body_length: length of raw body
* callback_position: position of the current callback function in the callback list, starts at 0
* client_cert: x509 certificate of the client if the instance uses client certificate authentication and the client is authenticated
* available only if websocket support is enabled
* client_cert_file: path to client certificate file for sending http requests with certificate authentication
* available only if websocket support is enabled
* client_key_file: path to client key file for sending http requests with certificate authentication
* available only if websocket support is enabled
* client_key_password: password to unlock client key file
* available only if websocket support is enabled
*/
struct _u_request {
char * http_protocol;
char * http_verb;
char * http_url;
char * url_path;
char * proxy;
#if MHD_VERSION >= 0x00095208
unsigned short network_type;
#endif
int check_server_certificate;
int check_server_certificate_flag;
int check_proxy_certificate;
int check_proxy_certificate_flag;
int follow_redirect;
char * ca_path;
unsigned long timeout;
struct sockaddr * client_address;
char * auth_basic_user;
char * auth_basic_password;
struct _u_map * map_url;
struct _u_map * map_header;
struct _u_map * map_cookie;
struct _u_map * map_post_body;
void * binary_body;
size_t binary_body_length;
unsigned int callback_position;
#ifndef U_DISABLE_GNUTLS
gnutls_x509_crt_t client_cert;
char * client_cert_file;
char * client_key_file;
char * client_key_password;
#endif
};
```
Functions dedicated to handle the request:
```C
/**
* ulfius_set_string_body_request
* Set a string string_body to a request
* string_body must end with a '\0' character
* return U_OK on success
*/
int ulfius_set_string_body_request(struct _u_response * request, const char * string_body);
/**
* ulfius_set_binary_body_request
* Add a binary binary_body to a request
* return U_OK on success
*/
int ulfius_set_binary_body_request(struct _u_response * request, const char * binary_body, const size_t length);
/**
* ulfius_set_empty_body_request
* Set an empty request body
* return U_OK on success
*/
int ulfius_set_empty_body_request(struct _u_request * request);
```
### ulfius_set_request_properties
The function `ulfius_set_request_properties` allows to put a variable set of request properties in a single-line. The parameter list MUST end with the option `U_OPT_NONE`
```
/**
* ulfius_set_request_properties
* Set a list of properties to a request
* return U_OK on success
*/
int ulfius_set_request_properties(struct _u_request * request, ...);
```
Options available:
| Option | Description |
|---|---|
| U_OPT_NONE | Empty option to complete a ulfius_set_request_properties or ulfius_set_request_properties |
| U_OPT_HTTP_VERB | http method (GET, POST, PUT, DELETE, etc.), expected option value type: const char * |
| U_OPT_HTTP_URL | full URL used to call this callback function or full URL to call when used in a ulfius_send_http_request, expected option value type: const char * |
| U_OPT_HTTP_URL_APPEND | append char * value to the current url, expected option value type: const char * |
| U_OPT_HTTP_PROXY | proxy address to use for outgoing connections, used by ulfius_send_http_request, expected option value type: const char * |
| U_OPT_NETWORK_TYPE | Force connect to IPv4, IPv6 addresses or both, values available are U_USE_ALL, U_USE_IPV4 or U_USE_IPV6, expected option value type: unsigned short |
| U_OPT_CHECK_SERVER_CERTIFICATE | check server certificate and hostname, default true, used by ulfius_send_http_request, expected option value type: int |
| U_OPT_CHECK_SERVER_CERTIFICATE_FLAG | check certificate peer and or server hostname if check_server_certificate is enabled, values available are U_SSL_VERIFY_PEER, U_SSL_VERIFY_HOSTNAME or both, default value is both (U_SSL_VERIFY_PEER\|U_SSL_VERIFY_HOSTNAME), used by ulfius_send_http_request, expected option value type: int |
| U_OPT_CHECK_PROXY_CERTIFICATE | check proxy certificate and hostname, default true, used by ulfius_send_http_request, requires libcurl >= 7.52, expected option value type: int |
| U_OPT_CHECK_PROXY_CERTIFICATE_FLAG | check certificate peer and or proxy hostname if check_proxy_certificate is enabled, values available are U_SSL_VERIFY_PEER, U_SSL_VERIFY_HOSTNAME or both, default value is both (U_SSL_VERIFY_PEER\|U_SSL_VERIFY_HOSTNAME), used by ulfius_send_http_request, requires libcurl >= 7.52, expected option value type: int |
| U_OPT_FOLLOW_REDIRECT | follow URL redirections, used by ulfius_send_http_request, expected option value type: int |
| U_OPT_CA_PATH | specify a path to CA certificates instead of system path, used by ulfius_send_http_request, expected option value type: const char * |
| U_OPT_TIMEOUT | connection timeout used by ulfius_send_http_request, default is 0 _or_ Timeout in seconds to close the connection because of inactivity between the client and the server, expected option value type: unsigned long |
| U_OPT_AUTH_BASIC_USER | basic authentication username, expected option value type: const char * |
| U_OPT_AUTH_BASIC_PASSWORD | basic authentication password, expected option value type: const char * |
| U_OPT_URL_PARAMETER | Add to the map containing the URL variables, both from the route and the ?key=value variables, expected option value type: const char *, const char * |
| U_OPT_HEADER_PARAMETER | Add to the map containing the header variables, expected option value type: const char *, const char * |
| U_OPT_COOKIE_PARAMETER | Add to the map containing the cookie variables, expected option value type: const char *, const char * |
| U_OPT_POST_BODY_PARAMETER | Add to the map containing the post body variables (if available), expected option value type: const char *, const char * |
| U_OPT_URL_PARAMETER_REMOVE | Remove from the map containing the URL variables, both from the route and the ?key=value variables, expected option value type: const char * |
| U_OPT_HEADER_PARAMETER_REMOVE | Remove from map containing the header variables, expected option value type: const char * |
| U_OPT_COOKIE_PARAMETER_REMOVE | Remove from map containing the cookie variables, expected option value type: const char * |
| U_OPT_POST_BODY_PARAMETER_REMOVE | Remove from map containing the post body variables (if available), expected option value type: const char * |
| U_OPT_BINARY_BODY | Set a raw body to the request or the response, expected option value type: const char *, size_t |
| U_OPT_STRING_BODY | Set a char * body to the request or the response, expected option value type: const char * |
| U_OPT_JSON_BODY | Set a stringified json_t * body to the request or the response, expected option value type: json_t * |
| U_OPT_CLIENT_CERT_FILE | path to client certificate file for sending http requests with certificate authentication, available only if GnuTLS support is enabled, expected option value type: const char * |
| U_OPT_CLIENT_KEY_FILE | path to client key file for sending http requests with certificate authentication, available only if GnuTLS support is enabled, expected option value type: const char * |
| U_OPT_CLIENT_KEY_PASSWORD | password to unlock client key file, available only if GnuTLS support is enabled, expected option value type: const char * |
Example:
```C
ulfius_set_request_properties(&req, U_OPT_HTTP_VERB, "POST", U_OPT_HTTP_URL, "https://www.example.com/", U_OPT_CHECK_SERVER_CERTIFICATE, 0, U_OPT_STRING_BODY, "Hello World!", U_OPT_HEADER_PARAMETER, "Content-Type", "PlainText", U_OPT_NONE);
```
### Response structure
The response variable is defined as:
```C
/**
*
* Structure of response parameters
*
* Contains response data that must be set by the user
* status: HTTP status code (200, 404, 500, etc)
* protocol: HTTP Protocol sent
* map_header: map containing the header variables
* nb_cookies: number of cookies sent
* map_cookie: array of cookies sent
* auth_realm: realm to send to the client on authenticationb failed
* binary_body: a void * containing a raw binary content
* binary_body_length: the length of the binary_body
* stream_callback: callback function to stream data in response body
* stream_callback_free: callback function to free data allocated for streaming
* stream_size: size of the streamed data (U_STREAM_SIZE_UNKNOWN if unknown)
* stream_block_size: size of each block to be streamed, set according to your system
* stream_user_data: user defined data that will be available in your callback stream functions
* websocket_handle: handle for websocket extension
* shared_data: any data shared between callback functions, must be allocated and freed by the callback functions
* free_shared_data: pointer to a function that will free shared_data
* timeout: Timeout in seconds to close the connection because of inactivity between the client and the server
*
*/
struct _u_response {
long status;
char * protocol;
struct _u_map * map_header;
unsigned int nb_cookies;
struct _u_cookie * map_cookie;
char * auth_realm;
void * binary_body;
size_t binary_body_length;
ssize_t (* stream_callback) (void * stream_user_data, uint64_t offset, char * out_buf, size_t max);
void (* stream_callback_free) (void * stream_user_data);
uint64_t stream_size;
size_t stream_block_size;
void * stream_user_data;
void * websocket_handle;
void * shared_data;
void (* free_shared_data)(void * shared_data);
unsigned int timeout;
};
```
In the response variable set by the framework to the callback function, the structure is initialized with no data.
The user can set the `binary_body` before the return statement, or no response body at all if no need. If a `binary_body` is set, its size must be set to `binary_body_length`. `binary_body` is freed by the framework when the response has been sent to the client, so you must use dynamically allocated values. If no status is set, status 200 will be sent to the client.
Some functions are dedicated to handle the response:
```C
/**
* ulfius_add_header_to_response
* add a header to the response
* return U_OK on success
*/
int ulfius_add_header_to_response(struct _u_response * response, const char * key, const char * value);
/**
* ulfius_set_string_body_response
* Add a string body to a response
* body must end with a '\0' character
* return U_OK on success
*/
int ulfius_set_string_body_response(struct _u_response * response, const uint status, const char * body);
/**
* ulfius_set_binary_response
* Add a binary body to a response
* return U_OK on success
*/
int ulfius_set_binary_response(struct _u_response * response, const uint status, const char * body, const size_t length);
/**
* ulfius_set_empty_body_response
* Set an empty response with only a status
* return U_OK on success
*/
int ulfius_set_empty_body_response(struct _u_response * response, const uint status);
/**
* ulfius_set_stream_response
* Set an stream response with a status
* return U_OK on success
*/
int ulfius_set_stream_response(struct _u_response * response,
const uint status,
ssize_t (* stream_callback) (void * stream_user_data, uint64_t offset, char * out_buf, size_t max);
void (* stream_callback_free) (void * stream_user_data),
uint64_t stream_size,
size_t stream_block_size,
void * stream_user_data);
/**
* Set a websocket in the response
* You must set at least websocket_manager_callback or websocket_incoming_message_callback
* @Parameters
* response: struct _u_response to send back the websocket initialization, mandatory
* websocket_protocol: list of protocols, separated by a comma, or NULL if all protocols are accepted
* websocket_extensions: list of extensions, separated by a comma, or NULL if all extensions are accepted
* websocket_manager_callback: callback function called right after the handshake acceptance, optional
* websocket_manager_user_data: any data that will be given to the websocket_manager_callback, optional
* websocket_incoming_message_callback: callback function called on each incoming complete message, optional
* websocket_incoming_user_data: any data that will be given to the websocket_incoming_message_callback, optional
* websocket_onclose_callback: callback function called right before closing the websocket, must be complete for the websocket to close
* websocket_onclose_user_data: any data that will be given to the websocket_onclose_callback, optional
* @Return value: U_OK on success
*/
int ulfius_set_websocket_response(struct _u_response * response,
const char * websocket_protocol,
const char * websocket_extensions,
void (* websocket_manager_callback) (const struct _u_request * request,
struct _websocket_manager * websocket_manager,
void * websocket_manager_user_data),
void * websocket_manager_user_data,
void (* websocket_incoming_message_callback) (const struct _u_request * request,
struct _websocket_manager * websocket_manager,
const struct _websocket_message * message,
void * websocket_incoming_user_data),
void * websocket_incoming_user_data,
void (* websocket_onclose_callback) (const struct _u_request * request,
struct _websocket_manager * websocket_manager,
void * websocket_onclose_user_data),
void * websocket_onclose_user_data);
```
### ulfius_set_response_properties
The function `ulfius_set_response_properties` allows to put a variable set of response properties in a single-line. The parameter list MUST end with the option `U_OPT_NONE`
```C
/**
* ulfius_set_response_properties
* Set a list of properties to a response
* return U_OK on success
*/
int ulfius_set_response_properties(struct _u_response * response, ...);
```
Options available:
| Option | Description |
|---|---|
| U_OPT_NONE | Empty option to complete a ulfius_set_request_properties or ulfius_set_request_properties |
| U_OPT_STATUS | HTTP response status code (200, 404, 500, etc), expected option value type: long |
| U_OPT_AUTH_REALM | realm to send to the client response on authentication failed, expected option value type: const char * |
| U_OPT_SHARED_DATA | any data shared between callback functions, must be allocated and freed by the callback functions, expected option value type: void * |
| U_OPT_TIMEOUT | Timeout in seconds to close the connection because of inactivity between the client and the server, expected option value type: long |
| U_OPT_HEADER_PARAMETER | Add to the map containing the header variables, expected option value type: const char *, const char * |
| U_OPT_HEADER_PARAMETER_REMOVE | Remove from map containing the header variables, expected option value type: const char * |
| U_OPT_BINARY_BODY | Set a raw body to the request or the response, expected option value type: const char *, size_t |
| U_OPT_STRING_BODY | Set a char * body to the request or the response, expected option value type: const char * |
| U_OPT_JSON_BODY | Set a stringified json_t * body to the request or the response, expected option value type: json_t * |
Example:
```C
ulfius_set_response_properties(&req, U_OPT_STATUS, 200, U_OPT_STRING_BODY, "Hello World!", U_OPT_HEADER_PARAMETER, "Content-Type", "PlainText", U_OPT_NONE);
```
### Callback functions return value
The callback returned value can have the following values:
- `U_CALLBACK_CONTINUE`: The framework can transfer the request and the response to the next callback function in priority order if there is one, or complete the transaction and send back the response to the client.
- `U_CALLBACK_IGNORE`: The framework can transfer the request and the response to the next callback function in priority order if there is one, or complete the transaction and send back the response to the client, the counter `request->callback_position` will not be incremented. If at the end of the callback list `request->callback_position` is 0, the default callback (if set) will be called.
- `U_CALLBACK_COMPLETE`: The framework must complete the transaction and send the response to the client without calling any further callback function.
- `U_CALLBACK_UNAUTHORIZED`: The framework must complete the transaction without calling any further callback function and send an unauthorized response to the client with the status 401, the body specified and the `auth_realm` value if specified.
- `U_CALLBACK_ERROR`: An error occurred during execution, the framework will complete the transaction without calling any further callback function and send an error 500 to the client.
Except for the return values `U_CALLBACK_UNAUTHORIZED` and `U_CALLBACK_ERROR`, the callback return value isn't useful to specify the response sent back to the client. Use the `struct _u_response` variable in your callback function to set all values in the HTTP response.
### Use JSON in request and response body
In Ulfius 2.0, hard dependency with `libjansson` has been removed, the Jansson library is now optional but enabled by default.
If you want to remove JSON dependency, build Ulfius library using Makefile with the flag `JANSSONFLAG=-DU_DISABLE_JANSSON` or with CMake with the option `-DWITH_WEBSOCKET=off`.
```
$ make JANSSONFLAG=-DU_DISABLE_JANSSON # Makefile
$ cmake -DWITH_WEBSOCKET=off # CMake
```
if JSON is enabled, the following functions are available in Ulfius:
```C
/**
* ulfius_get_json_body_request
* Get JSON structure from the request body if the request is valid
* In case of an error in getting or parsing JSON data in the request,
* the structure json_error_t * json_error will be filled with an error
* message if json_error is not NULL
*/
json_t * ulfius_get_json_body_request(const struct _u_request * request, json_error_t * json_error);
/**
* ulfius_set_json_body_request
* Add a json_t body to a request
* return U_OK on success
*/
int ulfius_set_json_body_request(struct _u_request * request, json_t * body);
/**
* ulfius_get_json_body_response
* Get JSON structure from the response body if the request is valid
* In case of an error in getting or parsing JSON data in the request,
* the structure json_error_t * json_error will be filled with an error
* message if json_error is not NULL
*/
json_t * ulfius_get_json_body_response(struct _u_response * response, json_error_t * json_error);
/**
* ulfius_set_json_body_response
* Add a json_t body to a response
* return U_OK on success
*/
int ulfius_set_json_body_response(struct _u_response * response, const uint status, const json_t * body);
```
The `jansson` API documentation is available at the following address: [Jansson documentation](https://jansson.readthedocs.org/).
Note: According to the [JSON RFC section 6](https://tools.ietf.org/html/rfc4627#section-6), the MIME media type for JSON text is `application/json`. Thus, if there is no HTTP header specifying JSON content-type, the functions `ulfius_get_json_body_request` and `ulfius_get_json_body_response` will return NULL.
### Additional functions
In addition with manipulating the raw parameters of the structures, you can use the `_u_request` and `_u_response` structures by using specific functions designed to facilitate their use and memory management:
```C
/**
* ulfius_init_request
* Initialize a request structure by allocating inner elements
* return U_OK on success
*/
int ulfius_init_request(struct _u_request * request);
/**
* ulfius_clean_request
* clean the specified request's inner elements
* user must free the parent pointer if needed after clean
* or use ulfius_clean_request_full
* return U_OK on success
*/
int ulfius_clean_request(struct _u_request * request);
/**
* ulfius_clean_request_full
* clean the specified request and all its elements
* return U_OK on success
*/
int ulfius_clean_request_full(struct _u_request * request);
/**
* ulfius_init_response
* Initialize a response structure by allocating inner elements
* return U_OK on success
*/
int ulfius_init_response(struct _u_response * response);
/**
* ulfius_clean_response
* clean the specified response's inner elements
* user must free the parent pointer if needed after clean
* or use ulfius_clean_response_full
* return U_OK on success
*/
int ulfius_clean_response(struct _u_response * response);
/**
* ulfius_clean_response_full
* clean the specified response and all its elements
* return U_OK on success
*/
int ulfius_clean_response_full(struct _u_response * response);
/**
* ulfius_copy_response
* Copy the source response elements into the des response
* return U_OK on success
*/
int ulfius_copy_response(struct _u_response * dest, const struct _u_response * source);
/**
* ulfius_clean_cookie
* clean the cookie's elements
* return U_OK on success
*/
int ulfius_clean_cookie(struct _u_cookie * cookie);
/**
* Copy the cookie source elements into dest elements
* return U_OK on success
*/
int ulfius_copy_cookie(struct _u_cookie * dest, const struct _u_cookie * source);
/**
* create a new request based on the source elements
* returned value must be free'd after use
*/
struct _u_request * ulfius_duplicate_request(const struct _u_request * request);
/**
* create a new response based on the source elements
* return value must be free'd after use
*/
struct _u_response * ulfius_duplicate_response(const struct _u_response * response);
```
### Memory management
The Ulfius framework will automatically free the variables referenced by the request and responses structures, so you must use dynamically allocated values for the response pointers.
### Character encoding
You may be careful with characters encoding if you use non UTF8 characters in your application or webservice source code, and especially if you use different encoding in the same application. Ulfius may not work properly.
### Accessing POST parameters
In the callback function, you can access the POST parameters in the `struct _u_request.map_post_body`. The parameters keys are case-sensitive.
This variable is a `struct _u_map`, therefore you can access it using the [struct _u_map documentation](#struct-_u_map-api).
```C
// Example of accessing a POST parameter
int callback_test (const struct _u_request * request, struct _u_response * response, void * user_data) {
printf("POST parameter id: %s\n", u_map_get(request->map_post_body, "id"));
return U_CALLBACK_CONTINUE;
}
```
### Accessing query string and URL parameters
In the callback function, you can access the URL and query parameters in the `struct _u_request.map_url`. This variable contains both URL parameters and query string parameters, the parameters keys are case-sensitive. If a parameter appears multiple times in the URL and the query string, the values will be chained in the `struct _u_request.map_url`, separated by a comma `,`.
This variable is a `struct _u_map`, therefore you can access it using the [struct _u_map documentation](#struct-_u_map-api).
```C
// Example of accessing URL parameters
int callback_test (const struct _u_request * request, struct _u_response * response, void * user_data) {
/**
* The url could be either
* http://localhost:8080/?id=xxx
* http://localhost:8080/id/xxx/ (with a url format like '/id/:id')
* http://localhost:8080/id/xxx/?id=xxx (with a url format like '/id/:id')
*/
printf("URL parameter id: %s\n", u_map_get(request->map_url, "id"));
return U_CALLBACK_CONTINUE;
}
```
### Accessing header parameters
In the callback function, you can access the header parameters in the `struct _u_request.map_header`.
In the callback function, you can access the header parameters in the `struct _u_request.map_header`. The parameters keys are case-sensitive. If a parameter appears multiple times in the header, the values will be chained in the `struct _u_request.map_header`, separated by a comma `,`.
This variable is a `struct _u_map`, therefore you can access it using the [struct _u_map documentation](#struct-_u_map-api).
```C
// Example of accessing a POST parameter
int callback_test (const struct _u_request * request, struct _u_response * response, void * user_data) {
printf("Heder parameter id: %s\n", u_map_get(request->map_header, "id"));
return U_CALLBACK_CONTINUE;
}
```
### Cookie management
The map_cookie structure will contain a set of key/values for the cookies. The cookie structure is defined as
```C
/**
* struct _u_cookie
* the structure containing the response cookie parameters
*/
struct _u_cookie {
char * key;
char * value;
char * expires;
uint max_age;
char * domain;
char * path;
int secure;
int http_only;
int same_site;
};
```
You can use the functions `ulfius_add_cookie_to_response` or `ulfius_add_same_site_cookie_to_response` in your callback function to facilitate cookies management. These functions are defined as:
```C
/**
* ulfius_add_cookie_to_response
* add a cookie to the cookie map
* return U_OK on success
*/
int ulfius_add_cookie_to_response(struct _u_response * response, const char * key, const char * value, const char * expires, const uint max_age,
const char * domain, const char * path, const int secure, const int http_only);
/**
* ulfius_add_same_site_cookie_to_response
* add a cookie to the cookie map with a SameSite attribute
* the same_site parameter must have one of the following values:
* - U_COOKIE_SAME_SITE_NONE - No SameSite attribute
* - U_COOKIE_SAME_SITE_STRICT - SameSite attribute set to 'Strict'
* - U_COOKIE_SAME_SITE_LAX - SameSite attribute set to 'Lax'
* return U_OK on success
*/
int ulfius_add_same_site_cookie_to_response(struct _u_response * response, const char * key, const char * value, const char * expires, const unsigned int max_age,
const char * domain, const char * path, const int secure, const int http_only, const int same_site);
```
If you need to remove a cookie on the client, you can send a cookie with the same key but an empty value and a expiration in the past.
```C
/*
* Example of a cookie removal, you must change the values domain, path, secure, http_only
* according to your settings
*/
char * expires = "Sat, 10 Jan 1970 12:00:00 GMT"
ulfius_add_cookie_to_response(response, "cookie_key", "", expires, 0, "your_domain.tld", "/", 0, 0);
```
Please note that the client (browser, app, etc.) doesn't have to remove the cookies if it doesn't want to.
## File upload
Ulfius allows file upload to the server. Beware that an uploaded file will be stored in the request object in memory, so uploading large files may dramatically slow the application or even crash it, depending on your system. An uploaded file is stored in the `request->map_body` structure. You can use `u_map_get_length` to get the exact length of the file as it may not be a string format.
If you want to limit the size of a post parameter, if you want to limit the file size for example, set the value `struct _u_instance.max_post_param_size`. Files or post data exceeding this size will be truncated to the size `struct _u_instance.max_post_param_size`. If this parameter is 0, then no limit is set. Default value is 0.
If you want to handle file upload yourself, you can intercept the file upload process with your own callback function. Before running the webservice with `ulfius_start_framework`, you must call the function `ulfius_set_upload_file_callback_function` with a pointer to your file upload callback function. By using this method, the specified callback function will be executed as much as needed with a chunk of the file upload each time.
This function `ulfius_set_upload_file_callback_function` has the following prototype:
```C
/**
* ulfius_set_upload_file_callback_function
*
* Set the callback function to handle file upload
* Used to facilitate large files upload management
* The callback function file_upload_callback will be called
* multiple times, with the uploaded file in striped in parts
*
* Warning: If this function is used, all the uploaded files
* for the instance will be managed via this function, and they
* will no longer be available in the struct _u_request in the
* ulfius callback function afterwards.
*
* Thanks to Thad Phetteplace for the help on this feature
*
* u_instance: pointer to a struct _u_instance that describe its port and bind address
* file_upload_callback: Pointer to a callback function that will handle all file uploads
* cls: a pointer that will be passed to file_upload_callback each tim it's called
*/
int ulfius_set_upload_file_callback_function(struct _u_instance * u_instance,
int (* file_upload_callback) (const struct _u_request * request,
const char * key,
const char * filename,
const char * content_type,
const char * transfer_encoding,
const char * data,
uint64_t off,
size_t size,
void * cls),
void * cls);
```
This callback function will be called before all the other callback functions, and be aware that not all parameters, especially URL parameters, will be present during the file upload callback function executions.
See `examples/sheep_counter` for a file upload example.
## Streaming data
If you need to stream data, i.e. send a variable and potentially large amount of data, or if you need to send a chunked response, you can define and use `stream_callback_function` in the `struct _u_response`.
Not that if you stream data to the client, any data that was in the `response->binary_body` will be ignored. You must at least set the function pointer `struct _u_response.stream_callback` to stream data. Set `stream_size` to U_STREAM_SIZE_UNKNOWN if you don't know the size of the data you need to send, like in audio stream for example. Set `stream_block_size` according to you system resources to avoid out of memory errors, also, set `stream_callback_free` with a pointer to a function that will free values allocated by your stream callback function, as a `close()` file for example, and finally, you can set `stream_user_data` to a pointer.
You can use the function `ulfius_set_stream_response` to set those parameters.
The prototype of the `stream_callback` function is the following:
```C
ssize_t stream_callback (void * stream_user_data, // Your predefined user_data
uint64_t offset, // the position of the current data to send
char * out_buf, // The output buffer to fill with data
size_t max); // the max size of data to be put in the out_buf
```
The return value must be the size of the data put in `out_buf`.
This function will be called over and over in loop as long as the client has the connection opened.
If you want to close the stream from the server side, return `U_STREAM_END` in the `stream_callback` function. If a problem occurred, you can close the connection with a `U_STREAM_ERROR` return value.
While the `stream_callback_free` function is as simple as:
```C
void stream_callback_free (void * stream_user_data);
```
Check the application `stream_example` in the example folder.
## Websockets communication
The websocket protocol is defined in the [RFC6455](https://tools.ietf.org/html/rfc6455). A websocket is a full-duplex communication layer between a server and a client initiated by a HTTP request. Once the websocket handshake is complete between the client and the server, the TCP socket between them is kept open and messages in a specific format can be exchanged. Any side of the socket can send a message to the other side, which allows the server to push messages to the client.
Ulfius implements websocket communication, both server-side and client-side. The following chapter will describe how to create a websocket service or a websocket client by using callback functions. The framework will handle sending and receiving messages with the clients, and your application will deal with high level functions to facilitate the communication process.
### Websocket management
During the websocket connection, you can either send messages, read the incoming messages, close the connection, or wait until the connection is closed by the client or by a network problem.
### Messages manipulation
A websocket message has the following structure:
```C
/**
* websocket message structure
* contains all the data of a websocket message
* and the timestamp of when it was sent of received
*/
struct _websocket_message {
time_t datestamp; // datestamp when the message was transmitted
uint8_t rsv; // RSV (extension) flags, must be binary tested over U_WEBSOCKET_RSV1, U_WEBSOCKET_RSV2, U_WEBSOCKET_RSV3
uint8_t opcode; // opcode of the message: U_WEBSOCKET_OPCODE_TEXT, U_WEBSOCKET_OPCODE_BINARY, U_WEBSOCKET_OPCODE_PING, U_WEBSOCKET_OPCODE_PONG
uint8_t has_mask; // Flag to specify if the message has a mask
uint8_t mask[4]; // mask
size_t data_len; // Length of the data payload
char * data; // data payload
};
```
The different opcode values available are the following:
```C
U_WEBSOCKET_OPCODE_TEXT
U_WEBSOCKET_OPCODE_BINARY
U_WEBSOCKET_OPCODE_CLOSE
U_WEBSOCKET_OPCODE_PING
```
To send a message to the client, use the dedicated functions `ulfius_websocket_send_message`, `ulfius_websocket_send_fragmented_message` or `ulfius_websocket_send_json_message`:
```C
/**
* Send a message in the websocket
* Return U_OK on success
*/
int ulfius_websocket_send_message(struct _websocket_manager * websocket_manager,
const uint8_t opcode,
const uint64_t data_len,
const char * data);
/**
* Send a fragmented message in the websocket
* each fragment size will be at most fragment_len
* Return U_OK on success
*/
int ulfius_websocket_send_fragmented_message(struct _websocket_manager * websocket_manager,
const uint8_t opcode,
const uint64_t data_len,
const char * data,
const size_t fragment_len);
/**
* Send a JSON message in the websocket
* Return U_OK on success
*/
int ulfius_websocket_send_json_message(struct _websocket_manager * websocket_manager,
json_t * message);
```
To get the first message of the incoming or outcoming if you need to with `ulfius_websocket_pop_first_message`, this will remove the first message of the list, and return it as a pointer. You must free the message using the function `ulfius_clear_websocket_message` after use:
All the sent or received messages are stored by default in the `struct _websocket_manager` attributes `message_list_incoming` and `message_list_outcoming`. To skip storing incoming and/or outcoming messages, you can set the flag `struct _websocket_manager.keep_messages` with the values `U_WEBSOCKET_KEEP_INCOMING`, `U_WEBSOCKET_KEEP_OUTCOMING` or `U_WEBSOCKET_KEEP_NONE`. The flag is set to default with `U_WEBSOCKET_KEEP_INCOMING|U_WEBSOCKET_KEEP_OUTCOMING`.
```C
/**
* Return the first message of the message list
* Return NULL if message_list has no message
* Returned value must be cleared after use
*/
struct _websocket_message * ulfius_websocket_pop_first_message(struct _websocket_message_list * message_list);
/**
* Clear data of a websocket message
*/
void ulfius_clear_websocket_message(struct _websocket_message * message);
```
#### Fragmented messages limitation in browsers
It seems that some browsers like Firefox or Chromium don't like to receive fragmented messages, they will close the connection with a fragmented message is received. Use `ulfius_websocket_send_fragmented_message` with caution then.
### Server-side websocket
#### Open a websocket communication
To start a websocket communication between the client and your application, you must use the dedicated function `ulfius_start_websocket_cb` with proper values:
```C
/**
* Set a websocket in the response
* You must set at least websocket_manager_callback or websocket_incoming_message_callback
* @Parameters
* response: struct _u_response to send back the websocket initialization, mandatory
* websocket_protocol: list of protocols, separated by a comma, or NULL if all protocols are accepted
* websocket_extensions: list of extensions, separated by a comma, or NULL if all extensions are accepted
* websocket_manager_callback: callback function called right after the handshake acceptance, optional
* websocket_manager_user_data: any data that will be given to the websocket_manager_callback, optional
* websocket_incoming_message_callback: callback function called on each incoming complete message, optional
* websocket_incoming_user_data: any data that will be given to the websocket_incoming_message_callback, optional
* websocket_onclose_callback: callback function called right before closing the websocket, must be complete for the websocket to close
* websocket_onclose_user_data: any data that will be given to the websocket_onclose_callback, optional
* @Return value: U_OK on success
*/
int ulfius_set_websocket_response(struct _u_response * response,
const char * websocket_protocol,
const char * websocket_extensions,
void (* websocket_manager_callback) (const struct _u_request * request,
struct _websocket_manager * websocket_manager,
void * websocket_manager_user_data),
void * websocket_manager_user_data,
void (* websocket_incoming_message_callback) (const struct _u_request * request,
struct _websocket_manager * websocket_manager,
const struct _websocket_message * message,
void * websocket_incoming_user_data),
void * websocket_incoming_user_data,
void (* websocket_onclose_callback) (const struct _u_request * request,
struct _websocket_manager * websocket_manager,
void * websocket_onclose_user_data),
void * websocket_onclose_user_data);
```
According to the Websockets RFC, parameters `websocket_protocol` and `websocket_extensions` are specific for your application.
In Ulfius Implementation, if you specify a list of protocols as a string of protocol names, separated by a comma (`,`), Ulfius framework will check each one and see if they match the list of protocols specified by the client. The resulting protocol list will be sent back to the client.
Likewise, the websocket extension is specific to your application, you can specify a list of websocket extension separated by a comma (`,`).
If no protocol match your list, the connection will be closed by the framework and will return an error 400 to the client.
If you set a `NULL` value for the protocol and/or the extension, Ulfius will not accept any protocols and/or extension sent by the client, but the websocket connexion will be opened.
3 callback functions are available for the websocket implementation:
- `websocket_manager_callback`: This function will be called in a separate thread, and the websocket will remain open as long as this callback function is not completed. In this function, your program will have access to the websocket status (connected or not), and the list of messages sent and received. When this function ends, the websocket will close itself automatically.
- `websocket_incoming_message_callback`: This function will be called every time a new message is sent by the client. Although, it is in synchronous mode, which means that you won't have 2 different `websocket_incoming_message_callback` of the same websocket executed at the same time.
- `websocket_onclose_callback`: This optional function will be called right after the websocket connection is closed, but before the websocket structure is cleaned.
You must specify at least one of the callback functions between `websocket_manager_callback` or `websocket_incoming_message_callback`.
When the function `ulfius_stop_framework` is called, it will wait for all running websockets to end by themselves, there is no force close. So if you have a `websocket_manager_callback` function running, you *MUST* end this function in order to make a clean stop of the http daemon.
For each of these callback function, you can specify a `*_user_data` pointer containing any data you need.
#### Advanced websocket extension
Since Ulfius 2.7.0, you have advanced functions to handle websocket extensions based on the functions `ulfius_add_websocket_extension_message_perform` for the server websockets and `ulfius_add_websocket_client_extension_message_perform` for the clients websockets.
```C
/**
* Adds a set of callback functions to perform a message transformation via an extension
* @param response struct _u_response to send back the websocket initialization, mandatory
* @param extension the expected extension value
* @param websocket_extension_message_out_perform a callback function called before a message is sent to the server
* @param websocket_extension_message_out_perform_user_data a user-defined pointer passed to websocket_extension_message_out_perform
* @param websocket_extension_message_in_perform a callback function called after a message is received from the server
* @param websocket_extension_message_in_perform_user_data a user-defined pointer passed to websocket_extension_message_in_perform
* @param websocket_extension_server_match a callback function called on handshake response to match an extensions value with the given callback message perform extensions
* if NULL, then extension_client and the extension sent by the server will be compared for an exact match to enable this extension
* @param websocket_extension_server_match_user_data a user-defined pointer passed to websocket_extension_server_match
* @param websocket_extension_free_context a callback function called during the websocket close to free the context created in websocket_extension_server_match
* @param websocket_extension_free_context_user_data a user-defined pointer passed to websocket_extension_free_context
* @return U_OK on success
*/
int ulfius_add_websocket_extension_message_perform(struct _u_response * response,
const char * extension_server,
int (* websocket_extension_message_out_perform)(const uint8_t opcode,
uint8_t * rsv,
const uint64_t data_len_in,
const char * data_in,
uint64_t * data_len_out,
char ** data_out,
const uint64_t fragment_len,
void * user_data,
void * context),
void * websocket_extension_message_out_perform_user_data,
int (* websocket_extension_message_in_perform)(const uint8_t opcode,
uint8_t rsv,
const uint64_t data_len_in,
const char * data_in,
uint64_t * data_len_out,
char ** data_out,
const uint64_t fragment_len,
void * user_data,
void * context),
void * websocket_extension_message_in_perform_user_data,
int (* websocket_extension_server_match)(const char * extension_client,
const char ** extension_client_list,
char ** extension_server,
void * user_data,
void ** context),
void * websocket_extension_server_match_user_data,
void (* websocket_extension_free_context)(void * user_data,
void * context),
void * websocket_extension_free_context_user_data);
/**
* Adds a set of callback functions to perform a message transformation via an extension
* @param websocket_client_handler the handler of the websocket
* @param extension the expected extension value
* @param websocket_extension_message_out_perform a callback function called before a message is sent to the client
* @param websocket_extension_message_out_perform_user_data a user-defined pointer passed to websocket_extension_message_out_perform
* @param websocket_extension_message_in_perform a callback function called after a message is received from the client
* @param websocket_extension_message_in_perform_user_data a user-defined pointer passed to websocket_extension_message_in_perform
* @param websocket_extension_client_match a callback function called on handshake response to match an extensions value with the given callback message perform extensions
* if NULL, then extension and the extension sent by the client will be compared for an exact match to enable this extension
* @param websocket_extension_client_match_user_data a user-defined pointer passed to websocket_extension_client_match
* @param websocket_extension_free_context a callback function called during the websocket close to free the context created in websocket_extension_server_match
* @param websocket_extension_free_context_user_data a user-defined pointer passed to websocket_extension_free_context
* @return U_OK on success
*/
int ulfius_add_websocket_client_extension_message_perform(struct _websocket_client_handler * websocket_client_handler,
const char * extension,
int (* websocket_extension_message_out_perform)(const uint8_t opcode,
uint8_t * rsv,
const uint64_t data_len_in,
const char * data_in,
uint64_t * data_len_out,
char ** data_out,
const uint64_t fragment_len,
void * user_data,
void * context),
void * websocket_extension_message_out_perform_user_data,
int (* websocket_extension_message_in_perform)(const uint8_t opcode,
uint8_t rsv,
const uint64_t data_len_in,
const char * data_in,
uint64_t * data_len_out,
char ** data_out,
const uint64_t fragment_len,
void * user_data,
void * context),
void * websocket_extension_message_in_perform_user_data,
int (* websocket_extension_client_match)(const char * extension_server,
void * user_data,
void ** context),
void * websocket_extension_client_match_user_data,
void (* websocket_extension_free_context)(void * user_data,
void * context),
void * websocket_extension_free_context_user_data);
```
These functions add the possibility to run a callback function before a message is sent and/or after a message is received.
The callback functions `websocket_extension_server_match` and `websocket_extension_client_match` can be use if you expect to match an extension with parameters. If `NULL`, then instead an exact match between `const char * extension` and the extension received will be checked to enable or not this extension callback functions.
```C
/**
* Checks an extension sent by the client if it matches the expected extension
* if the function return U_OK, the extension will be enabled and the functions
* websocket_extension_message_out_perform and websocket_extension_message_in_perform available
* @param extension_client the extension value to check
* @param extension_client_list the list of all extension_client to match
* @param extension_server the extension value to return to the client
* @param user_data user-defined data
* @param context context to allocate
* @return U_OK on success
*/
int websocket_extension_server_match(const char * extension_client,
const char ** extension_client_list,
char ** extension_server,
void * user_data,
void ** context);
/**
* Checks an extension sent by the server if it matches the expected extension
* if the function return U_OK, the extension will be enabled and the functions
* websocket_extension_message_out_perform and websocket_extension_message_in_perform available
* @param extension_server the extension value to check
* @param user_data user-defined data
* @param context context to allocate
* @return U_OK on success
*/
int websocket_extension_client_match(const char * extension_server, void * user_data, void ** context);
```
The callback function `websocket_extension_message_out_perform` can modify the message data and data lenght and the RSV flags. The callback function `websocket_extension_message_in_perform` can modify the message data only. Inside these functions, `data_in` and `data_len_in` are the current data, your extension callback function must update `data_out` with a `o_malloc`'ed data and set the new data length using `data_len_out` and return `U_OK` on success.
If your function doesn't return `U_OK`, the message data won't be updated and `data_out` won't be free'd if set.
You can call `ulfius_add_websocket_extension_message_perform` or `ulfius_add_websocket_client_extension_message_perform` multiple times for a websocket definition. In that case the extension callbacks function will be called in the same order for the `websocket_extension_message_out_perform` callbacks, and in reverse order for the `websocket_extension_message_in_perform` callbacks.
#### Built-in server extension permessage-deflate
The Websocket extension [permessage-deflate](https://tools.ietf.org/html/rfc7692) used to compress the message data is available in Ulfius. To use this extension in your websocket server, you must call `ulfius_add_websocket_deflate_extension` after calling `ulfius_set_websocket_response` and before finishing the callback endpoint.
```C
/**
* Adds the required extension message perform to implement message compression according to
* RFC 7692: Compression Extensions for WebSocket
* https://tools.ietf.org/html/rfc7692
* Due to limited implementation, will force response parameters to server_no_context_takeover; client_no_context_takeover
* @param response struct _u_response to send back the websocket initialization, mandatory
* @return U_OK on success
*/
int ulfius_add_websocket_deflate_extension(struct _u_response * response);
```
See the sample code in [websocket_example/websocket_server.c](example_programs/websocket_example/websocket_server.c)
#### Close a websocket communication
To close a websocket communication from the server, you can do one of the following:
- End the function `websocket_manager_callback`, it will result in closing the websocket connection
- Send a message with the opcode `U_WEBSOCKET_OPCODE_CLOSE`
- Call the function `ulfius_websocket_wait_close` or `ulfius_websocket_send_close_signal` described below
If no `websocket_manager_callback` is specified, you can send a `U_WEBSOCKET_OPCODE_CLOSE` in the `websocket_incoming_message_callback` function when you need, or call the function `ulfius_websocket_send_close_signal`.
If a callback function `websocket_onclose_callback` has been specified, this function will be executed on every case at the end of the websocket connection.
If the websocket handshake hasn't been correctly completed or if an error appears during the handshake connection, the callback `websocket_onclose_callback` will be called anyway, even if the callback functions `websocket_manager_callback` or `websocket_incoming_message_callback` are skipped due to no websocket connection.
This is to allow the calling program to close opened resources or clean allocated memory. Beware that in this specific case, the parameter `struct _websocket_manager * websocket_manager` may be `NULL`.
#### Websocket status
The following functions allow the application to know if the the websocket is still open, to enforce closing the websocket or to wait until the websocket is closed by the client:
```C
/**
* Sets the websocket in closing mode
* The websocket will not necessarily be closed at the return of this function,
* it will process through the end of the `websocket_manager_callback`
* and the `websocket_onclose_callback` calls first.
* return U_OK on success
* or U_ERROR on error
*/
int ulfius_websocket_send_close_signal(struct _websocket_manager * websocket_manager);
/**
* Returns the status of the websocket connection
* Returned values can be U_WEBSOCKET_STATUS_OPEN or U_WEBSOCKET_STATUS_CLOSE
* wether the websocket is open or closed, or U_WEBSOCKET_STATUS_ERROR on error
*/
int ulfius_websocket_status(struct _websocket_manager * websocket_manager);
/**
* Wait until the websocket connection is closed or the timeout in milliseconds is reached
* if timeout is 0, no timeout is set
* Returned values can be U_WEBSOCKET_STATUS_OPEN or U_WEBSOCKET_STATUS_CLOSE
* wether the websocket is open or closed, or U_WEBSOCKET_STATUS_ERROR on error
*/
int ulfius_websocket_wait_close(struct _websocket_manager * websocket_manager, unsigned int timeout);
```
### Client-side websocket
Ulfius allows to create a websocket connection as a client. The behavior is quite similar to the server-side websocket. The application will open a websocket connection specified by a `struct _u_request`, and a set of callback functions to manage the websocket once connected.
#### Prepare the request
You can manually fill the `struct _u_request` with your parameters or use the dedicated function `ulfius_set_websocket_request`:
```C
/**
* Set values for a struct _u_request to open a websocket
* request must be previously initialized
* Return U_OK on success
*/
int ulfius_set_websocket_request(struct _u_request * request,
const char * url,
const char * websocket_protocol,
const char * websocket_extensions);
```
The `url` specified must have one of the following form:
- `http://`
- `ws://`
- `https://`
- `wss://`
The `websocket_protocol` and `websocket_extensions` values are optional. To specify multiple protocol, you must separate them with the comma `,` character. To specify multiple extensions, you must separate them with the semicolon `;` character.
You can also specify additional headers or cookies to the request.
Any body parameter or body raw value will be ignored, the header `Content-Length` will be set to 0.
The header `User-Agent` value will be `Ulfius Websocket Client Framework`, feel free to modify it afterwards if you need.
#### Built-in client extension permessage-deflate
The Websocket extension [permessage-deflate](https://tools.ietf.org/html/rfc7692) used to compress the message data is available in Ulfius. To use this extension in your websocket client, you must call `ulfius_add_websocket_client_deflate_extension` after calling `ulfius_set_websocket_request` and before calling `ulfius_open_websocket_client_connection`. Also, the parameter `struct _websocket_client_handler` must be initialized to `{NULL, NULL}` before calling `ulfius_set_websocket_request`.
```
/**
* Adds the required extension message perform to implement message compression according to
* RFC 7692: Compression Extensions for WebSocket
* https://tools.ietf.org/html/rfc7692
* @param websocket_client_handler the handler of the websocket
* @return U_OK on success
*/
int ulfius_add_websocket_client_deflate_extension(struct _websocket_client_handler * websocket_client_handler);
```
See the sample code in [websocket_example/websocket_client.c](example_programs/websocket_example/websocket_client.c)
#### Opening the websocket connection
Once the request is completed, you can open the websocket connection with `ulfius_open_websocket_client_connection`:
```C
/**
* Open a websocket client connection
* Return U_OK on success
* @parameters
* struct _u_request * request: request used to specify the input parameters
* websocket_manager_callback: main websocket callback function
* websocket_manager_user_data: a pointer that will be available in websocket_manager_callback
* websocket_incoming_message_callback: callback function that will be called each time a message is received
* websocket_incoming_user_data: a pointer that will be available in websocket_incoming_message_callback
* websocket_onclose_callback: callback function that will be called right after the websocket is closed
* websocket_onclose_user_data: a pointer that will be available in websocket_onclose_callback
* websocket_client_handler: The handler for the websocket
*
*/
int ulfius_open_websocket_client_connection(struct _u_request * request,
void (* websocket_manager_callback) (const struct _u_request * request,
struct _websocket_manager * websocket_manager,
void * websocket_manager_user_data),
void * websocket_manager_user_data,
void (* websocket_incoming_message_callback) (const struct _u_request * request,
struct _websocket_manager * websocket_manager,
const struct _websocket_message * message,
void * websocket_incoming_user_data),
void * websocket_incoming_user_data,
void (* websocket_onclose_callback) (const struct _u_request * request,
struct _websocket_manager * websocket_manager,
void * websocket_onclose_user_data),
void * websocket_onclose_user_data,
struct _websocket_client_handler * websocket_client_handler);
```
If the websocket connection is established, `U_OK` will be returned and the websocket connection will be executed in a separate thread.
#### Closing a websocket communication
To close a websocket communication, you can do one of the following:
- End the function `websocket_manager_callback`, it will result in closing the websocket connection
- Send a message with the opcode `U_WEBSOCKET_OPCODE_CLOSE`
- Call the function `ulfius_websocket_wait_close` described below, this function will return U_OK when the websocket is closed
- Call the function `ulfius_websocket_client_connection_send_close_signal` described below, this function is non-blocking, it will send a closing signal to the websocket and will return even if the websocket is still open. You can use `ulfius_websocket_wait_close` or `ulfius_websocket_client_connection_status` to check if the websocket is closed.
### Websocket status
The following functions allow the application to know if the the websocket is still open, to enforce closing the websocket or to wait until the websocket is closed by the server:
```C
/**
* Send a close signal to the websocket
* return U_OK when the signal is sent
* or U_ERROR on error
*/
int ulfius_websocket_client_connection_send_close_signal(struct _websocket_client_handler * websocket_client_handler);
/**
* Closes a websocket client connection
* return U_OK when the websocket is closed
* or U_ERROR on error
*/
int ulfius_websocket_client_connection_close(struct _websocket_client_handler * websocket_client_handler);
/**
* Returns the status of the websocket client connection
* Returned values can be U_WEBSOCKET_STATUS_OPEN or U_WEBSOCKET_STATUS_CLOSE
* wether the websocket is open or closed, or U_WEBSOCKET_STATUS_ERROR on error
*/
int ulfius_websocket_client_connection_status(struct _websocket_client_handler * websocket_client_handler);
/**
* Wait until the websocket client connection is closed or the timeout in milliseconds is reached
* if timeout is 0, no timeout is set
* Returned values can be U_WEBSOCKET_STATUS_OPEN or U_WEBSOCKET_STATUS_CLOSE
* wether the websocket is open or closed, or U_WEBSOCKET_STATUS_ERROR on error
*/
int ulfius_websocket_client_connection_wait_close(struct _websocket_client_handler * websocket_client_handler, unsigned int timeout);
```
## Outgoing request functions
Ulfius allows output functions to send HTTP or SMTP requests. These functions use `libcurl`. You can disable these functions by appending the argument `CURLFLAG=-DU_DISABLE_CURL` when you build the library with Makefile or by disabling the flag in CMake build:
```
$ make CURLFLAG=-DU_DISABLE_CURL # Makefile
$ cmake -DWITH_CURL=off # CMake
```
### Send HTTP request API
The functions `int ulfius_send_http_request(const struct _u_request * request, struct _u_response * response)` and `int ulfius_send_http_streaming_request(const struct _u_request * request, struct _u_response * response, size_t (* write_body_function)(void * contents, size_t size, size_t nmemb, void * user_data), void * write_body_data)` are based on `libcurl` API.
They allow to send an HTTP request with the parameters specified by the `_u_request` structure. Use the parameter `_u_request.http_url` to specify the distant URL to call.
You can fill the maps in the `_u_request` structure with parameters, they will be used to build the request. Note that if you fill `_u_request.map_post_body` with parameters, the content-type `application/x-www-form-urlencoded` will be use to encode the data.
The response parameters is stored into the `_u_response` structure. If you specify NULL for the response structure, the http call will still be made but no response details will be returned. If you use `ulfius_send_http_request`, the response body will be stored in the parameter `response->*body*`.
If you use `ulfius_send_http_streaming_request`, the response body will be available in the `write_body_function` specified in the call. The `ulfius_send_http_streaming_request` can be used for streaming data or large response, or if you need to receive a checked response from the server.
Return value is `U_OK` on success.
This functions are defined as:
```C
/**
* ulfius_send_http_request
* Send a HTTP request and store the result into a _u_response
* return U_OK on success
*/
int ulfius_send_http_request(const struct _u_request * request, struct _u_response * response);
/**
* ulfius_send_http_streaming_request
* Send a HTTP request and store the result into a _u_response
* Except for the body which will be available using write_body_function in the write_body_data
* return U_OK on success
*/
int ulfius_send_http_streaming_request(const struct _u_request * request,
struct _u_response * response,
size_t (* write_body_function)(void * contents,
size_t size,
size_t nmemb,
void * user_data),
void * write_body_data);
```
### Send SMTP request API
The function `ulfius_send_smtp_email` is used to send emails using a smtp server. It is based on `libcurl` API. It's used to send plain/text emails via a smtp server.
The function `ulfius_send_smtp_rich_email` is used to send an e-mail with a specified content-type.
The functions are defined as:
```C
/**
* ulfius_send_smtp_email
* Send an email using libcurl
* email is plain/text and UTF8 charset
* host: smtp server host name
* port: tcp port number (optional, 0 for default)
* use_tls: true if the connection is tls secured
* verify_certificate: true if you want to disable the certificate verification on a tls server
* user: connection user name (optional, NULL: no user name)
* password: connection password (optional, NULL: no password)
* from: from address (mandatory)
* to: to recipient address (mandatory)
* cc: cc recipient address (optional, NULL: no cc)
* bcc: bcc recipient address (optional, NULL: no bcc)
* subject: email subject (mandatory)
* mail_body: email body (mandatory)
* return U_OK on success
*/
int ulfius_send_smtp_email(const char * host,
const int port,
const int use_tls,
const int verify_certificate,
const char * user,
const char * password,
const char * from,
const char * to,
const char * cc,
const char * bcc,
const char * subject,
const char * mail_body);
/**
* Send an email using libcurl
* email has the content-type specified in parameter
* host: smtp server host name
* port: tcp port number (optional, 0 for default)
* use_tls: true if the connection is tls secured
* verify_certificate: true if you want to disable the certificate verification on a tls server
* user: connection user name (optional, NULL: no user name)
* password: connection password (optional, NULL: no password)
* from: from address (mandatory)
* to: to recipient address (mandatory)
* cc: cc recipient address (optional, NULL: no cc)
* bcc: bcc recipient address (optional, NULL: no bcc)
* content_type: content-type to add to the e-mail body
* subject: email subject (mandatory)
* mail_body: email body (mandatory)
* return U_OK on success
*/
int ulfius_send_smtp_rich_email(const char * host,
const int port,
const int use_tls,
const int verify_certificate,
const char * user,
const char * password,
const char * from,
const char * to,
const char * cc,
const char * bcc,
const char * content_type,
const char * subject,
const char * mail_body);
```
## struct _u_map API
The `struct _u_map` is a simple key/value mapping API used in the requests and the response for setting parameters. The available functions to use this structure are:
```C
/**
* initialize a struct _u_map
* this function MUST be called after a declaration or allocation
* return U_OK on success
*/
int u_map_init(struct _u_map * map);
/**
* free the struct _u_map's inner components
* return U_OK on success
*/
int u_map_clean(struct _u_map * u_map);
/**
* free the struct _u_map and its components
* return U_OK on success
*/
int u_map_clean_full(struct _u_map * u_map);
/**
* free an enum return by functions u_map_enum_keys or u_map_enum_values
* return U_OK on success
*/
int u_map_clean_enum(char ** array);
/**
* returns an array containing all the keys in the struct _u_map
* return an array of char * ending with a NULL element
*/
const char ** u_map_enum_keys(const struct _u_map * u_map);
/**
* returns an array containing all the values in the struct _u_map
* return an array of char * ending with a NULL element
*/
const char ** u_map_enum_values(const struct _u_map * u_map);
/**
* return true if the sprcified u_map contains the specified key
* false otherwise
* search is case sensitive
*/
int u_map_has_key(const struct _u_map * u_map, const char * key);
/**
* return true if the sprcified u_map contains the specified value
* false otherwise
* search is case sensitive
*/
int u_map_has_value(const struct _u_map * u_map, const char * value);
/**
* return true if the sprcified u_map contains the specified value up until the specified length
* false otherwise
* search is case sensitive
*/
int u_map_has_value_binary(const struct _u_map * u_map, const char * value, size_t length);
/**
* return true if the sprcified u_map contains the specified key
* false otherwise
* search is case insensitive
*/
int u_map_has_key_case(const struct _u_map * u_map, const char * key);
/**
* return true if the sprcified u_map contains the specified value
* false otherwise
* search is case insensitive
*/
int u_map_has_value_case(const struct _u_map * u_map, const char * value);
/**
* add the specified key/value pair into the specified u_map
* if the u_map already contains a pair with the same key, replace the value
* return U_OK on success
*/
int u_map_put(struct _u_map * u_map, const char * key, const char * value);
/**
* add the specified key/binary value pair into the specified u_map
* if the u_map already contains a pair with the same key,
* replace the value at the specified offset with the specified length
* return U_OK on success
*/
int u_map_put_binary(struct _u_map * u_map, const char * key, const char * value, uint64_t offset, size_t length);
/**
* get the value length corresponding to the specified key in the u_map
* return -1 if no match found
* search is case sensitive
*/
size_t u_map_get_length(const struct _u_map * u_map, const char * key);
/**
* get the value length corresponding to the specified key in the u_map
* return -1 if no match found
* search is case insensitive
*/
size_t u_map_get_case_length(const struct _u_map * u_map, const char * key);
/**
* get the value corresponding to the specified key in the u_map
* return NULL if no match found
* search is case sensitive
*/
const char * u_map_get(const struct _u_map * u_map, const char * key);
/**
* get the value corresponding to the specified key in the u_map
* return NULL if no match found
* search is case insensitive
*/
const char * u_map_get_case(const struct _u_map * u_map, const char * key);
/**
* remove an pair key/value that has the specified key
* return U_OK on success, U_NOT_FOUND if key was not found, error otherwise
*/
int u_map_remove_from_key(struct _u_map * u_map, const char * key);
/**
* remove all pairs key/value that has the specified key (case insensitive search)
* return U_OK on success, U_NOT_FOUND if key was not found, error otherwise
*/
int u_map_remove_from_key_case(struct _u_map * u_map, const char * key);
/**
* remove all pairs key/value that has the specified value
* return U_OK on success, U_NOT_FOUND if key was not found, error otherwise
*/
int u_map_remove_from_value(struct _u_map * u_map, const char * value);
/**
* remove all pairs key/value that has the specified value (case insensitive search)
* return U_OK on success, U_NOT_FOUND if key was not found, error otherwise
*/
int u_map_remove_from_value_case(struct _u_map * u_map, const char * value);
/**
* remove all pairs key/value that has the specified value up until the specified length
* return U_OK on success, U_NOT_FOUND if key was not found, error otherwise
*/
int u_map_remove_from_value_binary(struct _u_map * u_map, const char * key, size_t length);
/**
* remove the pair key/value at the specified index
* return U_OK on success, U_NOT_FOUND if index is out of bound, error otherwise
*/
int u_map_remove_at(struct _u_map * u_map, const int index);
/**
* Create an exact copy of the specified struct _u_map
* return a reference to the copy, NULL otherwise
* returned value must be free'd after use
*/
struct _u_map * u_map_copy(const struct _u_map * source);
/**
* Copy all key/values pairs of source into target
* If key is already present in target, it's overwritten
* return U_OK on success, error otherwise
*/
int u_map_copy_into(const struct _u_map * source, struct _u_map * target);
/**
* Return the number of key/values pair in the specified struct _u_map
* Return -1 on error
*/
int u_map_count(const struct _u_map * source);
```
## What's new in Ulfius 2.7?
Allow `Content-Enconding` header with `ulfius_send_http_request` to compress the response body
Add http_compression callback example
Add static_compressed_inmemory_website callback example
Add callback return value `U_CALLBACK_IGNORE` to igore incrementation of `request->callback_position`
Add `ulfius_add_websocket_extension_message_perform` and `ulfius_add_websocket_client_extension_message_perform` for advanced websocket extensions management
Add [Compression Extensions for WebSocket](https://tools.ietf.org/html/rfc7692)
### Breaking change with struct _websocket_client_handler
When declaring a `struct _websocket_client_handler` for websocket client API, you must initialize its members content to `NULL` before using it:
```C
struct _websocket_client_handler websocket_client_handler = {NULL, NULL};
```
### Breaking change with ulfius_set_websocket_response
When using `ulfius_set_websocket_response` with parameters `websocket_protocol` or `websocket_extensions` set to `NULL`, Ulfius will no longer accept any protocol or extension sent by the client, but will return no extension nor protocol to the client, and the websocket connexion will be "raw".
## What's new in Ulfius 2.6?
Add IPv6 support.
Add `struct _u_request->callback_position` to know the position of the current callback in the callback list.
## What's new in Ulfius 2.5?
Add option to ignore non UTF8 strings in incoming requests.
Allow client certificate authentication
## What's new in Ulfius 2.4?
Improve websocket service features with lots of bugfixes and add the possibility to send a fragmented message.
Add websocket client functionality. Allow to create a websocket client connection and exchange messages with the websocket service. In `http://`/`ws://` non-secure mode or `https://`/`wss://` secure mode.
Add a command-line websocket client: `uwsc`.
## What's new in Ulfius 2.3?
Not much on the API, a lot on the build process.
Install via CMake script.
## What's new in Ulfius 2.2?
Allow to use your own callback function when uploading files with `ulfius_set_upload_file_callback_function`, so a large file can be uploaded, even with the option `struct _u_instance.max_post_param_size` set.
## What's new in Ulfius 2.1?
I know it wasn't long since Ulfius 2.0 was released. But after some review and tests, I realized some adjustments had to be made to avoid bugs and to clean the framework a little bit more.
Some of the adjustments made in the new release:
- An annoying bug has been fixed that made streaming data a little buggy when used on Raspbian. Now if you don't know the data size you're sending, use the macro U_STREAM_SIZE_UNKNOWN instead of the previous value -1. There is some updates in the stream callback function parameter types. Check the [streaming data documentation](API.md#streaming-data).
- Fix bug on `ulfius_send_http_request` that didn't send back all headers value with the same name (#19)
- Fix websocket declaration structures to have them outside of the `ulfius.h`, because it could lead to horrifying bugs when you compile Ulfius with websocket but add `#define U_DISABLE_WEBSOCKET` in your application.
- Add proxy value for outgoing requests (#18)
- Unify and update functions name `ulfius_set_[string|json|binary]_body`. You may have to update your legacy code.
The minor version number has been incremented, from 2.0 to 2.1 because some of the changes may require changes in your own code.
## What's new in Ulfius 2.0?
Ulfius 2.0 brings several changes that make the library incompatible with Ulfius 1.0.x branch. The goal of making Ulfius 2.0 is to make a spring cleaning of some functions, remove what is apparently useless, and should bring bugs and memory loss. The main new features are multiple callback functions and websockets implementation.
### Multiple callback functions
Instead of having an authentication callback function, then a main callback function, you can now have as much callback functions as you want for the same endpoint. A `priority` number has been added in the `struct _u_endpoint` and the auth_callback function and its dependencies have been removed.
For example, let's say you have the following endpoints defined:
- `GET` `/api/tomato/:tomato` => `tomato_get_callback` function, priority 10
- `GET` `/api/potato/:potato` => `potato_get_callback` function, priority 10
- `GET` `/api/*` => `api_validate_callback` function, priority 5
- `*` `*` => `authentication_callback` function, priority 1
- `GET` `*` => `gzip_body_callback` function, priority 99
Then if the client calls the URL `GET` `/api/potato/myPotato`, the following callback functions will be called in that order:
- `authentication_callback`
- `api_validate_callback`
- `potato_get_callback`
- `gzip_body_callback`
*Warning:* In this example, the URL parameter `myPotato` will be available only in the `potato_get_callback` function, because the other endpoints did not defined a URL parameter after `/potato`.
If you need to communicate between callback functions for any purpose, you can use the new parameter `struct _u_response.shared_data`. This is a `void *` pointer initialized to `NULL`.
The dedicated function `ulfius_set_response_shared_data` can be used to set `struct _u_response.shared_data` and `struct _u_response.free_shared_data`. If `struct _u_response.free_shared_data` is set, the function will be used to free `struct _u_response.shared_data` at the end of the callback list.
Note: If you call `ulfius_set_response_shared_data` multiple times in the same request, before replacing `_u_response.shared_data`, the function `ulfius_set_response_shared_data` will free the previous pointer with the previous `struct _u_response.free_shared_data` if set.
### Keep only binary_body in struct _u_request and struct _u_response
the values `string_body` and `json_body` have been removed from the structures `struct _u_request` and `struct _u_response`. This may be painless in the response if you used only the functions `ulfius_set_xxx_body_response`. Otherwise, you should make small arrangements to your code.
### Websocket service
Ulfius now allows websockets communication between the client and the server. Check the [API.md](API.md#websockets-communication) file for implementation details.
Using websocket requires [libgnutls](https://www.gnutls.org/). It also requires a recent version of [Libmicrohttpd](https://www.gnu.org/software/libmicrohttpd/), at least 0.9.53.
If you don't need or can't use this feature, you can disable it by adding the option `WEBSOCKETFLAG=-DU_DISABLE_WEBSOCKET` to the make command when you build Ulfius:
```shell
$ make WEBSOCKETFLAG=-DU_DISABLE_WEBSOCKET
```
### Remove libjansson and libcurl hard dependency
In Ulfius 1.0, libjansson and libcurl were mandatory to build the library, but their usage was not in the core of the framework. Although they can be very useful, so the dependency is now optional.
They are enabled by default, but if you don't need them, you can disable them when you build Ulfius library.
#### libjansson dependency
This dependency allows to use the following functions:
```c
/**
* ulfius_get_json_body_request
* Get JSON structure from the request body if the request is valid
*/
json_t * ulfius_get_json_body_request(const struct _u_request * request, json_error_t * json_error);
/**
* ulfius_set_json_body_request
* Add a json_t body to a request
* return U_OK on success
*/
int ulfius_set_json_body_request(struct _u_request * request, json_t * body);
/**
* ulfius_set_json_body_response
* Add a json_t body to a response
* return U_OK on success
*/
int ulfius_set_json_body_response(struct _u_response * response, const uint status, const json_t * body);
/**
* ulfius_get_json_body_response
* Get JSON structure from the response body if the request is valid
*/
json_t * ulfius_get_json_body_response(struct _u_response * response, json_error_t * json_error);
```
If you want to disable these functions, append `JANSSONFLAG=-DU_DISABLE_JANSSON` when you build Ulfius library.
```
$ git clone https://github.com/babelouest/ulfius.git
$ cd ulfius/
$ git submodule update --init
$ make JANSSONFLAG=-DU_DISABLE_JANSSON
$ sudo make install
```
#### libcurl dependency
This dependency allows to use the following functions:
```c
/**
* ulfius_send_http_request
* Send a HTTP request and store the result into a _u_response
* return U_OK on success
*/
int ulfius_send_http_request(const struct _u_request * request, struct _u_response * response);
/**
* ulfius_send_http_streaming_request
* Send a HTTP request and store the result into a _u_response
* Except for the body which will be available using write_body_function in the write_body_data
* return U_OK on success
*/
int ulfius_send_http_streaming_request(const struct _u_request * request, struct _u_response * response, size_t (* write_body_function)(void * contents, size_t size, size_t nmemb, void * user_data), void * write_body_data);
/**
* ulfius_send_smtp_email
* Send an email using libcurl
* email is plain/text and UTF8 charset
* host: smtp server host name
* port: tcp port number (optional, 0 for default)
* use_tls: true if the connection is tls secured
* verify_certificate: true if you want to disable the certificate verification on a tls server
* user: connection user name (optional, NULL: no user name)
* password: connection password (optional, NULL: no password)
* from: from address (mandatory)
* to: to recipient address (mandatory)
* cc: cc recipient address (optional, NULL: no cc)
* bcc: bcc recipient address (optional, NULL: no bcc)
* subject: email subject (mandatory)
* mail_body: email body (mandatory)
* return U_OK on success
*/
int ulfius_send_smtp_email(const char * host,
const int port,
const int use_tls,
const int verify_certificate,
const char * user,
const char * password,
const char * from,
const char * to,
const char * cc,
const char * bcc,
const char * subject,
const char * mail_body);
/**
* Send an email using libcurl
* email has the content-type specified in parameter
* host: smtp server host name
* port: tcp port number (optional, 0 for default)
* use_tls: true if the connection is tls secured
* verify_certificate: true if you want to disable the certificate verification on a tls server
* user: connection user name (optional, NULL: no user name)
* password: connection password (optional, NULL: no password)
* from: from address (mandatory)
* to: to recipient address (mandatory)
* cc: cc recipient address (optional, NULL: no cc)
* bcc: bcc recipient address (optional, NULL: no bcc)
* content_type: content-type to add to the e-mail body
* subject: email subject (mandatory)
* mail_body: email body (mandatory)
* return U_OK on success
*/
int ulfius_send_smtp_rich_email(const char * host,
const int port,
const int use_tls,
const int verify_certificate,
const char * user,
const char * password,
const char * from,
const char * to,
const char * cc,
const char * bcc,
const char * content_type,
const char * subject,
const char * mail_body);
```
If you want to disable these functions, append `CURLFLAG=-DU_DISABLE_CURL` when you build Ulfius library.
```
$ git clone https://github.com/babelouest/ulfius.git
$ cd ulfius/
$ git submodule update --init
$ make CURLFLAG=-DU_DISABLE_CURL
$ sudo make install
```
If you wan to disable libjansson and libcurl, you can append both parameters.
```
$ git clone https://github.com/babelouest/ulfius.git
$ cd ulfius/
$ git submodule update --init
$ make CURLFLAG=-DU_DISABLE_CURL JANSSONFLAG=-DU_DISABLE_JANSSON
$ sudo make install
```
### Ready-to-use callback functions
You can find some ready-to-use callback functions in the folder [example_callbacks](https://github.com/babelouest/ulfius/blob/master/example_callbacks).
## Update existing programs from Ulfius 2.0 to 2.1
- An annoying bug has been fixed that made streaming data a little buggy when used on Raspbian. Now if you don't know the data size you're sending, use the macro U_STREAM_SIZE_UNKNOWN instead of the previous value -1.
- There are some updates in the stream callback function parameter types. Check the [streaming data documentation](#streaming-data).
- The websocket data structures are no longer available directly in `struct _u_response` or `struct _u_instance`. But you shouldn't use them like this anyway so it won't be a problem.
- Unify and update functions name `ulfius_set_*_body_response`. You may have to update your legacy code.
The new functions names are:
```c
int ulfius_set_string_body_response(struct _u_response * response, const uint status, const char * body);
int ulfius_set_binary_body_response(struct _u_response * response, const uint status, const char * body, const size_t length);
int ulfius_set_empty_body_response(struct _u_response * response, const uint status);
```
## Update existing programs from Ulfius 1.x to 2.0
If you already have programs that use Ulfius 1.x and want to update them to the brand new fresh Ulfius 2.0, it may require the following minor changes.
### Endpoints definitions
Endpoints structure have changed, `ulfius_add_endpoint_by_val` now requires only one callback function, but requires a priority number.
If you don't use authentication callback functions, you can simply remove the `NULL, NULL, NULL` parameters corresponding to the former authentication callback function pointer, the authentication callback user data, and the realm value. Then add any number as a priority, 0 for example.
If you use authentication callback functions, split your `ulfius_add_endpoint_by_val` call in 2 separate calls, one for the authentication function, one for the main callback function. For example:
```C
// An Ulfius 1.x call
ulfius_add_endpoint_by_val(&instance, "GET", "/", NULL, &auth_callback, my_auth_data, "my realm", &main_callback, my_main_data);
// The same behaviour with Ulfius 2.0
ulfius_add_endpoint_by_val(&instance, "GET", "/", NULL, 0, &auth_callback, my_auth_data);
ulfius_add_endpoint_by_val(&instance, "GET", "/", NULL, 1, &main_callback, my_main_data);
// In this case, the realm value "my realm" must be specified in the response
```
### Callback return value
The return value for the callback functions must be adapted, instead of U_OK, U_ERROR or U_ERROR_UNAUTHORIZED, you must use one of the following:
```C
#define U_CALLBACK_CONTINUE 0 // Will replace U_OK
#define U_CALLBACK_IGNORE 1
#define U_CALLBACK_COMPLETE 2
#define U_CALLBACK_UNAUTHORIZED 3 // Will replace U_ERROR_UNAUTHORIZED
#define U_CALLBACK_ERROR 4 // Will replace U_ERROR
```
If you want more details on the multiple callback functions, check the [documentation](#callback-functions-return-value).
Other functions may have change their name or signature, check the documentation for more information.
ulfius-2.7.7/CHANGELOG.md 0000664 0000000 0000000 00000021267 14154204040 0014651 0 ustar 00root root 0000000 0000000 # Ulfius Changelog
## 2.7.7
- Use `o_malloc` everywhere instead of `malloc` (#206)
## 2.7.6
- Fix `ulfius_websocket_wait_close`
- Fix `ulfius_send_http_request` when url contains spaces
## 2.7.5
- Fix cookie management in `ulfius_send_http_request` and `ulfius_send_http_streaming_request`
- Add option `U_OPT_AUTH_BASIC` to `ulfius_set_request_properties`
- Fix bug in static_compressed_inmemory_website callback example
## 2.7.4
- Add `void` parameter to functions with no param
- Fix bug when malformed HTTP requests are sent, thanks Jeremy Brown!
- Remove yder flag from `libulfius.pc` when yder is disabled
- Avoid Time-of-check time-of-use filesystem race condition, assume `fopen` result is enough
## 2.7.3
- Add `ULFIUS_CHECK_VERSION` macro (Thanks Oliv3)
- Add `struct _websocket_manager.keep_messages` flag
- Add `struct _u_response.free_shared_data` and `ulfius_set_response_shared_data`
## 2.7.2
- Fix post processor on multiple values with the same key (Thanks Oliv3)
- Fix certificate generation on MacOS (Thanks @valera-rozuvan)
- Add missing check includes if tests are built (Thanks @valera-rozuvan)
- Add option `U_OPT_HTTP_URL_APPEND` to `ulfius_set_request_properties`
- Use `ulfius_set_request_properties` in example programs
## 2.7.1
- Fix websocket protocol and extension management bug, thanks to Olivier Girondel
- Remove Travis CI tests
- Add Makefile flag `UWSCFLAG` to disable uwsc build
## 2.7.0
- Allow `Content-Enconding` header with `ulfius_send_http_request` to compress the response body
- Add http_compression callback example
- Add static_compressed_inmemory_website callback example
- Add callback return value `U_CALLBACK_IGNORE` to igore incrementation of `request->callback_position`
- Add `ulfius_add_websocket_extension_message_perform` and `ulfius_add_websocket_client_extension_message_perform` for advanced websocket extensions management
- Add [Compression Extensions for WebSocket](https://tools.ietf.org/html/rfc7692)
- Fix lots of websocket bugs thanks to [Autobahn|Testsuite](https://github.com/crossbario/autobahn-testsuite).
## 2.6.9
- Update doc generation
- Add `ulfius_websocket_send_json_message`, thanks to Olivier Girondel
- Update pkg-config Libs with all dependencies
- Add `ulfius_global_init` and `ulfius_global_close`
- Rename `U_STREAM_SIZE_UNKOWN` to `U_STREAM_SIZE_UNKNOWN`, keep `U_STREAM_SIZE_UNKOWN` for backward compatibility
## 2.6.8
- Increase `ULFIUS_POSTBUFFERSIZE` to follow MHD documentation
- Adapt code to be compatible with all MHD version
- In case of secure websocket communication, use a combination of `gnutls_record_check_pending()` and `poll()` to determine if data is ready. (Thanks **Wouter van Herpen**!)
- Install uwsc manpage
- Fix bug about missing `res` variable assignment. (Thanks **Gianfranco Costamagna**!)
## 2.6.7
- Check header property case insensitive in websocket client
- Add libcurl option `CURLOPT_NOPROGRESS` in `ulfius_send_http_streaming_request`
- Add `ulfius_start_framework_with_mhd_options` for expert mode
- Fix websocket bugs: #163 (Thanks wouher!)
- Add `ulfius_set_request_properties` and `ulfius_set_response_properties`
## 2.6.6
- Update doc generation
- Fix jansson memoy management bug
## 2.6.5
- Fix build on MinGW-w64
- Allow `NULL` values on `struct _u_map`
- Add function `ulfius_send_smtp_rich_email` to send e-mails with a specified content-type
- Fix and improve `ulfius_add_endpoint_list`
- Add doxygen documentation
- Add `follow_redirect` in `struct _u_request`
- Fix certificate check #154
## 2.6.4
- Add precision for chunked response, got the inspiration from #132
- Update access token for oauth2 bearer validation callback function, add precision concerning libjwt, fix #133
- Update callback_check_glewlwyd_access_token to the up-to-date version
- Various small fixes
## 2.6.3
- Fix warning appeared with gcc 9.1, fixes #128
- Make `instance->mhd_response_copy_data` useless if MHD>=0.9.61
- Fix `MHD_start_daemon` flag to reuse `MHD_USE_THREAD_PER_CONNECTION` by default, fix #131, thanks laf0rge!
## 2.6.2
- Clean build process
- Fix memory leak in `ulfius_set_string_body_request` and `ulfius_set_string_body_response`
- Call callback function websocket_onclose_callback on all times, even if the websocket hasn't properly worked, so the calling program can avoid memory leak and broken resources, fix #126
## 2.6.1
- Fix package dependencies in cmake script
- Fix core test to skip websocket tests if webscket is disabled
- Disable ipv6 capabilities if libmicrohttpd is older than 0.9.52
- Small bugfixes
## 2.6.0
- Add `struct _u_request->callback_position` to know the position of the current callback in the callback list
- Use `MHD_USE_AUTO` instead of `MHD_USE_THREAD_PER_CONNECTION` if `libmicrohttpd` is newer then 0.9.52
- Add `network_type` in `struct _u_instance` and `struct _u_request` to specify IPV4, IPV6 or both networks
- Add `check_server_certificate_flag`, `check_proxy_certificate`, `check_proxy_certificate_flag` and `ca_path` in `struct _u_request` to add more precision and control on SSL verification in `u_send_request`
- Add functions `ulfius_set_string_body_request`, `ulfius_set_binary_body_request`, `ulfius_set_empty_body_request`
- Add `url_path` in `struct _u_request` to store the url path only, without query parameters
- Add `ulfius_url_decode` and `ulfius_url_encode`
- Clean code, add more tests
- Install pkgconfig file when using Makefile
- Fix #121 where websockets messages of 126 or 127 bytes long made errors
- Use `gnutls_rnd()` instead of `rand()`
- Fix sneaky bug where endpoint injection inside a endpoint callback can lead to wrong callback calls, or even worse, crashes
## 2.5.5
- Fix #121 where websockets messages of 126 or 127 bytes long made errors
- Fix sneaky bug where endpoint injection inside a endpoint callback can lead to wrong callback calls, or even worse, crashes
## 2.5.3
- Add flag to build Ulfius with GnuTLS support but without Websockets
- Improve Travis CI script
- Fix CMake build process that didn't obviously linked Ulfius with pthreads
- Add command to run tests with valgrind
## 2.5.2
- Fix utf8 check on NULL value
## 2.5.1
- Fix uwsc crash on some systems
## 2.5.0
- Add struct _u_endpoint.check_utf8 to check all request parameters and values to be valid utf8 strings
- Add client certificate authentication for webservice and send request library (issue #83)
- Fix build config file bug when using -jxx option to Makefile (issue #84)
- Allow to disable Yder logging library, to use Ulfius in embedded systems like FreeRTOS
where console, syslog or journald are not available, and file logging is overkill
- Add support for FreeRTOS and LWIP, Thanks to Dirk Uhlemann
- Add support for SameSite attribute in response cookies (issue #88)
## 2.4.4
- CMake scripts improvements
## 2.4.3
- Add config file ulfius-cfg.h dynamically built with the options
- Adapt examples with new ulfius-cfg.h file
## 2.4.2
- Fix #79 where yuarel should be hidden from the outside world
## 2.4.1
- Fix #78 where gnutls is not required if websocket is disabled
## 2.4.0
- Fix Websocket fragmented messages
- Fix CMake script that installed Orcania twice
- Fix cppcheck warnings
- Add timeout for http connections
- Allow to use MHD_RESPMEM_MUST_COPY for different memory manager, fix #63
- Add websocket client framework
- Add uwsc - Ulfius WebSocket Client - A simple command-line websocket client program
- Add Travis CI
- Add RPM in CMake script package
## 2.3.8
- Fix CMake build when /usr/local is not present in default build path
## 2.3.7
- Improve documentation with summary
- Yet another websocket fix, this one was binary messages not properly handled
- At the same time, improve websocket_example to handle incoming binary messages
## 2.3.6
- Fix websocket bug that did not close a websocket properly after wrongly closed connections
- Add last example_callbacks versions
- Improve documentation on ulfius_get_json_body_request and ulfius_get_json_body_response
## 2.3.5
- Fix websocket bug that kept some connections open after being unproperly closed by the client
## 2.3.4
- Fix Makefile soname
## 2.3.3
- Add Debian hardening patch on Makefile
## 2.3.2
- Fix websocket_example that worked for Firefox onky due to minor bugs in websocket management and misunderstanding the RFC
- Update oauth2_bearer/glewlwyd_resource to handle client tokens
## 2.3.1
- Sync version number on all places it's located
## 2.3
- Add CMake installation script
- Various bugfixes
## 2.2.3
- Fix PTHREAD_MUTEX_RECURSIVE_NP bug
## 2.2.2
- Fix bug in websockets
## 2.2.1
- Added error informations inside ulfius_get_json_body_request function (#33)
- code cleaning
- small bugfixes
## 2.2
- Add large file upload support (#31)
- fix `upload_data_size` and memory consumption
- Make ldconfig harmless if not root (#26)
ulfius-2.7.7/CMakeLists.txt 0000664 0000000 0000000 00000044372 14154204040 0015602 0 ustar 00root root 0000000 0000000 #
# Ulfius library
#
# CMake file used to build all programs
#
# Copyright 2018 Silvio Clecio
# Copyright 2018-2021 Nicolas Mora
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the MIT License
#
# 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.
#
cmake_minimum_required(VERSION 3.5)
project(ulfius C)
set(CMAKE_C_STANDARD 99)
if (NOT MSVC)
set(CMAKE_C_FLAGS "-Wall -Werror ${CMAKE_C_FLAGS}")
endif()
# library info
set(PROJECT_DESCRIPTION "Web Framework to build REST APIs, Webservices or any HTTP endpoint in C language. Can stream large amount of data, integrate JSON data with Jansson, and create websocket services")
set(PROJECT_HOMEPAGE_URL "https://github.com/babelouest/ulfius/")
set(PROJECT_BUGREPORT_PATH "https://github.com/babelouest/ulfius/issues")
set(LIBRARY_VERSION_MAJOR "2")
set(LIBRARY_VERSION_MINOR "7")
set(LIBRARY_VERSION_PATCH "7")
set(PROJECT_VERSION "${LIBRARY_VERSION_MAJOR}.${LIBRARY_VERSION_MINOR}.${LIBRARY_VERSION_PATCH}")
set(PROJECT_VERSION_MAJOR ${LIBRARY_VERSION_MAJOR})
set(PROJECT_VERSION_MINOR ${LIBRARY_VERSION_MINOR})
set(PROJECT_VERSION_PATCH ${LIBRARY_VERSION_PATCH})
if (${LIBRARY_VERSION_MAJOR} VERSION_LESS 10)
set (LIBRARY_VERSION_MAJOR_PAD "0${LIBRARY_VERSION_MAJOR}")
else ()
set (LIBRARY_VERSION_MAJOR_PAD "${LIBRARY_VERSION_MAJOR}")
endif ()
if (${LIBRARY_VERSION_MINOR} VERSION_LESS 10)
set (LIBRARY_VERSION_MINOR_PAD "0${LIBRARY_VERSION_MINOR}")
else ()
set (LIBRARY_VERSION_MINOR_PAD "${LIBRARY_VERSION_MINOR}")
endif ()
if (${LIBRARY_VERSION_PATCH} VERSION_LESS 10)
set (LIBRARY_VERSION_PATCH_PAD "0${LIBRARY_VERSION_PATCH}")
else ()
set (LIBRARY_VERSION_PATCH_PAD "${LIBRARY_VERSION_PATCH}")
endif ()
set(PROJECT_VERSION_NUMBER "${LIBRARY_VERSION_MAJOR_PAD}${LIBRARY_VERSION_MINOR_PAD}${LIBRARY_VERSION_PATCH_PAD}")
set(LIBRARY_VERSION "${LIBRARY_VERSION_MAJOR}.${LIBRARY_VERSION_MINOR}.${LIBRARY_VERSION_PATCH}")
set(LIBRARY_SOVERSION "${LIBRARY_VERSION_MAJOR}.${LIBRARY_VERSION_MINOR}")
set(ORCANIA_VERSION_REQUIRED "2.2.1")
set(YDER_VERSION_REQUIRED "1.4.14")
set(JANSSON_VERSION_REQUIRED "2.1")
# cmake modules
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules)
include(GNUInstallDirs)
include(CheckSymbolExists)
# check if _GNU_SOURCE is available
if (NOT _GNU_SOURCE)
check_symbol_exists(__GNU_LIBRARY__ "features.h" _GNU_SOURCE)
if (NOT _GNU_SOURCE)
unset(_GNU_SOURCE CACHE)
check_symbol_exists(_GNU_SOURCE "features.h" _GNU_SOURCE)
endif ()
endif ()
if (_GNU_SOURCE)
add_definitions(-D_GNU_SOURCE)
endif ()
# directories and source
set(INC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
set(UWSC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tools/uwsc)
include_directories(${INC_DIR})
set(LIB_SRC
${INC_DIR}/ulfius.h
${INC_DIR}/u_private.h
${INC_DIR}/yuarel.h
${SRC_DIR}/u_map.c
${SRC_DIR}/u_request.c
${SRC_DIR}/u_response.c
${SRC_DIR}/u_send_request.c
${SRC_DIR}/u_websocket.c
${SRC_DIR}/yuarel.c
${SRC_DIR}/ulfius.c)
# pthread libraries
find_package (Threads)
set(LIBS ${LIBS} ${CMAKE_THREAD_LIBS_INIT})
# GNU TLS support
option(WITH_GNUTLS "GNU TLS support" ON)
if (WITH_GNUTLS)
include(FindGnuTLS)
find_package(GnuTLS REQUIRED)
if (GNUTLS_FOUND)
set(LIBS ${LIBS} ${GNUTLS_LIBRARIES})
include_directories(${GNUTLS_INCLUDE_DIRS})
endif ()
endif ()
# websocket support
option(WITH_WEBSOCKET "Websocket support" ON)
if (WIN32)
set(WITH_WEBSOCKET OFF)
endif ()
# current websocket implementation depends on GNU TLS
if (NOT WITH_GNUTLS)
set(WITH_WEBSOCKET OFF)
endif ()
if (WITH_WEBSOCKET AND NOT ${RELEASE_CODENAME} STREQUAL "stretch")
set(MHD_MIN_VERSION 0.9.53)
else ()
set(MHD_MIN_VERSION 0.9.51)
endif ()
if (WITH_GNUTLS)
set(U_DISABLE_GNUTLS OFF)
else ()
set(U_DISABLE_GNUTLS ON)
endif ()
include(FindMHD)
find_package(MHD ${MHD_MIN_VERSION} REQUIRED)
if (MHD_FOUND)
set(LIBS ${LIBS} ${MHD_LIBRARIES})
include_directories(${MHD_INCLUDE_DIRS})
if (MHD_VERSION_STRING VERSION_LESS "0.9.53")
set(WITH_WEBSOCKET OFF)
endif ()
endif ()
if (WITH_WEBSOCKET)
set(U_DISABLE_WEBSOCKET OFF)
include(FindZLIB)
find_package(ZLIB REQUIRED)
if (ZLIB_FOUND)
set(LIBS ${LIBS} ${ZLIB_LIBRARIES})
include_directories(${ZLIB_INCLUDE_DIRS})
endif ()
else ()
set(U_DISABLE_WEBSOCKET ON)
endif ()
option(WITH_CURL "Use Curl library" ON)
if (WITH_CURL)
include(FindCURL)
find_package(CURL REQUIRED)
if (CURL_FOUND)
set(LIBS ${LIBS} ${CURL_LIBRARIES})
include_directories(${CURL_INCLUDE_DIRS})
set(U_DISABLE_CURL OFF)
endif ()
else ()
set(U_DISABLE_CURL ON)
endif ()
option(WITH_JANSSON "Use jansson library" ON)
if (WITH_JANSSON)
include(FindJansson)
set(JANSSON_MIN_VERSION 2.4)
find_package(Jansson ${JANSSON_MIN_VERSION} REQUIRED)
if (JANSSON_FOUND)
include_directories(${JANSSON_INCLUDE_DIRS})
set(LIBS ${LIBS} ${JANSSON_LIBRARIES})
set(U_DISABLE_JANSSON OFF)
endif ()
else ()
set(U_DISABLE_JANSSON ON)
endif ()
# TO MY FUTURE SELF
# The following 2 blocks are put BEFORE searching for Orcania and Yder by design
# Otherwise it will lead to cmake errors
# DON'T MOVE IT BELOW PLEASE!
# static library
option(BUILD_STATIC "Build static library." OFF)
if (BUILD_STATIC)
add_library(ulfius_static STATIC ${LIB_SRC})
target_compile_definitions(ulfius_static PUBLIC -DO_STATIC_LIBRARY)
set_target_properties(ulfius_static PROPERTIES
OUTPUT_NAME ulfius)
endif ()
# shared library
add_library(ulfius SHARED ${LIB_SRC})
if (NOT MSVC)
set_target_properties(ulfius PROPERTIES
COMPILE_OPTIONS -Wextra
PUBLIC_HEADER "${INC_DIR}/ulfius.h;${PROJECT_BINARY_DIR}/ulfius-cfg.h"
VERSION "${LIBRARY_VERSION}"
SOVERSION "${LIBRARY_SOVERSION}")
endif()
if (WIN32)
set_target_properties(ulfius PROPERTIES SUFFIX "-${LIBRARY_VERSION_MAJOR}.dll")
endif ()
target_link_libraries(ulfius ${LIBS})
# documentation
option(BUILD_ULFIUS_DOCUMENTATION "Build the documentation." OFF)
if (BUILD_ULFIUS_DOCUMENTATION)
find_package(Doxygen)
if (DOXYGEN_FOUND)
set(doxyfile_in ${CMAKE_CURRENT_SOURCE_DIR}/doc/doxygen.cfg)
set(doxyfile ${CMAKE_CURRENT_BINARY_DIR}/doxyfile)
configure_file(${doxyfile_in} ${doxyfile} @ONLY)
add_custom_target(doc
COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile_in}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Generating documentation with Doxygen"
VERBATIM)
else ()
message(FATAL_ERROR "Doxygen is needed to build the documentation.")
endif ()
endif ()
# dependencies
option(DOWNLOAD_DEPENDENCIES "Download required dependencies" ON)
option(SEARCH_ORCANIA_U "Search for ORCANIA library" ON)
if (SEARCH_ORCANIA_U)
set(Orcania_FIND_QUIETLY ON) # force to find Orcania quietly
include(FindOrcania)
find_package(Orcania ${ORCANIA_VERSION_REQUIRED} QUIET) # try to find orcania
if (NOT ORCANIA_FOUND)
if (DOWNLOAD_DEPENDENCIES)
include(DownloadProject)
download_project(PROJ orcania # ... otherwise, download archive
URL "https://github.com/babelouest/orcania/archive/v${ORCANIA_VERSION_REQUIRED}.tar.gz"
QUIET)
add_subdirectory(${orcania_SOURCE_DIR} ${orcania_BINARY_DIR})
include_directories(${orcania_SOURCE_DIR}/include)
add_dependencies(ulfius orcania)
set(ORCANIA_LIBRARIES orcania)
set(LIBS ${LIBS} ${ORCANIA_LIBRARIES})
include_directories(${orcania_BINARY_DIR})
else ()
message( FATAL_ERROR "Orcania not found")
endif ()
else()
set(LIBS ${LIBS} ${ORCANIA_LIBRARIES})
include_directories(${ORCANIA_INCLUDE_DIRS})
endif ()
target_link_libraries(ulfius ${LIBS} ${ORCANIA_LIBRARIES})
endif ()
option(WITH_YDER "Use Yder library to log messages" ON)
option(SEARCH_YDER "Search for Yder library" ON)
set(LIB_YDER "")
if (WITH_YDER)
set(LIB_YDER "-lyder")
set(U_DISABLE_YDER OFF)
set(SEARCH_ORCANIA OFF CACHE BOOL "Force to false") # Avoid to search and download orcania during yder search and download
if (SEARCH_YDER)
set(Yder_FIND_QUIETLY ON) # force to find Yder quietly
include(FindYder)
find_package(Yder ${YDER_VERSION_REQUIRED} QUIET) # try to find Yder
if (NOT YDER_FOUND)
if (DOWNLOAD_DEPENDENCIES)
include(DownloadProject)
download_project(PROJ yder # ... otherwise, download archive
URL "https://github.com/babelouest/yder/archive/v${YDER_VERSION_REQUIRED}.tar.gz"
QUIET)
add_subdirectory(${yder_SOURCE_DIR} ${yder_BINARY_DIR})
include_directories(${yder_SOURCE_DIR}/include)
add_dependencies(ulfius yder)
set(YDER_LIBRARIES yder orcania)
include_directories(${yder_BINARY_DIR})
else ()
message( FATAL_ERROR "Yder not found")
endif ()
else()
set(LIBS ${LIBS} ${YDER_LIBRARIES})
include_directories(${YDER_INCLUDE_DIRS})
endif ()
target_link_libraries(ulfius ${LIBS} ${YDER_LIBRARIES})
endif ()
else ()
set(U_DISABLE_YDER ON)
endif ()
# build uwsc
option(BUILD_UWSC "Build uwsc application." ON)
if (NOT WITH_WEBSOCKET)
set(BUILD_UWSC OFF)
endif ()
if (BUILD_UWSC)
add_executable(uwsc ${UWSC_DIR}/uwsc.c ${INC_DIR}/ulfius.h ${INC_DIR}/u_private.h ${PROJECT_BINARY_DIR}/ulfius-cfg.h)
set_target_properties(uwsc PROPERTIES SKIP_BUILD_RPATH TRUE)
add_dependencies(uwsc ulfius)
target_link_libraries(uwsc ulfius ${LIBS})
install(TARGETS uwsc RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
INSTALL(FILES ${UWSC_DIR}/uwsc.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 COMPONENT runtime)
endif ()
set(PKGCONF_REQ "")
set(PKGCONF_REQ_PRIVATE "liborcania, libyder")
if (WITH_CURL)
set (PKGCONF_REQ_PRIVATE "${PKGCONF_REQ_PRIVATE}, libcurl")
endif ()
if (WITH_JANSSON)
set (PKGCONF_REQ_PRIVATE "${PKGCONF_REQ_PRIVATE}, jansson")
endif ()
if (WITH_GNUTLS)
set (PKGCONF_REQ_PRIVATE "${PKGCONF_REQ_PRIVATE}, gnutls >= 3.5.0")
endif ()
if (WITH_WEBSOCKET)
set (PKGCONF_REQ_PRIVATE "${PKGCONF_REQ_PRIVATE}, libmicrohttpd >= 0.9.53")
else ()
set (PKGCONF_REQ_PRIVATE "${PKGCONF_REQ_PRIVATE}, libmicrohttpd >= 0.9.51")
endif ()
# build ulfius-cfg.h file
configure_file(${INC_DIR}/ulfius-cfg.h.in ${PROJECT_BINARY_DIR}/ulfius-cfg.h)
set (CMAKE_EXTRA_INCLUDE_FILES ${PROJECT_BINARY_DIR})
include_directories(${PROJECT_BINARY_DIR})
# tests
option(BUILD_ULFIUS_TESTING "Build the testing tree." OFF) # because we do not use include(CTest)
if (BUILD_ULFIUS_TESTING)
include(FindCheck)
find_package(Check REQUIRED)
if (CHECK_FOUND)
if (NOT WIN32 AND NOT APPLE)
include(FindSubunit)
find_package(Subunit REQUIRED)
endif ()
enable_testing()
set(CMAKE_CTEST_COMMAND ctest -V)
set(TST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/test)
set(LIBS ulfius ${LIBS} ${CHECK_LIBRARIES})
include_directories(${CHECK_INCLUDE_DIRS})
if (NOT WIN32)
find_package(Threads REQUIRED)
set(LIBS ${LIBS} ${CMAKE_THREAD_LIBS_INIT} m)
endif ()
if (NOT APPLE)
set(LIBS ${LIBS} rt)
endif ()
if (NOT WIN32 AND NOT APPLE)
set(LIBS ${LIBS} ${SUBUNIT_LIBRARIES} rt)
endif ()
set(TESTS core u_map framework)
if (WITH_WEBSOCKET)
set(TESTS ${TESTS} websocket)
endif ()
configure_file(
"${CMAKE_MODULE_PATH}/CTestCustom.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/CTestCustom.cmake"
@ONLY)
foreach (t ${TESTS})
add_executable(${t} EXCLUDE_FROM_ALL ${TST_DIR}/${t}.c)
target_include_directories(${t} PUBLIC ${TST_DIR})
target_link_libraries(${t} PUBLIC ${LIBS})
add_test(NAME ${t}
WORKING_DIRECTORY ${TST_DIR}
COMMAND ${t})
endforeach ()
endif ()
endif ()
# install target
option(INSTALL_HEADER "Install the header files" ON) # Install ulfius.h or not
configure_file(libulfius.pc.in libulfius.pc @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libulfius.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
SET (TARGETS ulfius)
if (BUILD_STATIC)
SET (TARGETS ${TARGETS} ulfius_static)
endif ()
if (INSTALL_HEADER)
install(TARGETS ${TARGETS}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(DIRECTORY example_callbacks/
DESTINATION ${CMAKE_INSTALL_DOCDIR}/example_callbacks/ COMPONENT runtime)
install(DIRECTORY example_programs/
DESTINATION ${CMAKE_INSTALL_DOCDIR}/example_programs/
COMPONENT runtime
PATTERN example_programs/.gitignore EXCLUDE)
install(FILES README.md
DESTINATION ${CMAKE_INSTALL_DOCDIR} COMPONENT runtime)
install(FILES INSTALL.md
DESTINATION ${CMAKE_INSTALL_DOCDIR} COMPONENT runtime)
install(FILES API.md
DESTINATION ${CMAKE_INSTALL_DOCDIR} COMPONENT runtime)
else ()
install(TARGETS ${TARGETS}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif ()
# uninstall target
if (NOT TARGET uninstall)
configure_file(
"${CMAKE_MODULE_PATH}/CMakeUninstall.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
IMMEDIATE @ONLY)
add_custom_target(uninstall
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
endif ()
# packaging
set(CPACK_PACKAGE_VERSION_MAJOR ${LIBRARY_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${LIBRARY_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${LIBRARY_VERSION_PATCH})
if (INSTALL_HEADER)
set(PACKAGE_FILE_NAME
"lib${CMAKE_PROJECT_NAME}-dev_${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
else ()
set(PACKAGE_FILE_NAME
"lib${CMAKE_PROJECT_NAME}_${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
endif ()
set(PACKAGE_IGNORED_FILES
"${CMAKE_CURRENT_BINARY_DIR}/;/.git/;.gitignore;~$;${CPACK_SOURCE_IGNORE_FILES}")
set(CPACK_PACKAGE_NAME "libulfius")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Web Framework for C programs")
set(CPACK_GENERATOR "TGZ;DEB")
set(CPACK_PACKAGE_VERSION_MAJOR ${LIBRARY_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${LIBRARY_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${LIBRARY_VERSION_PATCH})
option(BUILD_RPM "Build a RPM for your system" OFF)
if (BUILD_RPM)
set(CPACK_GENERATOR "TGZ;DEB;RPM")
set(CPACK_RPM_PACKAGE_LICENSE "LGPL")
set(CPACK_RPM_PACKAGE_URL "http://babelouest.github.io/ulfius/")
endif ()
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "mail@babelouest.org")
set(CPACK_DEBIAN_PACKAGE_DESCRIPTION ${PROJECT_DESCRIPTION})
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://babelouest.github.io/ulfius/")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.4), liborcania (>= ${ORCANIA_VERSION_REQUIRED}), libyder (>= ${YDER_VERSION_REQUIRED})")
if (INSTALL_HEADER)
if (WITH_CURL)
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}, libcurl4-gnutls-dev (>= 7.16.2) | libcurl4-nss-dev (>= 7.16.2) | libcurl4-openssl-dev (>= 7.16.2)")
endif ()
if (WITH_JANSSON)
if (NOT ${RELEASE_CODENAME} STREQUAL "stretch" AND NOT ${RELEASE_CODENAME} STREQUAL "bionic")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}, libjansson-dev (>= ${JANSSON_VERSION_REQUIRED})")
endif ()
endif ()
if (WITH_GNUTLS)
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}, libgnutls28-dev|libgnutls-dev (>= 3.5.0)")
endif ()
if (WITH_WEBSOCKET)
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}, libmicrohttpd-dev (>= 0.9.53)")
else ()
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}, libmicrohttpd-dev (>= 0.9.51)")
endif ()
else ()
if (WITH_CURL)
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}, libcurl3-gnutls (>= 7.16.2) | libcurl3-nss (>= 7.16.2) | libcurl4 (>= 7.16.2)")
endif ()
if (WITH_JANSSON)
if (NOT ${RELEASE_CODENAME} STREQUAL "stretch" AND NOT ${RELEASE_CODENAME} STREQUAL "bionic")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}, libjansson4 (>= ${JANSSON_VERSION_REQUIRED})")
endif ()
endif ()
if (WITH_GNUTLS)
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}, libgnutls30 (>= 3.5.0)")
endif ()
if (WITH_WEBSOCKET)
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}, libmicrohttpd12 (>= 0.9.53)")
else ()
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}, libmicrohttpd12 (>= 0.9.51)")
endif ()
endif ()
set(CPACK_PACKAGE_FILE_NAME ${PACKAGE_FILE_NAME})
set(CPACK_SOURCE_GENERATOR "TGZ")
set(CPACK_SOURCE_PACKAGE_FILE_NAME ${PACKAGE_FILE_NAME})
set(CPACK_SOURCE_IGNORE_FILES ${PACKAGE_IGNORED_FILES})
include(CPack)
add_custom_target(dist_u COMMAND ${CMAKE_MAKE_PROGRAM} package_source)
message(STATUS "GNU TLS support: ${WITH_GNUTLS}")
message(STATUS "Websocket support: ${WITH_WEBSOCKET}")
message(STATUS "Outgoing requests support: ${WITH_CURL}")
message(STATUS "Jansson library support: ${WITH_JANSSON}")
message(STATUS "Yder support: ${WITH_YDER}")
message(STATUS "Build uwsc application: ${BUILD_UWSC}")
message(STATUS "Build static library: ${BUILD_STATIC}")
message(STATUS "Build testing tree: ${BUILD_ULFIUS_TESTING}")
message(STATUS "Install the header files: ${INSTALL_HEADER}")
message(STATUS "Build RPM package: ${BUILD_RPM}")
message(STATUS "Build documentation: ${BUILD_ULFIUS_DOCUMENTATION}")
ulfius-2.7.7/INSTALL.md 0000664 0000000 0000000 00000017445 14154204040 0014473 0 ustar 00root root 0000000 0000000 # Install Ulfius
- [Distribution packages](#distribution-packages)
- [Pre-compiled packages](#pre-compiled-packages)
- [Manual install](#manual-install)
- [Prerequisites](#prerequisites)
- [CMake - Multi architecture](#cmake---multi-architecture)
- [Good ol' Makefile](#good-ol-makefile)
## Distribution packages
[](https://repology.org/metapackage/ulfius)
Ulfius is available in multiple distributions as official package. Check out your distribution documentation to install the package automatically.
```shell
$ # Example for Debian testing, install ulfius library with development files and uwsc
$ sudo apt install libulfius-dev uwsc
$ # Example for Debian testing, install uwsc only
$ sudo apt install uwsc
```
## Pre-compiled packages
You can install Ulfius with a pre-compiled package available in the [release pages](https://github.com/babelouest/ulfius/releases/latest/). `jansson`, `libmicrohttpd`, `gnutls`, `libcurl-gnutls` and `zlib` development files packages are required to install Ulfius. The packages files `ulfius-dev-full_*` contain the libraries `orcania`, `yder` and `ulfius`.
For example, to install Ulfius with the `ulfius-dev-full_2.7.0_Debian_stretch_x86_64.tar.gz` package downloaded on the `releases` page, you must execute the following commands:
```shell
$ sudo apt install -y libmicrohttpd-dev libjansson-dev libcurl4-gnutls-dev libgnutls28-dev libgcrypt20-dev libsystemd-dev
$ wget https://github.com/babelouest/ulfius/releases/download/v2.7.0/ulfius-dev-full_2.7.0_debian_buster_x86_64.tar.gz
$ tar xf ulfius-dev-full_2.7.0_debian_buster_x86_64.tar.gz
$ sudo dpkg -i liborcania-dev_2.1.1_Debian_stretch_x86_64.deb
$ sudo dpkg -i libyder-dev_1.4.12_Debian_stretch_x86_64.deb
$ sudo dpkg -i libulfius-dev_2.7.0_Debian_stretch_x86_64.deb
```
If there's no package available for your distribution, you can recompile it manually using `CMake` or `Makefile`.
## Manual install
### Prerequisites
Ulfius requires the following dependencies.
- libmicrohttpd (required), minimum 0.9.53 if you require Websockets support
- libjansson (optional), minimum 2.4, required for json support
- libgnutls, libgcrypt (optional), required for Websockets and https support
- libcurl (optional), required to send http/smtp requests
- libsystemd (optional), required for [Yder](https://github.com/babelouest/yder) to log messages in journald
- zlib (optional), required for Websockets support
Note: the build stacks require a compiler (`gcc` or `clang`), `make`, `cmake` (if using CMake build), and `pkg-config`.
For example, to install all the external dependencies on Debian Stretch, run as root:
```shell
# apt install -y libmicrohttpd-dev libjansson-dev libcurl4-gnutls-dev libgnutls28-dev libgcrypt20-dev zlib1g-dev
```
### Good ol' Makefile
Download Orcania, Yder and Ulfius source code from GitHub, compile and install Orcania, then Yder, then compile and install Ulfius:
```shell
$ git clone https://github.com/babelouest/orcania.git
$ git clone https://github.com/babelouest/yder.git
$ git clone https://github.com/babelouest/ulfius.git
$ cd orcania/
$ make && sudo make install
$ cd ../yder/
$ make && sudo make install
$ cd ../ulfius/
$ make && sudo make install
```
#### Disable Ulfius dependencies
To disable libcurl functions, append the option `CURLFLAG=1` to the make command when you build Ulfius:
```shell
$ make CURLFLAG=1
```
If libcurl functions are disabled, `libcurl4-gnutls-dev` is no longer mandatory for install.
To disable libjansson functions, append the option `JANSSONFLAG=1` to the make command when you build Ulfius and Orcania:
```shell
$ make JANSSONFLAG=1
```
If libjansson functions are disabled, `libjansson-dev` is no longer mandatory for install.
To disable GNU TLS extensions (HTTPS client certificate support) and avoid installing libgnutls, append the option `GNUTLSFLAG=1` to the make command when you build Ulfius:
```shell
$ make GNUTLSFLAG=1
```
If GNU TLS extensions are disabled, `libgnutls-dev` is no longer mandatory for install. However, this will also disable websocket support, since it depends on libgnutls.
To disable websocket implementation, append the option `WEBSOCKETFLAG=1` to the make command when you build Ulfius:
```shell
$ make WEBSOCKETFLAG=1
```
To disable Yder library (you will no longer have log messages available!), append the option `YDERFLAG=1` to the make command when you build Ulfius:
```shell
$ make YDERFLAG=1
```
To disable uwsc build, append the option `UWSCFLAG=1` to the make command when you build Ulfius:
```shell
$ make UWSCFLAG=1
```
To disable two or more libraries, append options, example:
```shell
$ make CURLFLAG=1 JANSSONFLAG=1
```
#### Install Ulfius as a static archive
Install Ulfius as a static archive, `libulfius.a`, use the make commands `make static*`:
```shell
$ cd src
$ make static && sudo make static-install # or make DESTDIR=/tmp static-install if you want to install in `/tmp/lib`
```
#### Enable embedded systems flags
To build Ulfius on [FreeRTOS](https://www.freertos.org/), append the option `FREERTOSFLAG=1` to the make command when you build Ulfius:
```shell
$ make FREERTOSFLAG=1
```
To build Ulfius with the [LWIP](https://savannah.nongnu.org/projects/lwip/) library, append the option `LWIPFLAG=1` to the make command when you build Ulfius:
```shell
$ make LWIPFLAG=1
```
Those two options are exclusive, you can't use them both at the same time.
#### Installation directory
By default, the shared libraries and the header files will be installed in the `/usr/local` location. To change this setting, you can modify the `DESTDIR` value in the `src/Makefile`, `lib/orcania/src/Makefile` and `lib/yder/src/Makefile` files.
```shell
$ make DESTDIR=/tmp install # to install ulfius in /tmp/lib for example
```
You can install Ulfius without root permission if your user has write access to `$(DESTDIR)`.
A `ldconfig` command is executed at the end of the install, it will probably fail if you don't have root permission, but this is harmless.
If you choose to install Ulfius in another directory, you must set your environment variable `LD_LIBRARY_PATH` properly.
#### Install uwsc
uwsc is a small command-line tool to connect to websocket services. To install uwsc only, you can use the `Makefile` in the `uwsc/` directory:
```shell
$ cd ulfius/uwsc
$ make && sudo make install
```
This will compile and install uwsc in `/usr/local/bin`, to install it in another directory, you can change the value of `DESTDIR`.
### CMake - Multi architecture
You can build Ulfius library using CMake, example:
```shell
$ mkdir build
$ cd build
$ cmake ..
$ make && sudo make install
```
The available options for CMake are:
- `-DWITH_JANSSON=[on|off]` (default `on`): Build with Jansson dependency
- `-DWITH_CURL=[on|off]` (default `on`): Build with libcurl dependency
- `-DWITH_GNUTLS=[on|off]` (default `on`): Build with GNU TLS extensions (HTTPS client certificate support), requires GnuTLS library.
- `-DWITH_WEBSOCKET=[on|off]` (default `on`): Build with websocket functions, not available for Windows, requires libmicrohttpd 0.9.53 minimum.
- `-DWITH_JOURNALD=[on|off]` (default `on`): Build with journald (SystemD) support for logging
- `-DWITH_YDER=[on|off]` (default `on`): Build with Yder library for logging messages
- `-DBUILD_UWSC=[on|off]` (default `on`): Build uwsc
- `-DBUILD_STATIC=[on|off]` (default `off`): Build the static archive in addition to the shared library
- `-DBUILD_ULFIUS_TESTING=[on|off]` (default `off`): Build unit tests
- `-DBUILD_ULFIUS_DOCUMENTATION=[on|off]` (default `off`): Build the documentation, doxygen is required
- `-DINSTALL_HEADER=[on|off]` (default `on`): Install header file `ulfius.h`
- `-DBUILD_RPM=[on|off]` (default `off`): Build RPM package when running `make package`
- `-DCMAKE_BUILD_TYPE=[Debug|Release]` (default `Release`): Compile with debugging symbols or not
ulfius-2.7.7/LICENSE 0000664 0000000 0000000 00000063536 14154204040 0014052 0 ustar 00root root 0000000 0000000 GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
(This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.)
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
{description}
Copyright (C) {year} {fullname}
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
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random
Hacker.
{signature of Ty Coon}, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
ulfius-2.7.7/Makefile 0000664 0000000 0000000 00000003374 14154204040 0014477 0 ustar 00root root 0000000 0000000 #
# Ulfius Framework
#
# Makefile used to build all programs
#
# Copyright 2014-2017 Nicolas Mora
#
# This program 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;
# version 2.1 of the License.
#
# 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 GENERAL PUBLIC LICENSE for more details.
#
# You should have received a copy of the GNU General Public
# License along with this library. If not, see .
#
LIBULFIUS_LOCATION=./src
EXAMPLES_LOCATION=./example_programs
ifndef UWSCFLAG
UWSC_LOCATION=./tools/uwsc
endif
TESTS_LOCATION=./test
all:
cd $(LIBULFIUS_LOCATION) && $(MAKE) $*
ifndef UWSCFLAG
cd $(UWSC_LOCATION) && $(MAKE) $*
endif
debug:
cd $(LIBULFIUS_LOCATION) && $(MAKE) debug $*
ifndef UWSCFLAG
cd $(UWSC_LOCATION) && $(MAKE) debug $*
endif
clean:
cd $(LIBULFIUS_LOCATION) && $(MAKE) clean
cd $(EXAMPLES_LOCATION) && $(MAKE) clean
ifndef UWSCFLAG
cd $(UWSC_LOCATION) && $(MAKE) clean
endif
cd $(TESTS_LOCATION) && $(MAKE) clean
cd $(TESTS_LOCATION)/autobahn && $(MAKE) clean
rm -rf doc/html $(TESTS_LOCATION)/cert/server.* $(TESTS_LOCATION)/cert/root* $(TESTS_LOCATION)/cert/client*
examples:
cd $(EXAMPLES_LOCATION) && $(MAKE) $*
install:
cd $(LIBULFIUS_LOCATION) && $(MAKE) install
ifndef UWSCFLAG
cd $(UWSC_LOCATION) && $(MAKE) install
endif
uninstall:
cd $(LIBULFIUS_LOCATION) && $(MAKE) uninstall
ifndef UWSCFLAG
cd $(UWSC_LOCATION) && $(MAKE) uninstall
endif
check:
cd $(TESTS_LOCATION) && $(MAKE)
doxygen:
doxygen doc/doxygen.cfg
ulfius-2.7.7/README.md 0000664 0000000 0000000 00000012413 14154204040 0014310 0 ustar 00root root 0000000 0000000 # Ulfius HTTP Framework


[](https://bestpractices.coreinfrastructure.org/projects/3195)
HTTP Framework for REST Applications in C.
Based on [GNU Libmicrohttpd](https://www.gnu.org/software/libmicrohttpd/) for the backend web server, [Jansson](http://www.digip.org/jansson/) for the json manipulation library, and [Libcurl](http://curl.haxx.se/libcurl/) for the http/smtp client API.
Used to facilitate creation of web applications in C programs with a small memory footprint, as in embedded systems applications.
You can create webservices in HTTP or HTTPS mode, stream data, or implement server websockets.
## Hello World! example application
The source code of a hello world using Ulfius is the following:
```C
/**
* test.c
* Small Hello World! example
* to compile with gcc, run the following command
* gcc -o test test.c -lulfius
*/
#include
#include
#define PORT 8080
/**
* Callback function for the web application on /helloworld url call
*/
int callback_hello_world (const struct _u_request * request, struct _u_response * response, void * user_data) {
ulfius_set_string_body_response(response, 200, "Hello World!");
return U_CALLBACK_CONTINUE;
}
/**
* main function
*/
int main(void) {
struct _u_instance instance;
// Initialize instance with the port number
if (ulfius_init_instance(&instance, PORT, NULL, NULL) != U_OK) {
fprintf(stderr, "Error ulfius_init_instance, abort\n");
return(1);
}
// Endpoint list declaration
ulfius_add_endpoint_by_val(&instance, "GET", "/helloworld", NULL, 0, &callback_hello_world, NULL);
// Start the framework
if (ulfius_start_framework(&instance) == U_OK) {
printf("Start framework on port %d\n", instance.port);
// Wait for the user to press on the console to quit the application
getchar();
} else {
fprintf(stderr, "Error starting framework\n");
}
printf("End framework\n");
ulfius_stop_framework(&instance);
ulfius_clean_instance(&instance);
return 0;
}
```
## Main features
### Webservice
- Create a webservice in a separate thread, the endpoint is identified by its method (ex: `GET`, `POST`, `PUT`, `DELETE`, etc.) and its URL path with its optional parameters (ex: `/api/doc/@id`). The webservice is executed in a callback function.
- Stream large amount of data with a reduced memory footprint.
- Websocket service, the websocket messages exchange is executed in dedicated callback functions.
### Client requests
- Client http[s] and smtp requests execution, the response is parsed in a dedicated structure.
- Client websocket request execution, the websocket messages exchange is executed in dedicated callback functions.
### Websockets
- Create a websocket service application
- Create websocket client application
- CLI to connect to a remote websocket: [uwsc](https://github.com/babelouest/ulfius/tree/master/tools/uwsc)
## Installation
See [INSTALL.md](INSTALL.md) file for installation details
## Documentation
See [API.md](API.md) file for API documentation details
See the [online documentation](https://babelouest.github.io/ulfius/) for a doxygen format of the API documentation.
## Example programs source code
Example programs are available to understand the different functionalities available, see [example_programs](https://github.com/babelouest/ulfius/blob/master/example_programs) folder for detailed sample source codes and documentation.
## Example callback functions
Example callback functions are available in the folder [example_callbacks](https://github.com/babelouest/ulfius/blob/master/example_callbacks). The example callback functions available are:
- static file server: to provide static files of a specific folder
- oauth2 bearer: to check the validity of a Oauth2 bearer jwt token. Requires [libjwt](https://github.com/benmcollins/libjwt).
## Projects using Ulfius framework
- [Glewlwyd](https://github.com/babelouest/glewlwyd), a lightweight SSO server that provides OAuth2 and OpenID Connect authentication protocols
- [Le Biniou](https://biniou.net/), user-friendly yet powerful music visualization / VJing tool
- [Angharad](https://github.com/babelouest/angharad), House automation system for ZWave and other types of devices
- [Hutch](https://github.com/babelouest/hutch), a safe locker for passwords and other secrets, using JavaScript client side encryption only
- [Taliesin](https://github.com/babelouest/taliesin), a lightweight audio streaming server
- [Taulas Raspberry Pi Serial interface](https://github.com/babelouest/taulas/tree/master/taulas_raspberrypi_serial), an interface for Arduino devices that implement [Taulas](https://github.com/babelouest/taulas/) protocol, a house automation protocol for Angharad
## Questions, problems ?
I'm open for questions and suggestions, feel free to open an [issue](https://github.com/babelouest/ulfius/issues), a [pull request](https://github.com/babelouest/ulfius/pulls) or send me an [e-mail](mailto:mail@babelouest.org) if you feel like it!
You can visit the IRC channel #ulfius on the [Libera.âChat](https://libera.chat/) network.
ulfius-2.7.7/cmake-modules/ 0000775 0000000 0000000 00000000000 14154204040 0015556 5 ustar 00root root 0000000 0000000 ulfius-2.7.7/cmake-modules/CMakeUninstall.cmake.in 0000664 0000000 0000000 00000002064 14154204040 0022041 0 ustar 00root root 0000000 0000000 if (NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt")
endif (NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files)
string(REGEX REPLACE "\n" ";" files "${files}")
foreach (file ${files})
message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
if (IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
exec_program(
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
OUTPUT_VARIABLE rm_out
RETURN_VALUE rm_retval
)
if (NOT "${rm_retval}" STREQUAL 0)
message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
endif (NOT "${rm_retval}" STREQUAL 0)
else (IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
endif (IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
endforeach (file)
ulfius-2.7.7/cmake-modules/CTestCustom.cmake.in 0000664 0000000 0000000 00000000142 14154204040 0021377 0 ustar 00root root 0000000 0000000 string(REPLACE ";" " " TESTS "@TESTS@")
set(CTEST_CUSTOM_PRE_TEST "@CMAKE_MAKE_PROGRAM@ ${TESTS}") ulfius-2.7.7/cmake-modules/DownloadProject.CMakeLists.cmake.in 0000664 0000000 0000000 00000001205 14154204040 0024257 0 ustar 00root root 0000000 0000000 # Distributed under the OSI-approved MIT License. See accompanying
# file LICENSE or https://github.com/Crascit/DownloadProject for details.
cmake_minimum_required(VERSION 2.8.12)
project(${DL_ARGS_PROJ}-download NONE)
include(ExternalProject)
ExternalProject_Add(${DL_ARGS_PROJ}-download
${DL_ARGS_UNPARSED_ARGUMENTS}
SOURCE_DIR "${DL_ARGS_SOURCE_DIR}"
BINARY_DIR "${DL_ARGS_BINARY_DIR}"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
)
ulfius-2.7.7/cmake-modules/DownloadProject.cmake 0000664 0000000 0000000 00000017553 14154204040 0021671 0 ustar 00root root 0000000 0000000 # Distributed under the OSI-approved MIT License. See accompanying
# file LICENSE or https://github.com/Crascit/DownloadProject for details.
#
# MODULE: DownloadProject
#
# PROVIDES:
# download_project( PROJ projectName
# [PREFIX prefixDir]
# [DOWNLOAD_DIR downloadDir]
# [SOURCE_DIR srcDir]
# [BINARY_DIR binDir]
# [QUIET]
# ...
# )
#
# Provides the ability to download and unpack a tarball, zip file, git repository,
# etc. at configure time (i.e. when the cmake command is run). How the downloaded
# and unpacked contents are used is up to the caller, but the motivating case is
# to download source code which can then be included directly in the build with
# add_subdirectory() after the call to download_project(). Source and build
# directories are set up with this in mind.
#
# The PROJ argument is required. The projectName value will be used to construct
# the following variables upon exit (obviously replace projectName with its actual
# value):
#
# projectName_SOURCE_DIR
# projectName_BINARY_DIR
#
# The SOURCE_DIR and BINARY_DIR arguments are optional and would not typically
# need to be provided. They can be specified if you want the downloaded source
# and build directories to be located in a specific place. The contents of
# projectName_SOURCE_DIR and projectName_BINARY_DIR will be populated with the
# locations used whether you provide SOURCE_DIR/BINARY_DIR or not.
#
# The DOWNLOAD_DIR argument does not normally need to be set. It controls the
# location of the temporary CMake build used to perform the download.
#
# The PREFIX argument can be provided to change the base location of the default
# values of DOWNLOAD_DIR, SOURCE_DIR and BINARY_DIR. If all of those three arguments
# are provided, then PREFIX will have no effect. The default value for PREFIX is
# CMAKE_BINARY_DIR.
#
# The QUIET option can be given if you do not want to show the output associated
# with downloading the specified project.
#
# In addition to the above, any other options are passed through unmodified to
# ExternalProject_Add() to perform the actual download, patch and update steps.
# The following ExternalProject_Add() options are explicitly prohibited (they
# are reserved for use by the download_project() command):
#
# CONFIGURE_COMMAND
# BUILD_COMMAND
# INSTALL_COMMAND
# TEST_COMMAND
#
# Only those ExternalProject_Add() arguments which relate to downloading, patching
# and updating of the project sources are intended to be used. Also note that at
# least one set of download-related arguments are required.
#
# If using CMake 3.2 or later, the UPDATE_DISCONNECTED option can be used to
# prevent a check at the remote end for changes every time CMake is run
# after the first successful download. See the documentation of the ExternalProject
# module for more information. It is likely you will want to use this option if it
# is available to you. Note, however, that the ExternalProject implementation contains
# bugs which result in incorrect handling of the UPDATE_DISCONNECTED option when
# using the URL download method or when specifying a SOURCE_DIR with no download
# method. Fixes for these have been created, the last of which is scheduled for
# inclusion in CMake 3.8.0. Details can be found here:
#
# https://gitlab.kitware.com/cmake/cmake/commit/bdca68388bd57f8302d3c1d83d691034b7ffa70c
# https://gitlab.kitware.com/cmake/cmake/issues/16428
#
# If you experience build errors related to the update step, consider avoiding
# the use of UPDATE_DISCONNECTED.
#
# EXAMPLE USAGE:
#
# include(DownloadProject)
# download_project(PROJ googletest
# GIT_REPOSITORY https://github.com/google/googletest.git
# GIT_TAG master
# UPDATE_DISCONNECTED 1
# QUIET
# )
#
# add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR})
#
#========================================================================================
set(_DownloadProjectDir "${CMAKE_CURRENT_LIST_DIR}")
include(CMakeParseArguments)
function(download_project)
set(options QUIET)
set(oneValueArgs
PROJ
PREFIX
DOWNLOAD_DIR
SOURCE_DIR
BINARY_DIR
# Prevent the following from being passed through
CONFIGURE_COMMAND
BUILD_COMMAND
INSTALL_COMMAND
TEST_COMMAND
)
set(multiValueArgs "")
cmake_parse_arguments(DL_ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
# Hide output if requested
if (DL_ARGS_QUIET)
set(OUTPUT_QUIET "OUTPUT_QUIET")
else()
unset(OUTPUT_QUIET)
message(STATUS "Downloading/updating ${DL_ARGS_PROJ}")
endif()
# Set up where we will put our temporary CMakeLists.txt file and also
# the base point below which the default source and binary dirs will be.
# The prefix must always be an absolute path.
if (NOT DL_ARGS_PREFIX)
set(DL_ARGS_PREFIX "${CMAKE_BINARY_DIR}")
else()
get_filename_component(DL_ARGS_PREFIX "${DL_ARGS_PREFIX}" ABSOLUTE
BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}")
endif()
if (NOT DL_ARGS_DOWNLOAD_DIR)
set(DL_ARGS_DOWNLOAD_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-download")
endif()
# Ensure the caller can know where to find the source and build directories
if (NOT DL_ARGS_SOURCE_DIR)
set(DL_ARGS_SOURCE_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-src")
endif()
if (NOT DL_ARGS_BINARY_DIR)
set(DL_ARGS_BINARY_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-build")
endif()
set(${DL_ARGS_PROJ}_SOURCE_DIR "${DL_ARGS_SOURCE_DIR}" PARENT_SCOPE)
set(${DL_ARGS_PROJ}_BINARY_DIR "${DL_ARGS_BINARY_DIR}" PARENT_SCOPE)
# The way that CLion manages multiple configurations, it causes a copy of
# the CMakeCache.txt to be copied across due to it not expecting there to
# be a project within a project. This causes the hard-coded paths in the
# cache to be copied and builds to fail. To mitigate this, we simply
# remove the cache if it exists before we configure the new project. It
# is safe to do so because it will be re-generated. Since this is only
# executed at the configure step, it should not cause additional builds or
# downloads.
file(REMOVE "${DL_ARGS_DOWNLOAD_DIR}/CMakeCache.txt")
# Create and build a separate CMake project to carry out the download.
# If we've already previously done these steps, they will not cause
# anything to be updated, so extra rebuilds of the project won't occur.
# Make sure to pass through CMAKE_MAKE_PROGRAM in case the main project
# has this set to something not findable on the PATH.
configure_file("${_DownloadProjectDir}/DownloadProject.CMakeLists.cmake.in"
"${DL_ARGS_DOWNLOAD_DIR}/CMakeLists.txt")
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}"
-D "CMAKE_MAKE_PROGRAM:FILE=${CMAKE_MAKE_PROGRAM}"
.
RESULT_VARIABLE result
${OUTPUT_QUIET}
WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}"
)
if(result)
message(FATAL_ERROR "CMake step for ${DL_ARGS_PROJ} failed: ${result}")
endif()
execute_process(COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
${OUTPUT_QUIET}
WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}"
)
if(result)
message(FATAL_ERROR "Build step for ${DL_ARGS_PROJ} failed: ${result}")
endif()
endfunction()
ulfius-2.7.7/cmake-modules/FindCheck.cmake 0000664 0000000 0000000 00000005041 14154204040 0020376 0 ustar 00root root 0000000 0000000 #.rst:
# FindCheck
# -----------
#
# Find Check
#
# Find Check headers and libraries.
#
# ::
#
# CHECK_FOUND - True if Check found.
# CHECK_INCLUDE_DIRS - Where to find check.h.
# CHECK_LIBRARIES - List of libraries when using Check.
# CHECK_VERSION_STRING - The version of Check found.
#=============================================================================
# Copyright 2018 Silvio Clecio
#
# This program 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;
# version 2.1 of the License.
#
# 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 GENERAL PUBLIC LICENSE for more details.
#
# You should have received a copy of the GNU General Public
# License along with this library. If not, see .
#=============================================================================
# Sat Jan 20 23:33:47 -03 2018
find_package(PkgConfig QUIET)
pkg_check_modules(PC_CHECK QUIET check)
find_path(CHECK_INCLUDE_DIR
NAMES check.h
HINTS ${PC_CHECK_INCLUDEDIR} ${PC_CHECK_INCLUDE_DIRS})
find_library(CHECK_LIBRARY
NAMES check libcheck
HINTS ${PC_CHECK_LIBDIR} ${PC_CHECK_LIBRARY_DIRS})
if (PC_CHECK_VERSION)
set(CHECK_VERSION_STRING ${PC_CHECK_VERSION})
elseif (CHECK_INCLUDE_DIR AND EXISTS "${CHECK_INCLUDE_DIR}/check.h")
set(check_version_list MAJOR MINOR MICRO)
foreach (v ${check_version_list})
set(regex_check_version "^#define CHECK_${v}_VERSION +\\(?([0-9]+)\\)?$")
file(STRINGS "${CHECK_INCLUDE_DIR}/check.h" check_version_${v} REGEX "${regex_check_version}")
string(REGEX REPLACE "${regex_check_version}" "\\1" check_version_${v} "${check_version_${v}}")
unset(regex_check_version)
endforeach ()
set(CHECK_VERSION_STRING "${check_version_MAJOR}.${check_version_MINOR}.${check_version_MICRO}")
foreach (v check_version_list)
unset(check_version_${v})
endforeach ()
unset(check_version_list)
endif ()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Check
REQUIRED_VARS CHECK_LIBRARY CHECK_INCLUDE_DIR
VERSION_VAR CHECK_VERSION_STRING)
if (CHECK_FOUND)
set(CHECK_LIBRARIES ${CHECK_LIBRARY})
set(CHECK_INCLUDE_DIRS ${CHECK_INCLUDE_DIR})
endif ()
mark_as_advanced(CHECK_INCLUDE_DIR CHECK_LIBRARY) ulfius-2.7.7/cmake-modules/FindJansson.cmake 0000664 0000000 0000000 00000004507 14154204040 0021002 0 ustar 00root root 0000000 0000000 #.rst:
# FindJansson
# -----------
#
# Find Jansson
#
# Find Jansson headers and libraries.
#
# ::
#
# JANSSON_FOUND - True if Jansson found.
# JANSSON_INCLUDE_DIRS - Where to find jansson.h.
# JANSSON_LIBRARIES - List of libraries when using Jansson.
# JANSSON_VERSION_STRING - The version of Jansson found.
#=============================================================================
# Copyright 2018 Silvio Clecio
#
# This program 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;
# version 2.1 of the License.
#
# 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 GENERAL PUBLIC LICENSE for more details.
#
# You should have received a copy of the GNU General Public
# License along with this library. If not, see .
#=============================================================================
# Sat Jan 20 12:32:26 -03 2018
find_package(PkgConfig QUIET)
pkg_check_modules(PC_JANSSON QUIET jansson)
find_path(JANSSON_INCLUDE_DIR
NAMES jansson.h
HINTS ${PC_JANSSON_INCLUDEDIR} ${PC_JANSSON_INCLUDE_DIRS})
find_library(JANSSON_LIBRARY
NAMES jansson libjansson
HINTS ${PC_JANSSON_LIBDIR} ${PC_JANSSON_LIBRARY_DIRS})
if (PC_JANSSON_VERSION)
set(JANSSON_VERSION_STRING ${PC_JANSSON_VERSION})
elseif (JANSSON_INCLUDE_DIR AND EXISTS "${JANSSON_INCLUDE_DIR}/jansson.h")
set(regex_jansson_version "^#define[ \t]+JANSSON_VERSION[ \t]+\"([^\"]+)\".*")
file(STRINGS "${JANSSON_INCLUDE_DIR}/jansson.h" jansson_version REGEX "${regex_jansson_version}")
string(REGEX REPLACE "${regex_jansson_version}" "\\1" JANSSON_VERSION_STRING "${jansson_version}")
unset(regex_jansson_version)
unset(jansson_version)
endif ()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Jansson
REQUIRED_VARS JANSSON_LIBRARY JANSSON_INCLUDE_DIR
VERSION_VAR JANSSON_VERSION_STRING)
if (JANSSON_FOUND)
set(JANSSON_LIBRARIES ${JANSSON_LIBRARY})
set(JANSSON_INCLUDE_DIRS ${JANSSON_INCLUDE_DIR})
endif ()
mark_as_advanced(JANSSON_INCLUDE_DIR JANSSON_LIBRARY) ulfius-2.7.7/cmake-modules/FindMHD.cmake 0000664 0000000 0000000 00000005410 14154204040 0017771 0 ustar 00root root 0000000 0000000 #.rst:
# FindMHD
# -----------
#
# Find libmicrohttpd
#
# Find libmicrohttpd headers and libraries.
#
# ::
#
# MHD_FOUND - True if libmicrohttpd found.
# MHD_INCLUDE_DIRS - Where to find microhttpd.h.
# MHD_LIBRARIES - List of libraries when using libmicrohttpd.
# MHD_VERSION_STRING - The version of libmicrohttpd found.
#=============================================================================
# Copyright 2018 Nicolas Mora
#
# This program 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;
# version 2.1 of the License.
#
# 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 GENERAL PUBLIC LICENSE for more details.
#
# You should have received a copy of the GNU General Public
# License along with this library. If not, see .
#=============================================================================
find_package(PkgConfig QUIET)
pkg_check_modules(PC_MHD QUIET libmicrohttpd)
find_path(MHD_INCLUDE_DIR
NAMES microhttpd.h
HINTS ${PC_MHD_INCLUDEDIR} ${PC_MHD_INCLUDE_DIRS})
find_library(MHD_LIBRARY
NAMES libmicrohttpd microhttpd
HINTS ${PC_MHD_LIBDIR} ${PC_MHD_LIBRARY_DIRS})
if (PC_MHD_VERSION)
set(MHD_VERSION_STRING ${PC_MHD_VERSION})
elseif (MHD_INCLUDE_DIR AND EXISTS "${MHD_INCLUDE_DIR}/microhttpd.h")
set(regex_mhd_version "^#define[ \t]+MHD_VERSION[ \t]+([^\"]+).*")
file(STRINGS "${MHD_INCLUDE_DIR}/microhttpd.h" mhd_version REGEX "${regex_mhd_version}")
string(REGEX REPLACE "${regex_mhd_version}" "\\1" MHD_VERSION_NUM "${mhd_version}")
unset(regex_mhd_version)
unset(mhd_version)
# parse MHD_VERSION from numerical format 0x12345678 to string format "12.34.56.78" so the version value can be compared to the one returned by pkg-config
string(SUBSTRING ${MHD_VERSION_NUM} 2 2 MHD_VERSION_STRING_MAJOR)
string(SUBSTRING ${MHD_VERSION_NUM} 4 2 MHD_VERSION_STRING_MINOR)
string(SUBSTRING ${MHD_VERSION_NUM} 6 2 MHD_VERSION_STRING_REVISION)
string(SUBSTRING ${MHD_VERSION_NUM} 8 2 MHD_VERSION_STRING_PATCH)
set(MHD_VERSION_STRING "${MHD_VERSION_STRING_MAJOR}.${MHD_VERSION_STRING_MINOR}.${MHD_VERSION_STRING_REVISION}.${MHD_VERSION_STRING_PATCH}")
endif ()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(MHD
REQUIRED_VARS MHD_LIBRARY MHD_INCLUDE_DIR
VERSION_VAR MHD_VERSION_STRING)
if (MHD_FOUND)
set(MHD_LIBRARIES ${MHD_LIBRARY})
set(MHD_INCLUDE_DIRS ${MHD_INCLUDE_DIR})
endif ()
mark_as_advanced(MHD_INCLUDE_DIR MHD_LIBRARY)
ulfius-2.7.7/cmake-modules/FindOrcania.cmake 0000664 0000000 0000000 00000005435 14154204040 0020744 0 ustar 00root root 0000000 0000000 #.rst:
# FindOrcania
# -----------
#
# Find Orcania
#
# Find Orcania headers and libraries.
#
# ::
#
# ORCANIA_FOUND - True if Orcania found.
# ORCANIA_INCLUDE_DIRS - Where to find orcania.h.
# ORCANIA_LIBRARIES - List of libraries when using Orcania.
# ORCANIA_VERSION_STRING - The version of Orcania found.
#=============================================================================
# Copyright 2018 Silvio Clecio
# Copyright 2018 Nicolas Mora
#
# This program 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;
# version 2.1 of the License.
#
# 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 GENERAL PUBLIC LICENSE for more details.
#
# You should have received a copy of the GNU General Public
# License along with this library. If not, see .
#=============================================================================
find_package(PkgConfig QUIET)
pkg_check_modules(PC_ORCANIA QUIET liborcania)
find_path(ORCANIA_INCLUDE_DIR
NAMES orcania.h
HINTS ${PC_ORCANIA_INCLUDEDIR} ${PC_ORCANIA_INCLUDE_DIRS})
find_library(ORCANIA_LIBRARY
NAMES orcania liborcania
HINTS ${PC_ORCANIA_LIBDIR} ${PC_ORCANIA_LIBRARY_DIRS})
set(ORCANIA_VERSION_STRING 0.0.0)
if (PC_ORCANIA_VERSION)
set(ORCANIA_VERSION_STRING ${PC_ORCANIA_VERSION})
elseif (ORCANIA_INCLUDE_DIR AND EXISTS "${ORCANIA_INCLUDE_DIR}/orcania.h")
set(regex_orcania_version "^#define[ \t]+ORCANIA_VERSION[ \t]+([^\"]+).*")
file(STRINGS "${ORCANIA_INCLUDE_DIR}/orcania.h" orcania_version REGEX "${regex_orcania_version}")
string(REGEX REPLACE "${regex_orcania_version}" "\\1" ORCANIA_VERSION_STRING "${orcania_version}")
unset(regex_orcania_version)
unset(orcania_version)
if (NOT ORCANIA_VERSION_STRING)
set(regex_orcania_version "^#define[ \t]+ORCANIA_VERSION[ \t]+([^\"]+).*")
file(STRINGS "${ORCANIA_INCLUDE_DIR}/orcania-cfg.h" orcania_version REGEX "${regex_orcania_version}")
string(REGEX REPLACE "${regex_orcania_version}" "\\1" ORCANIA_VERSION_STRING "${orcania_version}")
unset(regex_orcania_version)
unset(orcania_version)
endif ()
endif ()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Orcania
REQUIRED_VARS ORCANIA_LIBRARY ORCANIA_INCLUDE_DIR
VERSION_VAR ORCANIA_VERSION_STRING)
if (ORCANIA_FOUND)
set(ORCANIA_LIBRARIES ${ORCANIA_LIBRARY})
set(ORCANIA_INCLUDE_DIRS ${ORCANIA_INCLUDE_DIR})
endif ()
mark_as_advanced(ORCANIA_INCLUDE_DIR ORCANIA_LIBRARY)
ulfius-2.7.7/cmake-modules/FindSubunit.cmake 0000664 0000000 0000000 00000003642 14154204040 0021017 0 ustar 00root root 0000000 0000000 #.rst:
# FindSubunit
# -----------
#
# Find Subunit
#
# Find Subunit headers and libraries.
#
# ::
#
# SUBUNIT_FOUND - True if Subunit found.
# SUBUNIT_INCLUDE_DIRS - Where to find subunit/child.h.
# SUBUNIT_LIBRARIES - List of libraries when using Subunit.
# SUBUNIT_VERSION_STRING - The version of Subunit found.
#=============================================================================
# Copyright 2018 Silvio Clecio
#
# This program 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;
# version 2.1 of the License.
#
# 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 GENERAL PUBLIC LICENSE for more details.
#
# You should have received a copy of the GNU General Public
# License along with this library. If not, see .
#=============================================================================
# Fri Jan 19 22:27:51 -03 2018
find_package(PkgConfig QUIET)
pkg_check_modules(PC_SUBUNIT QUIET libsubunit)
set(SUBUNIT_VERSION_STRING "${PC_SUBUNIT_VERSION}")
find_path(SUBUNIT_INCLUDE_DIR
NAMES child.h
HINTS ${PC_SUBUNIT_INCLUDEDIR} ${PC_SUBUNIT_INCLUDE_DIRS}
PATH_SUFFIXES subunit)
find_library(SUBUNIT_LIBRARY
NAMES subunit libsubunit
HINTS ${PC_SUBUNIT_LIBDIR} ${PC_SUBUNIT_LIBRARY_DIRS})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Subunit
REQUIRED_VARS SUBUNIT_LIBRARY SUBUNIT_INCLUDE_DIR
VERSION_VAR SUBUNIT_VERSION_STRING)
if (SUBUNIT_FOUND)
set(SUBUNIT_LIBRARIES ${SUBUNIT_LIBRARY})
set(SUBUNIT_INCLUDE_DIRS ${SUBUNIT_INCLUDE_DIR})
endif ()
mark_as_advanced(SUBUNIT_INCLUDE_DIR SUBUNIT_LIBRARY) ulfius-2.7.7/cmake-modules/FindYder.cmake 0000664 0000000 0000000 00000005141 14154204040 0020265 0 ustar 00root root 0000000 0000000 #.rst:
# FindYder
# -----------
#
# Find Yder
#
# Find Yder headers and libraries.
#
# ::
#
# YDER_FOUND - True if Yder found.
# YDER_INCLUDE_DIRS - Where to find yder.h.
# YDER_LIBRARIES - List of libraries when using Yder.
# YDER_VERSION_STRING - The version of Yder found.
#=============================================================================
# Copyright 2018 Nicolas Mora
# Copyright 2018 Silvio Clecio
#
# This program 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;
# version 2.1 of the License.
#
# 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 GENERAL PUBLIC LICENSE for more details.
#
# You should have received a copy of the GNU General Public
# License along with this library. If not, see .
#=============================================================================
find_package(PkgConfig QUIET)
pkg_check_modules(PC_YDER QUIET libyder)
find_path(YDER_INCLUDE_DIR
NAMES yder.h
HINTS ${PC_YDER_INCLUDEDIR} ${PC_YDER_INCLUDE_DIRS})
find_library(YDER_LIBRARY
NAMES yder libyder
HINTS ${PC_YDER_LIBDIR} ${PC_YDER_LIBRARY_DIRS})
set(YDER_VERSION_STRING 0.0.0)
if (PC_YDER_VERSION)
set(YDER_VERSION_STRING ${PC_YDER_VERSION})
elseif (YDER_INCLUDE_DIR AND EXISTS "${YDER_INCLUDE_DIR}/yder.h")
set(regex_yder_version "^#define[ \t]+YDER_VERSION[ \t]+([^\"]+).*")
file(STRINGS "${YDER_INCLUDE_DIR}/yder.h" yder_version REGEX "${regex_yder_version}")
string(REGEX REPLACE "${regex_yder_version}" "\\1" YDER_VERSION_STRING "${yder_version}")
unset(regex_yder_version)
unset(yder_version)
if (NOT YDER_VERSION_STRING)
set(regex_yder_version "^#define[ \t]+YDER_VERSION[ \t]+([^\"]+).*")
file(STRINGS "${YDER_INCLUDE_DIR}/yder-cfg.h" yder_version REGEX "${regex_yder_version}")
string(REGEX REPLACE "${regex_yder_version}" "\\1" YDER_VERSION_STRING "${yder_version}")
unset(regex_yder_version)
unset(yder_version)
endif ()
endif ()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Yder
REQUIRED_VARS YDER_LIBRARY YDER_INCLUDE_DIR
VERSION_VAR YDER_VERSION_STRING)
if (YDER_FOUND)
set(YDER_LIBRARIES ${YDER_LIBRARY})
set(YDER_INCLUDE_DIRS ${YDER_INCLUDE_DIR})
endif ()
mark_as_advanced(YDER_INCLUDE_DIR YDER_LIBRARY)
ulfius-2.7.7/doc/ 0000775 0000000 0000000 00000000000 14154204040 0013575 5 ustar 00root root 0000000 0000000 ulfius-2.7.7/doc/doxygen.cfg 0000664 0000000 0000000 00000321400 14154204040 0015733 0 ustar 00root root 0000000 0000000 # Doxyfile 1.8.13
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
#
# All text after a double hash (##) is considered a comment and is placed in
# front of the TAG it is preceding.
#
# All text after a single hash (#) is considered a comment and will be ignored.
# The format is:
# TAG = value [value, ...]
# For lists, items can also be appended using:
# TAG += value [value, ...]
# Values that contain spaces should be placed between quotes (\" \").
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
# This tag specifies the encoding used for all characters in the config file
# that follow. The default is UTF-8 which is also the encoding used for all text
# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
# for the list of possible encodings.
# The default value is: UTF-8.
DOXYFILE_ENCODING = UTF-8
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
# double-quotes, unless you are using Doxywizard) that should identify the
# project for which the documentation is generated. This name is used in the
# title of most generated pages and in a few other places.
# The default value is: My Project.
PROJECT_NAME = "Ulfius"
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER =
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
# quick idea about the purpose of the project. Keep the description short.
PROJECT_BRIEF = "HTTP Framework for REST Applications in C"
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
# in the documentation. The maximum height of the logo should not exceed 55
# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
# the logo to the output directory.
PROJECT_LOGO =
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
# into which the generated documentation will be written. If a relative path is
# entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used.
OUTPUT_DIRECTORY = "doc"
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and
# will distribute the generated files over these directories. Enabling this
# option can be useful when feeding doxygen a huge amount of source files, where
# putting all generated files in the same directory would otherwise causes
# performance problems for the file system.
# The default value is: NO.
CREATE_SUBDIRS = NO
# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
# characters to appear in the names of generated files. If set to NO, non-ASCII
# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
# U+3044.
# The default value is: NO.
ALLOW_UNICODE_NAMES = NO
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language.
# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
# Ukrainian and Vietnamese.
# The default value is: English.
OUTPUT_LANGUAGE = English
# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
# descriptions after the members that are listed in the file and class
# documentation (similar to Javadoc). Set to NO to disable this.
# The default value is: YES.
BRIEF_MEMBER_DESC = YES
# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
# description of a member or function before the detailed description
#
# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
# brief descriptions will be completely suppressed.
# The default value is: YES.
REPEAT_BRIEF = YES
# This tag implements a quasi-intelligent brief description abbreviator that is
# used to form the text in various listings. Each string in this list, if found
# as the leading text of the brief description, will be stripped from the text
# and the result, after processing the whole list, is used as the annotated
# text. Otherwise, the brief description is used as-is. If left blank, the
# following values are used ($name is automatically replaced with the name of
# the entity):The $name class, The $name widget, The $name file, is, provides,
# specifies, contains, represents, a, an and the.
ABBREVIATE_BRIEF = "The $name class" \
"The $name widget" \
"The $name file" \
is \
provides \
specifies \
contains \
represents \
a \
an \
the
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
# doxygen will generate a detailed section even if there is only a brief
# description.
# The default value is: NO.
ALWAYS_DETAILED_SEC = NO
# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
# inherited members of a class in the documentation of that class as if those
# members were ordinary class members. Constructors, destructors and assignment
# operators of the base classes will not be shown.
# The default value is: NO.
INLINE_INHERITED_MEMB = NO
# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
# before files name in the file list and in the header files. If set to NO the
# shortest path that makes the file name unique will be used
# The default value is: YES.
FULL_PATH_NAMES = YES
# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
# Stripping is only done if one of the specified strings matches the left-hand
# part of the path. The tag can be used to show relative paths in the file list.
# If left blank the directory from which doxygen is run is used as the path to
# strip.
#
# Note that you can specify absolute paths here, but also relative paths, which
# will be relative from the directory where doxygen is started.
# This tag requires that the tag FULL_PATH_NAMES is set to YES.
STRIP_FROM_PATH =
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
# path mentioned in the documentation of a class, which tells the reader which
# header file to include in order to use a class. If left blank only the name of
# the header file containing the class definition is used. Otherwise one should
# specify the list of include paths that are normally passed to the compiler
# using the -I flag.
STRIP_FROM_INC_PATH =
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
# less readable) file names. This can be useful is your file systems doesn't
# support long names like on DOS, Mac, or CD-ROM.
# The default value is: NO.
SHORT_NAMES = NO
# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
# first line (until the first dot) of a Javadoc-style comment as the brief
# description. If set to NO, the Javadoc-style will behave just like regular Qt-
# style comments (thus requiring an explicit @brief command for a brief
# description.)
# The default value is: NO.
JAVADOC_AUTOBRIEF = NO
# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
# line (until the first dot) of a Qt-style comment as the brief description. If
# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
# requiring an explicit \brief command for a brief description.)
# The default value is: NO.
QT_AUTOBRIEF = NO
# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
# a brief description. This used to be the default behavior. The new default is
# to treat a multi-line C++ comment block as a detailed description. Set this
# tag to YES if you prefer the old behavior instead.
#
# Note that setting this tag to YES also means that rational rose comments are
# not recognized any more.
# The default value is: NO.
MULTILINE_CPP_IS_BRIEF = NO
# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
# documentation from any documented member that it re-implements.
# The default value is: YES.
INHERIT_DOCS = YES
# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
# page for each member. If set to NO, the documentation of a member will be part
# of the file/class/namespace that contains it.
# The default value is: NO.
SEPARATE_MEMBER_PAGES = NO
# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
# uses this value to replace tabs by spaces in code fragments.
# Minimum value: 1, maximum value: 16, default value: 4.
TAB_SIZE = 4
# This tag can be used to specify a number of aliases that act as commands in
# the documentation. An alias has the form:
# name=value
# For example adding
# "sideeffect=@par Side Effects:\n"
# will allow you to put the command \sideeffect (or @sideeffect) in the
# documentation, which will result in a user-defined paragraph with heading
# "Side Effects:". You can put \n's in the value part of an alias to insert
# newlines.
ALIASES =
# This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding "class=itcl::class"
# will allow you to use the command class in the itcl::class meaning.
TCL_SUBST =
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
# only. Doxygen will then generate output that is more tailored for C. For
# instance, some of the names that are used will be different. The list of all
# members will be omitted, etc.
# The default value is: NO.
OPTIMIZE_OUTPUT_FOR_C = YES
# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
# Python sources only. Doxygen will then generate output that is more tailored
# for that language. For instance, namespaces will be presented as packages,
# qualified scopes will look different, etc.
# The default value is: NO.
OPTIMIZE_OUTPUT_JAVA = NO
# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
# sources. Doxygen will then generate output that is tailored for Fortran.
# The default value is: NO.
OPTIMIZE_FOR_FORTRAN = NO
# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
# sources. Doxygen will then generate output that is tailored for VHDL.
# The default value is: NO.
OPTIMIZE_OUTPUT_VHDL = NO
# Doxygen selects the parser to use depending on the extension of the files it
# parses. With this tag you can assign which parser to use for a given
# extension. Doxygen has a built-in mapping, but you can override or extend it
# using this tag. The format is ext=language, where ext is a file extension, and
# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
# Fortran. In the later case the parser tries to guess whether the code is fixed
# or free formatted code, this is the default for Fortran type files), VHDL. For
# instance to make doxygen treat .inc files as Fortran files (default is PHP),
# and .f files as C (default is Fortran), use: inc=Fortran f=C.
#
# Note: For files without extension you can use no_extension as a placeholder.
#
# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
# the files are not read by doxygen.
EXTENSION_MAPPING =
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
# according to the Markdown format, which allows for more readable
# documentation. See http://daringfireball.net/projects/markdown/ for details.
# The output of markdown processing is further processed by doxygen, so you can
# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
# case of backward compatibilities issues.
# The default value is: YES.
MARKDOWN_SUPPORT = YES
# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
# to that level are automatically included in the table of contents, even if
# they do not have an id attribute.
# Note: This feature currently applies only to Markdown headings.
# Minimum value: 0, maximum value: 99, default value: 0.
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
TOC_INCLUDE_HEADINGS = 0
# When enabled doxygen tries to link words that correspond to documented
# classes, or namespaces to their corresponding documentation. Such a link can
# be prevented in individual cases by putting a % sign in front of the word or
# globally by setting AUTOLINK_SUPPORT to NO.
# The default value is: YES.
AUTOLINK_SUPPORT = YES
# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
# to include (a tag file for) the STL sources as input, then you should set this
# tag to YES in order to let doxygen match functions declarations and
# definitions whose arguments contain STL classes (e.g. func(std::string);
# versus func(std::string) {}). This also make the inheritance and collaboration
# diagrams that involve STL classes more complete and accurate.
# The default value is: NO.
BUILTIN_STL_SUPPORT = NO
# If you use Microsoft's C++/CLI language, you should set this option to YES to
# enable parsing support.
# The default value is: NO.
CPP_CLI_SUPPORT = NO
# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
# will parse them like normal C++ but will assume all classes use public instead
# of private inheritance when no explicit protection keyword is present.
# The default value is: NO.
SIP_SUPPORT = NO
# For Microsoft's IDL there are propget and propput attributes to indicate
# getter and setter methods for a property. Setting this option to YES will make
# doxygen to replace the get and set methods by a property in the documentation.
# This will only work if the methods are indeed getting or setting a simple
# type. If this is not the case, or you want to show the methods anyway, you
# should set this option to NO.
# The default value is: YES.
IDL_PROPERTY_SUPPORT = YES
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
# tag is set to YES then doxygen will reuse the documentation of the first
# member in the group (if any) for the other members of the group. By default
# all members of a group must be documented explicitly.
# The default value is: NO.
DISTRIBUTE_GROUP_DOC = NO
# If one adds a struct or class to a group and this option is enabled, then also
# any nested class or struct is added to the same group. By default this option
# is disabled and one has to add nested compounds explicitly via \ingroup.
# The default value is: NO.
GROUP_NESTED_COMPOUNDS = NO
# Set the SUBGROUPING tag to YES to allow class member groups of the same type
# (for instance a group of public functions) to be put as a subgroup of that
# type (e.g. under the Public Functions section). Set it to NO to prevent
# subgrouping. Alternatively, this can be done per class using the
# \nosubgrouping command.
# The default value is: YES.
SUBGROUPING = YES
# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
# are shown inside the group in which they are included (e.g. using \ingroup)
# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
# and RTF).
#
# Note that this feature does not work in combination with
# SEPARATE_MEMBER_PAGES.
# The default value is: NO.
INLINE_GROUPED_CLASSES = NO
# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
# with only public data fields or simple typedef fields will be shown inline in
# the documentation of the scope in which they are defined (i.e. file,
# namespace, or group documentation), provided this scope is documented. If set
# to NO, structs, classes, and unions are shown on a separate page (for HTML and
# Man pages) or section (for LaTeX and RTF).
# The default value is: NO.
INLINE_SIMPLE_STRUCTS = NO
# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
# enum is documented as struct, union, or enum with the name of the typedef. So
# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
# with name TypeT. When disabled the typedef will appear as a member of a file,
# namespace, or class. And the struct will be named TypeS. This can typically be
# useful for C code in case the coding convention dictates that all compound
# types are typedef'ed and only the typedef is referenced, never the tag name.
# The default value is: NO.
TYPEDEF_HIDES_STRUCT = NO
# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
# cache is used to resolve symbols given their name and scope. Since this can be
# an expensive process and often the same symbol appears multiple times in the
# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
# doxygen will become slower. If the cache is too large, memory is wasted. The
# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
# symbols. At the end of a run doxygen will report the cache usage and suggest
# the optimal cache size from a speed point of view.
# Minimum value: 0, maximum value: 9, default value: 0.
LOOKUP_CACHE_SIZE = 0
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
# documentation are documented, even if no documentation was available. Private
# class members and static file members will be hidden unless the
# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
# Note: This will also disable the warnings about undocumented members that are
# normally produced when WARNINGS is set to YES.
# The default value is: NO.
EXTRACT_ALL = YES
# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
# be included in the documentation.
# The default value is: NO.
EXTRACT_PRIVATE = NO
# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
# scope will be included in the documentation.
# The default value is: NO.
EXTRACT_PACKAGE = NO
# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
# included in the documentation.
# The default value is: NO.
EXTRACT_STATIC = NO
# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
# locally in source files will be included in the documentation. If set to NO,
# only classes defined in header files are included. Does not have any effect
# for Java sources.
# The default value is: YES.
EXTRACT_LOCAL_CLASSES = YES
# This flag is only useful for Objective-C code. If set to YES, local methods,
# which are defined in the implementation section but not in the interface are
# included in the documentation. If set to NO, only methods in the interface are
# included.
# The default value is: NO.
EXTRACT_LOCAL_METHODS = NO
# If this flag is set to YES, the members of anonymous namespaces will be
# extracted and appear in the documentation as a namespace called
# 'anonymous_namespace{file}', where file will be replaced with the base name of
# the file that contains the anonymous namespace. By default anonymous namespace
# are hidden.
# The default value is: NO.
EXTRACT_ANON_NSPACES = NO
# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
# undocumented members inside documented classes or files. If set to NO these
# members will be included in the various overviews, but no documentation
# section is generated. This option has no effect if EXTRACT_ALL is enabled.
# The default value is: NO.
HIDE_UNDOC_MEMBERS = NO
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy. If set
# to NO, these classes will be included in the various overviews. This option
# has no effect if EXTRACT_ALL is enabled.
# The default value is: NO.
HIDE_UNDOC_CLASSES = NO
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
# (class|struct|union) declarations. If set to NO, these declarations will be
# included in the documentation.
# The default value is: NO.
HIDE_FRIEND_COMPOUNDS = NO
# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
# documentation blocks found inside the body of a function. If set to NO, these
# blocks will be appended to the function's detailed documentation block.
# The default value is: NO.
HIDE_IN_BODY_DOCS = NO
# The INTERNAL_DOCS tag determines if documentation that is typed after a
# \internal command is included. If the tag is set to NO then the documentation
# will be excluded. Set it to YES to include the internal documentation.
# The default value is: NO.
INTERNAL_DOCS = NO
# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
# names in lower-case letters. If set to YES, upper-case letters are also
# allowed. This is useful if you have classes or files whose names only differ
# in case and if your file system supports case sensitive file names. Windows
# and Mac users are advised to set this option to NO.
# The default value is: system dependent.
CASE_SENSE_NAMES = YES
# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
# their full class and namespace scopes in the documentation. If set to YES, the
# scope will be hidden.
# The default value is: NO.
HIDE_SCOPE_NAMES = NO
# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
# append additional text to a page's title, such as Class Reference. If set to
# YES the compound reference will be hidden.
# The default value is: NO.
HIDE_COMPOUND_REFERENCE= NO
# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
# the files that are included by a file in the documentation of that file.
# The default value is: YES.
SHOW_INCLUDE_FILES = YES
# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
# grouped member an include statement to the documentation, telling the reader
# which file to include in order to use the member.
# The default value is: NO.
SHOW_GROUPED_MEMB_INC = NO
# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
# files with double quotes in the documentation rather than with sharp brackets.
# The default value is: NO.
FORCE_LOCAL_INCLUDES = NO
# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
# documentation for inline members.
# The default value is: YES.
INLINE_INFO = YES
# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
# (detailed) documentation of file and class members alphabetically by member
# name. If set to NO, the members will appear in declaration order.
# The default value is: YES.
SORT_MEMBER_DOCS = NO
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
# descriptions of file, namespace and class members alphabetically by member
# name. If set to NO, the members will appear in declaration order. Note that
# this will also influence the order of the classes in the class list.
# The default value is: NO.
SORT_BRIEF_DOCS = NO
# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
# (brief and detailed) documentation of class members so that constructors and
# destructors are listed first. If set to NO the constructors will appear in the
# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
# member documentation.
# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
# detailed member documentation.
# The default value is: NO.
SORT_MEMBERS_CTORS_1ST = NO
# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
# of group names into alphabetical order. If set to NO the group names will
# appear in their defined order.
# The default value is: NO.
SORT_GROUP_NAMES = NO
# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
# fully-qualified names, including namespaces. If set to NO, the class list will
# be sorted only by class name, not including the namespace part.
# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
# Note: This option applies only to the class list, not to the alphabetical
# list.
# The default value is: NO.
SORT_BY_SCOPE_NAME = NO
# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
# type resolution of all parameters of a function it will reject a match between
# the prototype and the implementation of a member function even if there is
# only one candidate or it is obvious which candidate to choose by doing a
# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
# accept a match between prototype and implementation in such cases.
# The default value is: NO.
STRICT_PROTO_MATCHING = NO
# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
# list. This list is created by putting \todo commands in the documentation.
# The default value is: YES.
GENERATE_TODOLIST = YES
# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
# list. This list is created by putting \test commands in the documentation.
# The default value is: YES.
GENERATE_TESTLIST = YES
# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
# list. This list is created by putting \bug commands in the documentation.
# The default value is: YES.
GENERATE_BUGLIST = YES
# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
# the deprecated list. This list is created by putting \deprecated commands in
# the documentation.
# The default value is: YES.
GENERATE_DEPRECATEDLIST= YES
# The ENABLED_SECTIONS tag can be used to enable conditional documentation
# sections, marked by \if ... \endif and \cond
# ... \endcond blocks.
ENABLED_SECTIONS =
# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
# initial value of a variable or macro / define can have for it to appear in the
# documentation. If the initializer consists of more lines than specified here
# it will be hidden. Use a value of 0 to hide initializers completely. The
# appearance of the value of individual variables and macros / defines can be
# controlled using \showinitializer or \hideinitializer command in the
# documentation regardless of this setting.
# Minimum value: 0, maximum value: 10000, default value: 30.
MAX_INITIALIZER_LINES = 30
# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
# the bottom of the documentation of classes and structs. If set to YES, the
# list will mention the files that were used to generate the documentation.
# The default value is: YES.
SHOW_USED_FILES = YES
# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
# will remove the Files entry from the Quick Index and from the Folder Tree View
# (if specified).
# The default value is: YES.
SHOW_FILES = YES
# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
# page. This will remove the Namespaces entry from the Quick Index and from the
# Folder Tree View (if specified).
# The default value is: YES.
SHOW_NAMESPACES = YES
# The FILE_VERSION_FILTER tag can be used to specify a program or script that
# doxygen should invoke to get the current version for each file (typically from
# the version control system). Doxygen will invoke the program by executing (via
# popen()) the command command input-file, where command is the value of the
# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
# by doxygen. Whatever the program writes to standard output is used as the file
# version. For an example see the documentation.
FILE_VERSION_FILTER =
# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
# by doxygen. The layout file controls the global structure of the generated
# output files in an output format independent way. To create the layout file
# that represents doxygen's defaults, run doxygen with the -l option. You can
# optionally specify a file name after the option, if omitted DoxygenLayout.xml
# will be used as the name of the layout file.
#
# Note that if you run doxygen from a directory containing a file called
# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
# tag is left empty.
LAYOUT_FILE =
# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
# the reference definitions. This must be a list of .bib files. The .bib
# extension is automatically appended if omitted. This requires the bibtex tool
# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
# For LaTeX the style of the bibliography can be controlled using
# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
# search path. See also \cite for info how to create references.
CITE_BIB_FILES =
#---------------------------------------------------------------------------
# Configuration options related to warning and progress messages
#---------------------------------------------------------------------------
# The QUIET tag can be used to turn on/off the messages that are generated to
# standard output by doxygen. If QUIET is set to YES this implies that the
# messages are off.
# The default value is: NO.
QUIET = NO
# The WARNINGS tag can be used to turn on/off the warning messages that are
# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
# this implies that the warnings are on.
#
# Tip: Turn warnings on while writing the documentation.
# The default value is: YES.
WARNINGS = YES
# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
# will automatically be disabled.
# The default value is: YES.
WARN_IF_UNDOCUMENTED = YES
# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
# potential errors in the documentation, such as not documenting some parameters
# in a documented function, or documenting parameters that don't exist or using
# markup commands wrongly.
# The default value is: YES.
WARN_IF_DOC_ERROR = YES
# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
# are documented, but have no documentation for their parameters or return
# value. If set to NO, doxygen will only warn about wrong or incomplete
# parameter documentation, but not about the absence of documentation.
# The default value is: NO.
WARN_NO_PARAMDOC = NO
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
# a warning is encountered.
# The default value is: NO.
WARN_AS_ERROR = NO
# The WARN_FORMAT tag determines the format of the warning messages that doxygen
# can produce. The string should contain the $file, $line, and $text tags, which
# will be replaced by the file and line number from which the warning originated
# and the warning text. Optionally the format may contain $version, which will
# be replaced by the version of the file (if it could be obtained via
# FILE_VERSION_FILTER)
# The default value is: $file:$line: $text.
WARN_FORMAT = "$file:$line: $text"
# The WARN_LOGFILE tag can be used to specify a file to which warning and error
# messages should be written. If left blank the output is written to standard
# error (stderr).
WARN_LOGFILE =
#---------------------------------------------------------------------------
# Configuration options related to the input files
#---------------------------------------------------------------------------
# The INPUT tag is used to specify the files and/or directories that contain
# documented source files. You may enter file names like myfile.cpp or
# directories like /usr/src/myproject. Separate the files or directories with
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
INPUT = README.md API.md INSTALL.md ./src/ ./include/
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
# documentation (see: http://www.gnu.org/software/libiconv) for the list of
# possible encodings.
# The default value is: UTF-8.
INPUT_ENCODING = UTF-8
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
# *.h) to filter out the source-files in the directories.
#
# Note that for custom extensions or not directly supported extensions you also
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# read by doxygen.
#
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
FILE_PATTERNS = *.c \
*.h \
*.md
# The RECURSIVE tag can be used to specify whether or not subdirectories should
# be searched for input files as well.
# The default value is: NO.
RECURSIVE = YES
# The EXCLUDE tag can be used to specify files and/or directories that should be
# excluded from the INPUT source files. This way you can easily exclude a
# subdirectory from a directory tree whose root is specified with the INPUT tag.
#
# Note that relative paths are relative to the directory from which doxygen is
# run.
EXCLUDE =
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
# from the input.
# The default value is: NO.
EXCLUDE_SYMLINKS = NO
# If the value of the INPUT tag contains directories, you can use the
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
# certain files from those directories.
#
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories for example use the pattern */test/*
EXCLUDE_PATTERNS =
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
# (namespaces, classes, functions, etc.) that should be excluded from the
# output. The symbol name can be a fully qualified name, a word, or if the
# wildcard * is used, a substring. Examples: ANamespace, AClass,
# AClass::ANamespace, ANamespace::*Test
#
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories use the pattern */test/*
EXCLUDE_SYMBOLS =
# The EXAMPLE_PATH tag can be used to specify one or more files or directories
# that contain example code fragments that are included (see the \include
# command).
EXAMPLE_PATH =
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
# *.h) to filter out the source-files in the directories. If left blank all
# files are included.
EXAMPLE_PATTERNS = *
# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
# searched for input files to be used with the \include or \dontinclude commands
# irrespective of the value of the RECURSIVE tag.
# The default value is: NO.
EXAMPLE_RECURSIVE = NO
# The IMAGE_PATH tag can be used to specify one or more files or directories
# that contain images that are to be included in the documentation (see the
# \image command).
IMAGE_PATH =
# The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program
# by executing (via popen()) the command:
#
#
#
# where is the value of the INPUT_FILTER tag, and is the
# name of an input file. Doxygen will then use the output that the filter
# program writes to standard output. If FILTER_PATTERNS is specified, this tag
# will be ignored.
#
# Note that the filter must not add or remove lines; it is applied before the
# code is scanned, but not when the output code is generated. If lines are added
# or removed, the anchors will not be placed correctly.
#
# Note that for custom extensions or not directly supported extensions you also
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# properly processed by doxygen.
INPUT_FILTER =
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
# basis. Doxygen will compare the file name with each pattern and apply the
# filter if there is a match. The filters are a list of the form: pattern=filter
# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
# patterns match the file name, INPUT_FILTER is applied.
#
# Note that for custom extensions or not directly supported extensions you also
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# properly processed by doxygen.
FILTER_PATTERNS =
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
# INPUT_FILTER) will also be used to filter the input files that are used for
# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
# The default value is: NO.
FILTER_SOURCE_FILES = NO
# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
# it is also possible to disable source filtering for a specific pattern using
# *.ext= (so without naming a filter).
# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
FILTER_SOURCE_PATTERNS =
# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
# is part of the input, its contents will be placed on the main page
# (index.html). This can be useful if you have a project on for instance GitHub
# and want to reuse the introduction page also for the doxygen output.
USE_MDFILE_AS_MAINPAGE = API.md
#---------------------------------------------------------------------------
# Configuration options related to source browsing
#---------------------------------------------------------------------------
# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
# generated. Documented entities will be cross-referenced with these sources.
#
# Note: To get rid of all source code in the generated output, make sure that
# also VERBATIM_HEADERS is set to NO.
# The default value is: NO.
SOURCE_BROWSER = NO
# Setting the INLINE_SOURCES tag to YES will include the body of functions,
# classes and enums directly into the documentation.
# The default value is: NO.
INLINE_SOURCES = NO
# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
# special comment blocks from generated source code fragments. Normal C, C++ and
# Fortran comments will always remain visible.
# The default value is: YES.
STRIP_CODE_COMMENTS = YES
# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
# function all documented functions referencing it will be listed.
# The default value is: NO.
REFERENCED_BY_RELATION = NO
# If the REFERENCES_RELATION tag is set to YES then for each documented function
# all documented entities called/used by that function will be listed.
# The default value is: NO.
REFERENCES_RELATION = NO
# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
# to YES then the hyperlinks from functions in REFERENCES_RELATION and
# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
# link to the documentation.
# The default value is: YES.
REFERENCES_LINK_SOURCE = YES
# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
# source code will show a tooltip with additional information such as prototype,
# brief description and links to the definition and documentation. Since this
# will make the HTML file larger and loading of large files a bit slower, you
# can opt to disable this feature.
# The default value is: YES.
# This tag requires that the tag SOURCE_BROWSER is set to YES.
SOURCE_TOOLTIPS = YES
# If the USE_HTAGS tag is set to YES then the references to source code will
# point to the HTML generated by the htags(1) tool instead of doxygen built-in
# source browser. The htags tool is part of GNU's global source tagging system
# (see http://www.gnu.org/software/global/global.html). You will need version
# 4.8.6 or higher.
#
# To use it do the following:
# - Install the latest version of global
# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
# - Make sure the INPUT points to the root of the source tree
# - Run doxygen as normal
#
# Doxygen will invoke htags (and that will in turn invoke gtags), so these
# tools must be available from the command line (i.e. in the search path).
#
# The result: instead of the source browser generated by doxygen, the links to
# source code will now point to the output of htags.
# The default value is: NO.
# This tag requires that the tag SOURCE_BROWSER is set to YES.
USE_HTAGS = NO
# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
# verbatim copy of the header file for each class for which an include is
# specified. Set to NO to disable this.
# See also: Section \class.
# The default value is: YES.
VERBATIM_HEADERS = YES
# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
# cost of reduced performance. This can be particularly helpful with template
# rich C++ code for which doxygen's built-in parser lacks the necessary type
# information.
# Note: The availability of this option depends on whether or not doxygen was
# generated with the -Duse-libclang=ON option for CMake.
# The default value is: NO.
CLANG_ASSISTED_PARSING = NO
# If clang assisted parsing is enabled you can provide the compiler with command
# line options that you would normally use when invoking the compiler. Note that
# the include paths will already be set by doxygen for the files and directories
# specified with INPUT and INCLUDE_PATH.
# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
CLANG_OPTIONS =
#---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
# compounds will be generated. Enable this if the project contains a lot of
# classes, structs, unions or interfaces.
# The default value is: YES.
ALPHABETICAL_INDEX = YES
# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
# which the alphabetical index list will be split.
# Minimum value: 1, maximum value: 20, default value: 5.
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
COLS_IN_ALPHA_INDEX = 5
# In case all classes in a project start with a common prefix, all classes will
# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
# can be used to specify a prefix (or a list of prefixes) that should be ignored
# while generating the index headers.
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the HTML output
#---------------------------------------------------------------------------
# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
# The default value is: YES.
GENERATE_HTML = YES
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
# it.
# The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_OUTPUT = html
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp).
# The default value is: .html.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_FILE_EXTENSION = .html
# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
# each generated HTML page. If the tag is left blank doxygen will generate a
# standard header.
#
# To get valid HTML the header file that includes any scripts and style sheets
# that doxygen needs, which is dependent on the configuration options used (e.g.
# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
# default header using
# doxygen -w html new_header.html new_footer.html new_stylesheet.css
# YourConfigFile
# and then modify the file new_header.html. See also section "Doxygen usage"
# for information on how to generate the default header that doxygen normally
# uses.
# Note: The header is subject to change so you typically have to regenerate the
# default header when upgrading to a newer version of doxygen. For a description
# of the possible markers and block names see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_HEADER =
# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
# generated HTML page. If the tag is left blank doxygen will generate a standard
# footer. See HTML_HEADER for more information on how to generate a default
# footer and what special commands can be used inside the footer. See also
# section "Doxygen usage" for information on how to generate the default footer
# that doxygen normally uses.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_FOOTER =
# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
# sheet that is used by each HTML page. It can be used to fine-tune the look of
# the HTML output. If left blank doxygen will generate a default style sheet.
# See also section "Doxygen usage" for information on how to generate the style
# sheet that doxygen normally uses.
# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
# it is more robust and this tag (HTML_STYLESHEET) will in the future become
# obsolete.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_STYLESHEET =
# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
# cascading style sheets that are included after the standard style sheets
# created by doxygen. Using this option one can overrule certain style aspects.
# This is preferred over using HTML_STYLESHEET since it does not replace the
# standard style sheet and is therefore more robust against future updates.
# Doxygen will copy the style sheet files to the output directory.
# Note: The order of the extra style sheet files is of importance (e.g. the last
# style sheet in the list overrules the setting of the previous ones in the
# list). For an example see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_STYLESHEET =
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the HTML output directory. Note
# that these files will be copied to the base HTML output directory. Use the
# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
# files will be copied as-is; there are no commands or markers available.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_FILES =
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
# will adjust the colors in the style sheet and background images according to
# this color. Hue is specified as an angle on a colorwheel, see
# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
# purple, and 360 is red again.
# Minimum value: 0, maximum value: 359, default value: 220.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE_HUE = 220
# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
# in the HTML output. For a value of 0 the output will use grayscales only. A
# value of 255 will produce the most vivid colors.
# Minimum value: 0, maximum value: 255, default value: 100.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE_SAT = 100
# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
# luminance component of the colors in the HTML output. Values below 100
# gradually make the output lighter, whereas values above 100 make the output
# darker. The value divided by 100 is the actual gamma applied, so 80 represents
# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
# change the gamma.
# Minimum value: 40, maximum value: 240, default value: 80.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE_GAMMA = 80
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
# page will contain the date and time when the page was generated. Setting this
# to YES can help to show when doxygen was last run and thus if the
# documentation is up to date.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_TIMESTAMP = NO
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
# documentation will contain sections that can be hidden and shown after the
# page has loaded.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_DYNAMIC_SECTIONS = NO
# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
# shown in the various tree structured indices initially; the user can expand
# and collapse entries dynamically later on. Doxygen will expand the tree to
# such a level that at most the specified number of entries are visible (unless
# a fully collapsed tree already exceeds this amount). So setting the number of
# entries 1 will produce a full collapsed tree by default. 0 is a special value
# representing an infinite number of entries and will result in a full expanded
# tree by default.
# Minimum value: 0, maximum value: 9999, default value: 100.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_INDEX_NUM_ENTRIES = 100
# If the GENERATE_DOCSET tag is set to YES, additional index files will be
# generated that can be used as input for Apple's Xcode 3 integrated development
# environment (see: http://developer.apple.com/tools/xcode/), introduced with
# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
# Makefile in the HTML output directory. Running make will produce the docset in
# that directory and running make install will install the docset in
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
# for more information.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_DOCSET = NO
# This tag determines the name of the docset feed. A documentation feed provides
# an umbrella under which multiple documentation sets from a single provider
# (such as a company or product suite) can be grouped.
# The default value is: Doxygen generated docs.
# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_FEEDNAME = "Doxygen generated docs"
# This tag specifies a string that should uniquely identify the documentation
# set bundle. This should be a reverse domain-name style string, e.g.
# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
# The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_BUNDLE_ID = org.babelouest.doc.ulfius
# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
# the documentation publisher. This should be a reverse domain-name style
# string, e.g. com.mycompany.MyDocSet.documentation.
# The default value is: org.doxygen.Publisher.
# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_PUBLISHER_ID = org.babelouest.doc
# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
# The default value is: Publisher.
# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_PUBLISHER_NAME = Publisher
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
# Windows.
#
# The HTML Help Workshop contains a compiler that can convert all HTML output
# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
# files are now used as the Windows 98 help format, and will replace the old
# Windows help format (.hlp) on all Windows platforms in the future. Compressed
# HTML files also contain an index, a table of contents, and you can search for
# words in the documentation. The HTML workshop also contains a viewer for
# compressed HTML files.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_HTMLHELP = NO
# The CHM_FILE tag can be used to specify the file name of the resulting .chm
# file. You can add a path in front of the file if the result should not be
# written to the html output directory.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
CHM_FILE =
# The HHC_LOCATION tag can be used to specify the location (absolute path
# including file name) of the HTML help compiler (hhc.exe). If non-empty,
# doxygen will try to run the HTML help compiler on the generated index.hhp.
# The file has to be specified with full path.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
HHC_LOCATION =
# The GENERATE_CHI flag controls if a separate .chi index file is generated
# (YES) or that it should be included in the master .chm file (NO).
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
GENERATE_CHI = NO
# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
# and project file content.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
CHM_INDEX_ENCODING =
# The BINARY_TOC flag controls whether a binary table of contents is generated
# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
# enables the Previous and Next buttons.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
BINARY_TOC = NO
# The TOC_EXPAND flag can be set to YES to add extra items for group members to
# the table of contents of the HTML help documentation and to the tree view.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
TOC_EXPAND = NO
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
# (.qch) of the generated HTML documentation.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_QHP = NO
# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
# the file name of the resulting .qch file. The path specified is relative to
# the HTML output folder.
# This tag requires that the tag GENERATE_QHP is set to YES.
QCH_FILE =
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
# Project output. For more information please see Qt Help Project / Namespace
# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
# The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_NAMESPACE = org.babelouest.doc
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
# Help Project output. For more information please see Qt Help Project / Virtual
# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
# folders).
# The default value is: doc.
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_VIRTUAL_FOLDER = doc
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
# filter to add. For more information please see Qt Help Project / Custom
# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
# filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_NAME =
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
# custom filter to add. For more information please see Qt Help Project / Custom
# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
# filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_ATTRS =
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
# project's filter section matches. Qt Help Project / Filter Attributes (see:
# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_SECT_FILTER_ATTRS =
# The QHG_LOCATION tag can be used to specify the location of Qt's
# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
# generated .qhp file.
# This tag requires that the tag GENERATE_QHP is set to YES.
QHG_LOCATION =
# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
# generated, together with the HTML files, they form an Eclipse help plugin. To
# install this plugin and make it available under the help contents menu in
# Eclipse, the contents of the directory containing the HTML and XML files needs
# to be copied into the plugins directory of eclipse. The name of the directory
# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
# After copying Eclipse needs to be restarted before the help appears.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_ECLIPSEHELP = NO
# A unique identifier for the Eclipse help plugin. When installing the plugin
# the directory name containing the HTML and XML files should also have this
# name. Each documentation set should have its own identifier.
# The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
ECLIPSE_DOC_ID = org.doxygen.Project
# If you want full control over the layout of the generated HTML pages it might
# be necessary to disable the index and replace it with your own. The
# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
# of each HTML page. A value of NO enables the index and the value YES disables
# it. Since the tabs in the index contain the same information as the navigation
# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
DISABLE_INDEX = NO
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
# structure should be generated to display hierarchical information. If the tag
# value is set to YES, a side panel will be generated containing a tree-like
# index structure (just like the one that is generated for HTML Help). For this
# to work a browser that supports JavaScript, DHTML, CSS and frames is required
# (i.e. any modern browser). Windows users are probably better off using the
# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
# further fine-tune the look of the index. As an example, the default style
# sheet generated by doxygen has an example that shows how to put an image at
# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
# the same information as the tab index, you could consider setting
# DISABLE_INDEX to YES when enabling this option.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_TREEVIEW = NO
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
# doxygen will group on one line in the generated HTML documentation.
#
# Note that a value of 0 will completely suppress the enum values from appearing
# in the overview section.
# Minimum value: 0, maximum value: 20, default value: 4.
# This tag requires that the tag GENERATE_HTML is set to YES.
ENUM_VALUES_PER_LINE = 4
# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
# to set the initial width (in pixels) of the frame in which the tree is shown.
# Minimum value: 0, maximum value: 1500, default value: 250.
# This tag requires that the tag GENERATE_HTML is set to YES.
TREEVIEW_WIDTH = 250
# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
# external symbols imported via tag files in a separate window.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
EXT_LINKS_IN_WINDOW = NO
# Use this tag to change the font size of LaTeX formulas included as images in
# the HTML documentation. When you change the font size after a successful
# doxygen run you need to manually remove any form_*.png images from the HTML
# output directory to force them to be regenerated.
# Minimum value: 8, maximum value: 50, default value: 10.
# This tag requires that the tag GENERATE_HTML is set to YES.
FORMULA_FONTSIZE = 10
# Use the FORMULA_TRANPARENT tag to determine whether or not the images
# generated for formulas are transparent PNGs. Transparent PNGs are not
# supported properly for IE 6.0, but are supported on all modern browsers.
#
# Note that when changing this option you need to delete any form_*.png files in
# the HTML output directory before the changes have effect.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
FORMULA_TRANSPARENT = YES
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
# http://www.mathjax.org) which uses client side Javascript for the rendering
# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
# installed or if you want to formulas look prettier in the HTML output. When
# enabled you may also need to install MathJax separately and configure the path
# to it using the MATHJAX_RELPATH option.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
USE_MATHJAX = NO
# When MathJax is enabled you can set the default output format to be used for
# the MathJax output. See the MathJax site (see:
# http://docs.mathjax.org/en/latest/output.html) for more details.
# Possible values are: HTML-CSS (which is slower, but has the best
# compatibility), NativeMML (i.e. MathML) and SVG.
# The default value is: HTML-CSS.
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_FORMAT = HTML-CSS
# When MathJax is enabled you need to specify the location relative to the HTML
# output directory using the MATHJAX_RELPATH option. The destination directory
# should contain the MathJax.js script. For instance, if the mathjax directory
# is located at the same level as the HTML output directory, then
# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
# Content Delivery Network so you can quickly see the result without installing
# MathJax. However, it is strongly recommended to install a local copy of
# MathJax from http://www.mathjax.org before deployment.
# The default value is: http://cdn.mathjax.org/mathjax/latest.
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
# extension names that should be enabled during MathJax rendering. For example
# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_EXTENSIONS =
# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
# of code that will be used on startup of the MathJax code. See the MathJax site
# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
# example see the documentation.
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_CODEFILE =
# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
# the HTML output. The underlying search engine uses javascript and DHTML and
# should work on any modern browser. Note that when using HTML help
# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
# there is already a search function so this one should typically be disabled.
# For large projects the javascript based search engine can be slow, then
# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
# search using the keyboard; to jump to the search box use + S
# (what the is depends on the OS and browser, but it is typically
# , /