summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2018-09-30 18:00:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2018-09-30 18:00:37 +0000
commit9026e9476ef67a1452d814a2ae48f47b5d23dae5 (patch)
tree765fa997e8ccac78a8664b91019da8aabb77a2c1
parentReleasing progress-linux version 2.3.6-1~dschinn1. (diff)
downloadulfius-9026e9476ef67a1452d814a2ae48f47b5d23dae5.zip
ulfius-9026e9476ef67a1452d814a2ae48f47b5d23dae5.tar.xz
Merging upstream version 2.3.7.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--API.md239
-rw-r--r--CHANGELOG.md6
-rw-r--r--CMakeLists.txt2
-rw-r--r--INSTALL.md23
-rw-r--r--example_programs/simple_example/simple_example.c6
-rw-r--r--example_programs/stream_example/stream_client.c10
-rw-r--r--example_programs/websocket_example/static/index.html10
-rw-r--r--example_programs/websocket_example/websocket_example.c13
-rw-r--r--include/ulfius.h4
-rw-r--r--src/Makefile2
-rw-r--r--src/u_response.c18
-rw-r--r--src/u_send_request.c12
-rw-r--r--src/u_websocket.c10
-rw-r--r--src/ulfius.c108
14 files changed, 279 insertions, 184 deletions
diff --git a/API.md b/API.md
index 16461bd..5bb55f7 100644
--- a/API.md
+++ b/API.md
@@ -1,49 +1,39 @@
# Ulfius API Documentation
-## Header file
-
-Include file `ulfius.h` in your source file:
-
-```C
-#include <ulfius.h>
-```
-
-If you have disabled `libcurl` during the build, define the macro `U_DISABLE_CURL` before including `ulfius.h`:
-
-```C
-#define U_DISABLE_CURL
-#include <ulfius.h>
-```
-
-If you have disabled `libjansson` during the build, define the macro `U_DISABLE_JANSSON` before including `ulfius.h`:
-
-```C
-#define U_DISABLE_JANSSON
-#include <ulfius.h>
-```
-
-If you have disabled `libgnutls` during the build, define the macro `U_DISABLE_WEBSOCKET` before including `ulfius.h`:
-
-```C
-#define U_DISABLE_WEBSOCKET
-#include <ulfius.h>
-```
-
-If you have disabled more than one library, for example both `libcurl` and `libjansson`, define both macros before including `ulfius.h`:
-
-```C
-#define U_DISABLE_CURL
-#define U_DISABLE_JANSSON
-#include <ulfius.h>
-```
-
-On your linker command, add ulfius as a dependency library, e.g. `-lulfius` for gcc.
-
-## API Documentation
-
-### 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_UNKOWN instead of the previous value -1. There is some updates in the stream callback function parameter types. Check the [streaming data documentation](#streaming-data).
+- [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)
+- [Header file](#header-file)
+- [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)
+- [Start and stop webservice](#start-and-stop-webservice)
+- [Callback functions management](#callback-functions-management)
+ - [Request structure](#request-structure)
+ - [Response structure](#response-structure)
+ - [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)
+ - [Cookie management](#cookie-management)
+ - [File upload](#file-upload)
+ - [Streaming data](#streaming-data)
+ - [Websockets communication](#websockets-communication)
+ - [Starting a websocket communication](#starting-a-websocket-communication)
+ - [Manipulating websocket data structure](#manipulating-websocket-data-structure)
+ - [Messages manipulation](#messages-manipulation)
+- [struct _u_map API](#struct-_u_map-api)
+- [Outgoing request functions](#outgoing-request-functions)
+- [Send HTTP request API](#send-http-request-api)
+- [Send SMTP request API](#send-http-request-api)
+
+## 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_UNKOWN 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:
@@ -53,11 +43,11 @@ int ulfius_set_binary_body_response(struct _u_response * response, const uint st
int ulfius_set_empty_body_response(struct _u_response * response, const uint status);
```
-### Update existing programs from Ulfius 1.x to 2.0
+## 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 definitions
Endpoints structure have changed, `ulfius_add_endpoint_by_val` now requires only one callback function, but requires a priority number.
@@ -75,7 +65,7 @@ ulfius_add_endpoint_by_val(&instance, "GET", "/", NULL, 1, &main_callback, my_ma
// In this case, the realm value "my realm" must be specified in the response
```
-#### Callback return value
+### 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:
@@ -90,6 +80,45 @@ If you want more details on the multiple callback functions, check the [document
Other functions may have change their name or signature, check the documentation for more information.
+## Header file
+
+Include file `ulfius.h` in your source file:
+
+```C
+#include <ulfius.h>
+```
+
+If you have disabled `libcurl` during the build, define the macro `U_DISABLE_CURL` before including `ulfius.h`:
+
+```C
+#define U_DISABLE_CURL
+#include <ulfius.h>
+```
+
+If you have disabled `libjansson` during the build, define the macro `U_DISABLE_JANSSON` before including `ulfius.h`:
+
+```C
+#define U_DISABLE_JANSSON
+#include <ulfius.h>
+```
+
+If you have disabled `libgnutls` during the build, define the macro `U_DISABLE_WEBSOCKET` before including `ulfius.h`:
+
+```C
+#define U_DISABLE_WEBSOCKET
+#include <ulfius.h>
+```
+
+If you have disabled more than one library, for example both `libcurl` and `libjansson`, define both macros before including `ulfius.h`:
+
+```C
+#define U_DISABLE_CURL
+#define U_DISABLE_JANSSON
+#include <ulfius.h>
+```
+
+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:
@@ -105,7 +134,7 @@ When specified, some functions return `U_OK` on success, and other values otherw
### Memory management
-Ulfius uses memory allocation functions `malloc/realloc/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.
+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);
@@ -152,12 +181,14 @@ int u_map_clean(struct _u_map * u_map);
void u_free(void * data);
```
-### Initialization
+### Webservice initialization
-When initialized, Ulfius runs a thread in background that will listen to the specified port and dispatch the calls to the specified functions. Ulfius allows adding and removing new endpoints during the instance execution.
+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
@@ -216,6 +247,8 @@ int ulfius_init_instance(struct _u_instance * u_instance, int port, struct socka
void ulfius_clean_instance(struct _u_instance * u_instance);
```
+#### Endpoint structure
+
The `struct _u_endpoint` is defined as:
```C
@@ -337,19 +370,21 @@ int ulfius_set_default_callback_function(struct _u_instance * u_instance,
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.
+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.
-Your `struct _u_endpoint` array **MUST** end with an empty `struct _u_endpoint`.
+If you fill your array of endoints 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`.
+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 for attributes `http_method`, `url_prefix` and `url_format`.
+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 incrementation of your choice.
-`Warning`: Having 2 callback functions with the same priority number will result in an undefined result for the callback functions execution order.
+`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 bse used. But it will not be allocated or freed by the framework, the program using this variable must free by itself.
@@ -382,7 +417,7 @@ int ulfius_start_framework(struct _u_instance * u_instance);
int ulfius_start_secure_framework(struct _u_instance * u_instance, const char * key_pem, const char * cert_pem);
```
-In your program where you want to start the web server, simply execute the function `ulfius_start_framework(struct _u_instance * u_instance)` for a non-secure http connection or `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. 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_CALLBACK_CONTINUE` or `U_CALLBACK_COMPLETE`, otherwise an error code.
+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 or `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. 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_CALLBACK_CONTINUE` or `U_CALLBACK_COMPLETE`, otherwise an error code.
Note: for security concerns, after running `ulfius_start_secure_framework`, you can free the parameters `key_pem` and `cert_pem` if you want to.
@@ -401,7 +436,7 @@ To stop the webservice, call the following function:
int ulfius_stop_framework(struct _u_instance * u_instance);
```
-### Callback functions
+### 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).
@@ -415,6 +450,8 @@ int (* callback_function)(const struct _u_request * request, // Input parameters
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
@@ -444,7 +481,7 @@ struct _u_request {
char * http_protocol;
char * http_verb;
char * http_url;
- char * proxy;
+ char * proxy;
int check_server_certificate;
long timeout;
struct sockaddr * client_address;
@@ -459,6 +496,8 @@ struct _u_request {
};
```
+#### Response structure
+
The response variable is defined as:
```C
@@ -551,19 +590,61 @@ int ulfius_set_stream_response(struct _u_response * response,
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);
```
-### JSON body in request and response
+#### 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_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 occured during execution, the framework must complete the transaction without calling any further callback function and send an error 500 to the client.
-In Ulfius 2.0, hard dependency with libjansson has been removed, the jansson library is now optional but enabled by default.
+#### Use JSON in request and response body
-If you want to remove libjansson dependency, build Ulfius library with the flag `JANSSONFLAG=-DU_DISABLE_JANSSON`
+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 th option `-DWITH_WEBSOCKET=off`.
```
-$ make JANSSONFLAG=-DU_DISABLE_JANSSON
+$ make JANSSONFLAG=-DU_DISABLE_JANSSON # Makefile
+$ cmake -DWITH_WEBSOCKET=off # CMake
```
-if libjansson library is enabled, the following functions are available in Ulfius:
+if JSON is enabled, the following functions are available in Ulfius:
```C
/**
@@ -603,14 +684,7 @@ The `jansson` api documentation is available at the following address: [Jansson
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.
-#### 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_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 occured during execution, the framework must complete the transaction without calling any further callback function and send an error 500 to the client.
+#### 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:
@@ -694,15 +768,15 @@ struct _u_request * ulfius_duplicate_request(const struct _u_request * request);
struct _u_response * ulfius_duplicate_response(const struct _u_response * response);
```
-### Memory management
+#### Memory management
The Ulfius framework will automatically free the variables referenced by the request and responses structures, except for `struct _u_response.shared_data`, so you must use dynamically allocated values for the response pointers.
-### Character encoding
+#### Character encoding
You may be careful with characters encoding if you use non UTF8 characters in your application or webservice, and especially if you use different encodings in the same application. Ulfius has not been fully tested in cases like that.
-### Cookie management
+#### Cookie management
The map_cookie structure will contain a set of key/values for the cookies. The cookie structure is defined as
@@ -794,9 +868,9 @@ 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
+ 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`.
@@ -927,7 +1001,6 @@ struct _websocket_message {
A message list has the following strucure:
```C
-
struct _websocket_message_list {
struct _websocket_message ** list;
size_t len;
@@ -950,7 +1023,6 @@ int ulfius_websocket_send_message(struct _websocket_manager * websocket_manager,
You can also pop 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 can free a message using the function `ulfius_clear_websocket_message`:
```C
-
/**
* Return the first message of the message list
* Return NULL if message_list has no message
@@ -1141,12 +1213,13 @@ int u_map_copy_into(const struct _u_map * source, struct _u_map * target);
int u_map_count(const struct _u_map * source);
```
-## Output request functions
+## 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:
+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
+$ make CURLFLAG=-DU_DISABLE_CURL # Makefile
+$ cmake -DWITH_CURL=off # CMake
```
### Send HTTP request API
@@ -1190,7 +1263,7 @@ int ulfius_send_http_streaming_request(const struct _u_request * request,
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 emails (without attached files) via a smtp server.
+It's used to send raw emails via a smtp server.
This function is defined as:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 847d3de..df1a81f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
# Ulfius Changelog
+## 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
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 00acd67..6cf0055 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -28,7 +28,7 @@ set(PROJECT_BUGREPORT_PATH "https://github.com/babelouest/ulfius/issues")
set(LIBRARY_VERSION_MAJOR "2")
set(LIBRARY_VERSION_MINOR "3")
-set(LIBRARY_VERSION_PATCH "6")
+set(LIBRARY_VERSION_PATCH "7")
set(LIBRARY_VERSION "${LIBRARY_VERSION_MAJOR}.${LIBRARY_VERSION_MINOR}.${LIBRARY_VERSION_PATCH}")
set(LIBRARY_SOVERSION "${LIBRARY_VERSION_MAJOR}.${LIBRARY_VERSION_MINOR}")
set(YDER_VERSION_DOWNLOAD "1.3.3")
diff --git a/INSTALL.md b/INSTALL.md
index 3196f01..b48421d 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -1,23 +1,31 @@
# Install Ulfius
-## Debian-ish packages
+- [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
[![Packaging status](https://repology.org/badge/vertical-allrepos/ulfius.svg)](https://repology.org/metapackage/ulfius)
-Ulfius is now available in Debian Buster (testing) and some Debian based distributions. To install it on your device, use the following command as root:
+Ulfius is available in multiple distributions as official package. Check out your distribution documentation to install the package automatically.
```shell
-# apt install libulfius-dev # Or apt install libulfius.1 if you don't need the development files
+$ # Example for Debian testing
+$ sudo apt install libulfius-dev # Or apt install libulfius2.3 if you don't need the development files
```
-### Pre-compiled packages
+## 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` and `libcurl-gnutls` 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.3.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
+$ 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.3.0/ulfius-dev-full_2.3.0_Debian_stretch_x86_64.tar.gz
$ tar xf ulfius-dev-full_2.3.0_Debian_stretch_x86_64.tar.gz
$ sudo dpkg -i liborcania-dev_1.2.0_Debian_stretch_x86_64.deb
@@ -39,14 +47,13 @@ $ git submodule update --init
### Prerequisites
-#### External dependencies
-
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
For example, to install all the external dependencies on Debian Stretch, run as root:
@@ -90,7 +97,7 @@ $ make
$ sudo make install
```
-#### Disable dependencies
+#### Disable Ulfius dependencies
To disable libcurl functions, append the option `CURLFLAG=-DU_DISABLE_CURL` to the make command when you build Ulfius:
diff --git a/example_programs/simple_example/simple_example.c b/example_programs/simple_example/simple_example.c
index 21267a4..185e5fe 100644
--- a/example_programs/simple_example/simple_example.c
+++ b/example_programs/simple_example/simple_example.c
@@ -14,9 +14,9 @@
#include <string.h>
#ifndef _WIN32
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
#endif
#define U_DISABLE_CURL
diff --git a/example_programs/stream_example/stream_client.c b/example_programs/stream_example/stream_client.c
index ac77524..cbc2d44 100644
--- a/example_programs/stream_example/stream_client.c
+++ b/example_programs/stream_example/stream_client.c
@@ -37,8 +37,8 @@ int main(void) {
struct _u_request request;
struct _u_response response;
int res;
-
- y_init_logs("stream_example client", Y_LOG_MODE_CONSOLE, Y_LOG_LEVEL_DEBUG, NULL, "Starting stream_example");
+
+ y_init_logs("stream_example client", Y_LOG_MODE_CONSOLE, Y_LOG_LEVEL_DEBUG, NULL, "Starting stream_example");
ulfius_init_response(&response);
ulfius_init_request(&request);
@@ -82,8 +82,8 @@ int main(void) {
ulfius_clean_response(&response);
ulfius_clean_request(&request);
-
- y_close_logs();
-
+
+ y_close_logs();
+
return 0;
}
diff --git a/example_programs/websocket_example/static/index.html b/example_programs/websocket_example/static/index.html
index 866d9e6..e2b9aeb 100644
--- a/example_programs/websocket_example/static/index.html
+++ b/example_programs/websocket_example/static/index.html
@@ -18,13 +18,17 @@
var mySocket = false;
function connectSocket() {
if (location.protocol === "https:") {
- mySocket = new WebSocket("wss://" + location.hostname + ":" + location.port + "/websocket", ["grut", "plop"]);
+ mySocket = new WebSocket("wss://" + location.hostname + ":" + location.port + "/websocket", ["plop"]);
} else {
- mySocket = new WebSocket("ws://" + location.hostname + ":" + location.port + "/websocket", ["grut", "plop"]);
+ mySocket = new WebSocket("ws://" + location.hostname + ":" + location.port + "/websocket", ["plop"]);
}
if (mySocket) {
mySocket.onmessage = function (event) {
- var message = "<div><strong>Date: </strong>" + (new Date()).toLocaleString() + "</div><p><strong>Message received: </strong>" + event.data + "</p><hr>"
+ if (event.data instanceof Blob) {
+ var message = "<div><strong>Date: </strong>" + (new Date()).toLocaleString() + "</div><p><strong>Binary message received: </strong>" + event.data.size + " bytes</p><hr>"
+ } else {
+ var message = "<div><strong>Date: </strong>" + (new Date()).toLocaleString() + "</div><p><strong>Text message received: </strong>" + event.data + "</p><hr>"
+ }
$("#message").append(message);
};
mySocket.onclose = function () {
diff --git a/example_programs/websocket_example/websocket_example.c b/example_programs/websocket_example/websocket_example.c
index 62da7ac..77df2f5 100644
--- a/example_programs/websocket_example/websocket_example.c
+++ b/example_programs/websocket_example/websocket_example.c
@@ -188,11 +188,16 @@ void websocket_manager_callback(const struct _u_request * request,
if (websocket_manager_user_data != NULL) {
y_log_message(Y_LOG_LEVEL_DEBUG, "websocket_manager_user_data is %s", websocket_manager_user_data);
}
- for (i=0; i<5; i++) {
+ for (i=0;; i++) {
sleep(2);
if (websocket_manager != NULL && websocket_manager->connected) {
- my_message = msprintf("Send message #%d", i);
- ret = ulfius_websocket_send_message(websocket_manager, U_WEBSOCKET_OPCODE_TEXT, o_strlen(my_message), my_message);
+ if (i%2) {
+ my_message = msprintf("Send text message #%d", i);
+ ret = ulfius_websocket_send_message(websocket_manager, U_WEBSOCKET_OPCODE_TEXT, o_strlen(my_message), my_message);
+ } else {
+ my_message = msprintf("Send binary message #%d", i);
+ ret = ulfius_websocket_send_message(websocket_manager, U_WEBSOCKET_OPCODE_BINARY, o_strlen(my_message), my_message);
+ }
o_free(my_message);
if (ret != U_OK) {
y_log_message(Y_LOG_LEVEL_DEBUG, "Error send message");
@@ -241,7 +246,7 @@ int callback_websocket (const struct _u_request * request, struct _u_response *
char * websocket_user_data = o_strdup("my_user_data");
int ret;
- if ((ret = ulfius_set_websocket_response(response, "grut,gna", "permessage-deflate", &websocket_manager_callback, websocket_user_data, &websocket_incoming_message_callback, websocket_user_data, &websocket_onclose_callback, websocket_user_data)) == U_OK) {
+ if ((ret = ulfius_set_websocket_response(response, NULL, NULL, &websocket_manager_callback, websocket_user_data, &websocket_incoming_message_callback, websocket_user_data, &websocket_onclose_callback, websocket_user_data)) == U_OK) {
return U_CALLBACK_CONTINUE;
} else {
return U_CALLBACK_ERROR;
diff --git a/include/ulfius.h b/include/ulfius.h
index bd8316b..b2b5384 100644
--- a/include/ulfius.h
+++ b/include/ulfius.h
@@ -26,7 +26,7 @@
#ifndef __ULFIUS_H__
#define __ULFIUS_H__
-#define ULFIUS_VERSION 2.3.6
+#define ULFIUS_VERSION 2.3.7
/** External dependencies **/
@@ -894,7 +894,7 @@ int u_map_empty(struct _u_map * u_map);
#define U_WEBSOCKET_LEN_MASK 0x7F
#define U_WEBSOCKET_OPCODE_CONTINUE 0x00
#define U_WEBSOCKET_OPCODE_TEXT 0x01
-#define U_WEBSOCKET_OPCODE_BINARY 0x01
+#define U_WEBSOCKET_OPCODE_BINARY 0x02
#define U_WEBSOCKET_OPCODE_CLOSE 0x08
#define U_WEBSOCKET_OPCODE_PING 0x09
#define U_WEBSOCKET_OPCODE_PONG 0x0A
diff --git a/src/Makefile b/src/Makefile
index 34b841d..cbb4361 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -27,7 +27,7 @@ CC=gcc
CFLAGS+=-c -pedantic -std=gnu99 -fPIC -Wall -D_REENTRANT -I$(DESTDIR)/include -I$(ULFIUS_INCLUDE) -I$(LIBORCANIA_LOCATION) -I$(LIBYDER_LOCATION) $(ADDITIONALFLAGS) $(JANSSONFLAG) $(CURLFLAG) $(WEBSOCKETFLAG) $(CPPFLAGS)
LIBS=-L$(DESTDIR)/lib -L$(LIBORCANIA_LOCATION) -L$(LIBYDER_LOCATION) -lc -lmicrohttpd -lyder -lorcania -lpthread $(LDFLAGS)
OUTPUT=libulfius.so
-VERSION=2.3.6
+VERSION=2.3.7
ifndef JANSSONFLAG
LJANSSON=-ljansson
diff --git a/src/u_response.c b/src/u_response.c
index 1ad7c72..c16bf81 100644
--- a/src/u_response.c
+++ b/src/u_response.c
@@ -178,7 +178,7 @@ int ulfius_set_response_header(struct MHD_Response * response, const struct _u_m
*/
int ulfius_set_response_cookie(struct MHD_Response * mhd_response, const struct _u_response * response) {
int ret;
- unsigned int i;
+ unsigned int i;
char * header;
if (mhd_response != NULL && response != NULL) {
for (i=0; i<response->nb_cookies; i++) {
@@ -414,14 +414,14 @@ int ulfius_init_response(struct _u_response * response) {
y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for response->websocket_handle");
return U_ERROR_MEMORY;
}
- ((struct _websocket_handle *)response->websocket_handle)->websocket_protocol = NULL;
- ((struct _websocket_handle *)response->websocket_handle)->websocket_extensions = NULL;
- ((struct _websocket_handle *)response->websocket_handle)->websocket_manager_callback = NULL;
- ((struct _websocket_handle *)response->websocket_handle)->websocket_manager_user_data = NULL;
- ((struct _websocket_handle *)response->websocket_handle)->websocket_incoming_message_callback = NULL;
- ((struct _websocket_handle *)response->websocket_handle)->websocket_incoming_user_data = NULL;
- ((struct _websocket_handle *)response->websocket_handle)->websocket_onclose_callback = NULL;
- ((struct _websocket_handle *)response->websocket_handle)->websocket_onclose_user_data = NULL;
+ ((struct _websocket_handle *)response->websocket_handle)->websocket_protocol = NULL;
+ ((struct _websocket_handle *)response->websocket_handle)->websocket_extensions = NULL;
+ ((struct _websocket_handle *)response->websocket_handle)->websocket_manager_callback = NULL;
+ ((struct _websocket_handle *)response->websocket_handle)->websocket_manager_user_data = NULL;
+ ((struct _websocket_handle *)response->websocket_handle)->websocket_incoming_message_callback = NULL;
+ ((struct _websocket_handle *)response->websocket_handle)->websocket_incoming_user_data = NULL;
+ ((struct _websocket_handle *)response->websocket_handle)->websocket_onclose_callback = NULL;
+ ((struct _websocket_handle *)response->websocket_handle)->websocket_onclose_user_data = NULL;
#endif
return U_OK;
} else {
diff --git a/src/u_send_request.c b/src/u_send_request.c
index 3dd20c7..34be26b 100644
--- a/src/u_send_request.c
+++ b/src/u_send_request.c
@@ -203,16 +203,16 @@ int ulfius_send_http_streaming_request(const struct _u_request * request, struct
return U_ERROR_LIBCURL;
}
}
-
- // Set proxy if defined
- if (copy_request->proxy != NULL) {
- if (curl_easy_setopt(curl_handle, CURLOPT_PROXY, copy_request->proxy) != CURLE_OK) {
+
+ // Set proxy if defined
+ if (copy_request->proxy != NULL) {
+ if (curl_easy_setopt(curl_handle, CURLOPT_PROXY, copy_request->proxy) != CURLE_OK) {
y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error setting proxy option");
ulfius_clean_request_full(copy_request);
curl_easy_cleanup(curl_handle);
return U_ERROR_LIBCURL;
- }
- }
+ }
+ }
has_params = (o_strchr(copy_request->http_url, '?') != NULL);
if (copy_request->map_url != NULL && u_map_count(copy_request->map_url) > 0) {
diff --git a/src/u_websocket.c b/src/u_websocket.c
index c4f98dc..128f566 100644
--- a/src/u_websocket.c
+++ b/src/u_websocket.c
@@ -205,10 +205,10 @@ void ulfius_start_websocket_cb (void * cls,
struct _websocket * websocket = (struct _websocket *)cls;
pthread_t thread_websocket;
int thread_ret_websocket = 0, thread_detach_websocket = 0;
- UNUSED(connection);
- UNUSED(con_cls);
- UNUSED(extra_in);
- UNUSED(extra_in_size);
+ UNUSED(connection);
+ UNUSED(con_cls);
+ UNUSED(extra_in);
+ UNUSED(extra_in_size);
if (websocket != NULL) {
websocket->urh = urh;
@@ -364,7 +364,7 @@ int ulfius_clear_websocket(struct _websocket * websocket) {
}
ulfius_instance_remove_websocket_active(websocket->instance, websocket);
ulfius_clear_websocket_manager(websocket->websocket_manager);
- ulfius_clean_request_full(websocket->request);
+ ulfius_clean_request_full(websocket->request);
o_free(websocket->websocket_manager);
websocket->websocket_manager = NULL;
o_free(websocket);
diff --git a/src/ulfius.c b/src/ulfius.c
index c49d3f3..a7d46a7 100644
--- a/src/ulfius.c
+++ b/src/ulfius.c
@@ -36,7 +36,7 @@ static int ulfius_fill_map(void * cls, enum MHD_ValueKind kind, const char * key
char * tmp;
int res;
UNUSED(kind);
-
+
if (cls == NULL || key == NULL) {
// Invalid parameters
y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error invalid parameters for ulfius_fill_map");
@@ -126,8 +126,8 @@ static int ulfius_validate_instance(const struct _u_instance * u_instance) {
*/
static void * ulfius_uri_logger (void * cls, const char * uri) {
struct connection_info_struct * con_info = o_malloc (sizeof (struct connection_info_struct));
- UNUSED(cls);
-
+ UNUSED(cls);
+
if (con_info != NULL) {
con_info->callback_first_iteration = 1;
con_info->u_instance = NULL;
@@ -199,10 +199,10 @@ static int ulfius_get_body_from_response(struct _u_response * response, void **
static void mhd_request_completed (void *cls, struct MHD_Connection *connection,
void **con_cls, enum MHD_RequestTerminationCode toe) {
struct connection_info_struct *con_info = *con_cls;
- UNUSED(toe);
- UNUSED(connection);
- UNUSED(cls);
-
+ UNUSED(toe);
+ UNUSED(connection);
+ UNUSED(cls);
+
if (NULL == con_info) {
return;
}
@@ -231,7 +231,7 @@ static int mhd_iterate_post_data (void * coninfo_cls, enum MHD_ValueKind kind, c
size_t cur_size = size;
char * data_dup, * filename_param;
UNUSED(kind);
-
+
if (filename != NULL && con_info->u_instance != NULL && con_info->u_instance->file_upload_callback != NULL) {
if (con_info->u_instance->file_upload_callback(con_info->request, key, filename, content_type, transfer_encoding, data, off, size, con_info->u_instance->file_upload_cls) == U_OK) {
return MHD_YES;
@@ -440,52 +440,52 @@ static int ulfius_webservice_dispatcher (void * cls, struct MHD_Connection * con
struct _websocket * websocket = o_malloc(sizeof(struct _websocket));
if (websocket != NULL) {
websocket->request = ulfius_duplicate_request(con_info->request);
- if (websocket->request != NULL) {
- websocket->instance = (struct _u_instance *)cls;
- websocket->websocket_protocol = ((struct _websocket_handle *)response->websocket_handle)->websocket_protocol;
- websocket->websocket_extensions = ((struct _websocket_handle *)response->websocket_handle)->websocket_extensions;
- websocket->websocket_manager_callback = ((struct _websocket_handle *)response->websocket_handle)->websocket_manager_callback;
- websocket->websocket_manager_user_data = ((struct _websocket_handle *)response->websocket_handle)->websocket_manager_user_data;
- websocket->websocket_incoming_message_callback = ((struct _websocket_handle *)response->websocket_handle)->websocket_incoming_message_callback;
- websocket->websocket_incoming_user_data = ((struct _websocket_handle *)response->websocket_handle)->websocket_incoming_user_data;
- websocket->websocket_onclose_callback = ((struct _websocket_handle *)response->websocket_handle)->websocket_onclose_callback;
- websocket->websocket_onclose_user_data = ((struct _websocket_handle *)response->websocket_handle)->websocket_onclose_user_data;
- websocket->tls = 0;
- mhd_response = MHD_create_response_for_upgrade(ulfius_start_websocket_cb, websocket);
- if (mhd_response == NULL) {
- y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error MHD_create_response_for_upgrade");
- mhd_ret = MHD_NO;
- } else {
- MHD_add_response_header (mhd_response,
- MHD_HTTP_HEADER_UPGRADE,
- U_WEBSOCKET_UPGRADE_VALUE);
- MHD_add_response_header (mhd_response,
- "Sec-WebSocket-Accept",
- websocket_accept);
- MHD_add_response_header (mhd_response,
- "Sec-WebSocket-Protocol",
- protocol);
- if (ulfius_set_response_header(mhd_response, response->map_header) == -1 || ulfius_set_response_cookie(mhd_response, response) == -1) {
- y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error setting headers or cookies");
- mhd_ret = MHD_NO;
- } else {
- ulfius_instance_add_websocket_active((struct _u_instance *)cls, websocket);
- upgrade_protocol = 1;
- }
- }
- } else {
- o_free(websocket);
- // Error building struct _websocket, sending error 500
- response->status = MHD_HTTP_INTERNAL_SERVER_ERROR;
- response_buffer = o_strdup(ULFIUS_HTTP_ERROR_BODY);
- if (response_buffer == NULL) {
- y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for websocket->request");
- mhd_ret = MHD_NO;
- } else {
- response_buffer_len = strlen(ULFIUS_HTTP_ERROR_BODY);
- mhd_response = MHD_create_response_from_buffer (response_buffer_len, response_buffer, MHD_RESPMEM_MUST_FREE );
- }
- }
+ if (websocket->request != NULL) {
+ websocket->instance = (struct _u_instance *)cls;
+ websocket->websocket_protocol = ((struct _websocket_handle *)response->websocket_handle)->websocket_protocol;
+ websocket->websocket_extensions = ((struct _websocket_handle *)response->websocket_handle)->websocket_extensions;
+ websocket->websocket_manager_callback = ((struct _websocket_handle *)response->websocket_handle)->websocket_manager_callback;
+ websocket->websocket_manager_user_data = ((struct _websocket_handle *)response->websocket_handle)->websocket_manager_user_data;
+ websocket->websocket_incoming_message_callback = ((struct _websocket_handle *)response->websocket_handle)->websocket_incoming_message_callback;
+ websocket->websocket_incoming_user_data = ((struct _websocket_handle *)response->websocket_handle)->websocket_incoming_user_data;
+ websocket->websocket_onclose_callback = ((struct _websocket_handle *)response->websocket_handle)->websocket_onclose_callback;
+ websocket->websocket_onclose_user_data = ((struct _websocket_handle *)response->websocket_handle)->websocket_onclose_user_data;
+ websocket->tls = 0;
+ mhd_response = MHD_create_response_for_upgrade(ulfius_start_websocket_cb, websocket);
+ if (mhd_response == NULL) {
+ y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error MHD_create_response_for_upgrade");
+ mhd_ret = MHD_NO;
+ } else {
+ MHD_add_response_header (mhd_response,
+ MHD_HTTP_HEADER_UPGRADE,
+ U_WEBSOCKET_UPGRADE_VALUE);
+ MHD_add_response_header (mhd_response,
+ "Sec-WebSocket-Accept",
+ websocket_accept);
+ MHD_add_response_header (mhd_response,
+ "Sec-WebSocket-Protocol",
+ protocol);
+ if (ulfius_set_response_header(mhd_response, response->map_header) == -1 || ulfius_set_response_cookie(mhd_response, response) == -1) {
+ y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error setting headers or cookies");
+ mhd_ret = MHD_NO;
+ } else {
+ ulfius_instance_add_websocket_active((struct _u_instance *)cls, websocket);
+ upgrade_protocol = 1;
+ }
+ }
+ } else {
+ o_free(websocket);
+ // Error building struct _websocket, sending error 500
+ response->status = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ response_buffer = o_strdup(ULFIUS_HTTP_ERROR_BODY);
+ if (response_buffer == NULL) {
+ y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for websocket->request");
+ mhd_ret = MHD_NO;
+ } else {
+ response_buffer_len = strlen(ULFIUS_HTTP_ERROR_BODY);
+ mhd_response = MHD_create_response_from_buffer (response_buffer_len, response_buffer, MHD_RESPMEM_MUST_FREE );
+ }
+ }
} else {
// Error building struct _websocket, sending error 500
response->status = MHD_HTTP_INTERNAL_SERVER_ERROR;