[Debian-iot-packaging] [ulfius] 01/02: Import Upstream version 2.2

Thorsten Alteholz alteholz at moszumanska.debian.org
Thu Nov 23 21:35:53 UTC 2017


This is an automated email from the git hooks/post-receive script.

alteholz pushed a commit to branch master
in repository ulfius.

commit 11520ac498c6cb40c7dcc55db011668a34f4c5ff
Author: Thorsten Alteholz <debian at alteholz.de>
Date:   Thu Nov 23 22:35:42 2017 +0100

    Import Upstream version 2.2
---
 .gitignore                                        |   9 +-
 API.md                                            |  45 ++++++++-
 INSTALL.md                                        |  52 ++++++++++-
 README.md                                         |  10 +-
 example_programs/sheep_counter/sheep_counter.c    |  38 +++++++-
 example_programs/sheep_counter/static/upload.html |   6 +-
 example_programs/simple_example/Makefile          |   5 +-
 example_programs/simple_example/README.md         |   8 ++
 src/Makefile                                      |  29 ++++--
 src/u_map.c                                       |   4 +-
 src/u_request.c                                   |   2 +-
 src/u_response.c                                  |   6 +-
 src/ulfius.c                                      | 108 +++++++++++++++++-----
 src/ulfius.h                                      |  48 +++++++++-
 14 files changed, 310 insertions(+), 60 deletions(-)

diff --git a/.gitignore b/.gitignore
index 24a0dd7..975b247 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,7 @@
 *.o
-example_programs/*/*.o
-example_programs/*/valgrind*.txt
-src/*.o
-src/*.so
-src/*.so.*
+*.so
+*.so.*
+*.a
 example_programs/auth_example/auth_client
 example_programs/auth_example/auth_server
 example_programs/injection_example/injection_example
@@ -18,6 +16,7 @@ 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_example
+example_programs/*/valgrind*.txt
 test/valgrind*.txt
 test/*.o
 test/core
diff --git a/API.md b/API.md
index f3b1fe7..3ec125b 100644
--- a/API.md
+++ b/API.md
@@ -733,6 +733,45 @@ Ulifius allows file upload to the server. Beware that an uploaded file will be s
 
 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
@@ -1014,21 +1053,21 @@ int u_map_put_binary(struct _u_map * u_map, const char * key, const char * value
  * return -1 if no match found
  * search is case sensitive
  */
-size_t u_map_get_length(const struct _u_map * u_map, const const char * key);
+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 const char * key);
+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 const char * key);
+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
diff --git a/INSTALL.md b/INSTALL.md
index 5270fd3..4837744 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -1,8 +1,20 @@
 # Install Ulfius
 
-## Prerequisites
+## Debian-ish packages
 
-### External dependencies
+[![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:
+
+```shell
+# apt install libulfius-dev # Or apt install libulfius.1 if you don't need the development files
+```
+
+## Manual install
+
+### Prerequisites
+
+#### External dependencies
 
 To install all the external dependencies, for Debian based distributions (Debian, Ubuntu, Raspbian, etc.), run as root:
 
@@ -10,7 +22,7 @@ To install all the external dependencies, for Debian based distributions (Debian
 # apt-get install libmicrohttpd-dev libjansson-dev libcurl4-gnutls-dev libgnutls28-dev libgcrypt20-dev
 ```
 
-### Note
+#### Note
 
 Here libcurl4-gnutls-dev for the example, but any `libcurl*-dev` library should be sufficent, depending on your needs and configuration. Note that gnutls is mandatory for websocket management and https support.
 
@@ -20,7 +32,9 @@ As in version 2.0, libcurl and libjansson are no longer mandatory if you don't n
 
 If you want to use the websocket server functions, you need to install libmicrohttpd 0.9.53 minimum version.
 
-## Installation
+### Installation
+
+#### Install Ulfius as a shared library
 
 Download Ulfius source code from Github, get the submodules, compile and install each submodule, then compile and install ulfius:
 
@@ -37,6 +51,8 @@ $ make
 $ sudo make install
 ```
 
+#### Update Ulfius
+
 If you update Ulfius from a previous version, you must install the corresponding version of the submodules as well:
 
 ```shell
@@ -52,6 +68,8 @@ $ make
 $ sudo make install
 ```
 
+#### Disable dependencies
+
 To disable libcurl functions, append the option `CURLFLAG=-DU_DISABLE_CURL` to the make command when you build Ulfius:
 
 ```shell
@@ -82,11 +100,37 @@ To disable two or more libraries, append options, example:
 $ make CURLFLAG=-DU_DISABLE_CURL JANSSONFLAG=-DU_DISABLE_JANSSON
 ```
 
+#### 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 `PREFIX` value in the `src/Makefile`, `lib/orcania/src/Makefile` and `lib/yder/src/Makefile` files.
 
+```shell
+$ make PREFIX=/tmp install # to install ulfius in /tmp/lib for example
+```
+
+You can install Ulfius without root permission if your user has write access to `$(PREFIX)`.
+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 from a `.zip` archive
+
 If you download Ulfius as a `.zip` or `.tar.gz` file via github release tab, you must initiaize the submodules prior to the compilaton with the following command:
 
 ```shell
 $ cd ulfius/
 $ git submodule update --init
 ```
+
+#### Install as a static archive
+
+To install Ulfius library as a static archive, `libulfius.a`, use the make commands `make static*`:
+
+The archives `liborcania.a` and `libyder.a` must previously be installed in the $(PREFIX) directory.
+
+```shell
+$ cd ulfius/src
+$ make static && sudo make static-install # or make PREFIX=/tmp static-install if you want to install in `/tmp/lib`
+```
+
+The example program `example_program/simple_example` has a static make command to test and validate building a program with the archive.
+
diff --git a/README.md b/README.md
index 3e7a989..8f332d9 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # Ulfius
 
-Web Framework for REST Applications in C.
+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.
 
@@ -90,7 +90,11 @@ Example callback functions are available in the folder [example_callbacks](https
 - [Hutch](https://github.com/babelouest/hutch), a safe locker for passwords and other secrets, using encryption on the client side only
 - [Taulas Raspberry Pi Serial interface](https://github.com/babelouest/taulas/tree/master/taulas_raspberrypi_serial), an interface for Arduino devices that implent [Taulas](https://github.com/babelouest/taulas/) protocol, a house automation protocol
 
-## What's new in Ulfius 2.1 ?
+## 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.
 
@@ -103,7 +107,7 @@ Some of the adjustments made in the new release:
 
 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 ?
+## 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.
 
diff --git a/example_programs/sheep_counter/sheep_counter.c b/example_programs/sheep_counter/sheep_counter.c
index 44c04eb..9da4c42 100644
--- a/example_programs/sheep_counter/sheep_counter.c
+++ b/example_programs/sheep_counter/sheep_counter.c
@@ -40,6 +40,16 @@ int callback_sheep_counter_add (const struct _u_request * request, struct _u_res
 // Callback function used to upload file
 int callback_upload_file (const struct _u_request * request, struct _u_response * response, void * user_data);
 
+// File upload callback function
+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 * user_data);
 /**
  * decode a u_map into a string
  */
@@ -51,9 +61,9 @@ char * print_map(const struct _u_map * map) {
     keys = u_map_enum_keys(map);
     for (i=0; keys[i] != NULL; i++) {
       value = u_map_get(map, keys[i]);
-      len = snprintf(NULL, 0, "key is %s, length is %ld, value is %.*s", keys[i], u_map_get_length(map, keys[i]), (int)u_map_get_length(map, keys[i]), value);
+      len = snprintf(NULL, 0, "key is %s, length is %zu, value is %.*s", keys[i], u_map_get_length(map, keys[i]), (int)u_map_get_length(map, keys[i]), value);
       line = o_malloc((len+1)*sizeof(char));
-      snprintf(line, (len+1), "key is %s, length is %ld, value is %.*s", keys[i], u_map_get_length(map, keys[i]), (int)u_map_get_length(map, keys[i]), value);
+      snprintf(line, (len+1), "key is %s, length is %zu, value is %.*s", keys[i], u_map_get_length(map, keys[i]), (int)u_map_get_length(map, keys[i]), value);
       if (to_return != NULL) {
         len = strlen(to_return) + strlen(line) + 1;
         to_return = o_realloc(to_return, (len+1)*sizeof(char));
@@ -97,6 +107,8 @@ int main (int argc, char **argv) {
   // Initialize the instance
   struct _u_instance instance;
   
+  y_init_logs("sheep_counter", Y_LOG_MODE_CONSOLE, Y_LOG_LEVEL_DEBUG, NULL, "Starting sheep_counter");
+  
   if (ulfius_init_instance(&instance, PORT, NULL, NULL) != U_OK) {
     y_log_message(Y_LOG_LEVEL_ERROR, "Error ulfius_init_instance, abort");
     return(1);
@@ -105,6 +117,10 @@ int main (int argc, char **argv) {
   // Max post param size is 16 Kb, which means an uploaded file is no more than 16 Kb
   instance.max_post_param_size = 16*1024;
   
+  if (ulfius_set_upload_file_callback_function(&instance, &file_upload_callback, "my cls") != U_OK) {
+    y_log_message(Y_LOG_LEVEL_ERROR, "Error ulfius_set_upload_file_callback_function");
+  }
+  
   // MIME types that will define the static files
   struct _u_map mime_types;
   u_map_init(&mime_types);
@@ -142,6 +158,8 @@ int main (int argc, char **argv) {
   ulfius_stop_framework(&instance);
   ulfius_clean_instance(&instance);
   
+  y_close_logs();
+  
   return 0;
 }
 
@@ -271,3 +289,19 @@ int callback_upload_file (const struct _u_request * request, struct _u_response
   o_free(string_body);
   return U_CALLBACK_CONTINUE;
 }
+
+/**
+ * File upload callback function
+ */
+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) {
+  y_log_message(Y_LOG_LEVEL_DEBUG, "Got from file '%s' of the key '%s', offset %llu, size %zu, cls is '%s'", filename, key, off, size, cls);
+  return U_OK;
+}
diff --git a/example_programs/sheep_counter/static/upload.html b/example_programs/sheep_counter/static/upload.html
index 0a27ae8..2528d58 100644
--- a/example_programs/sheep_counter/static/upload.html
+++ b/example_programs/sheep_counter/static/upload.html
@@ -2,12 +2,12 @@
 <html>
 <body>
 
-<form action="/upload" method="post" enctype="multipart/form-data">
+<form action="upload" method="post" enctype="multipart/form-data">
+		<input type="text" name="textParam" value="textValue">
     Select files to upload:<br>
-    <input type="file" name="fileToUpload1" id="fileToUpload"><br>
+    <input type="file" name="fileToUpload1" id="fileToUpload" value=""><br>
     <input type="submit" value="Upload File" name="submit">
 </form>
 
 </body>
 </html>
-
diff --git a/example_programs/simple_example/Makefile b/example_programs/simple_example/Makefile
index 1410928..c69f42c 100644
--- a/example_programs/simple_example/Makefile
+++ b/example_programs/simple_example/Makefile
@@ -12,7 +12,7 @@
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 #
-
+PREFIX=/usr/local
 LIBYDER_LOCATION=../../lib/yder/src
 CC=gcc
 CFLAGS=-c -Wall -I$(LIBYDER_LOCATION) -D_REENTRANT $(ADDITIONALFLAGS)
@@ -39,3 +39,6 @@ simple_example: libulfius.so simple_example.o
 
 test: simple_example
 	LD_LIBRARY_PATH=$(ULFIUS_LOCATION):${LD_LIBRARY_PATH} ./simple_example
+
+static: simple_example.o
+	$(CC) -o simple_example simple_example.o $(PREFIX)/lib/liborcania.a $(PREFIX)/lib/libyder.a $(PREFIX)/lib/libulfius.a -ljansson -lmicrohttpd -lpthread -lgnutls
diff --git a/example_programs/simple_example/README.md b/example_programs/simple_example/README.md
index 6786b53..c28232b 100644
--- a/example_programs/simple_example/README.md
+++ b/example_programs/simple_example/README.md
@@ -8,6 +8,14 @@ Run a simple webservice that listen on port 8537.
 $ make test
 ```
 
+## Compile with Ulfius built as a static archive
+
+Ulfius must be built as a static archive and installed in the $(PREFIX) directory.
+
+```bash
+$ make static
+```
+
 ### https connection
 
 If you want this program to listen to a secure (https) connection, create a certificate with its certificate and private keys in to separate files, and run the program with the options `-secure <key_file> <cert_file>`.
diff --git a/src/Makefile b/src/Makefile
index ed53106..c50cfbe 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -26,17 +26,17 @@ CC=gcc
 CFLAGS=-c -pedantic -std=gnu99 -fPIC -Wall -D_REENTRANT -I$(PREFIX)/include -I$(LIBORCANIA_LOCATION) -I$(LIBYDER_LOCATION) $(ADDITIONALFLAGS) $(JANSSONFLAG) $(CURLFLAG) $(WEBSOCKETFLAG)
 LIBS=-L$(PREFIX)/lib -L$(LIBORCANIA_LOCATION) -L$(LIBYDER_LOCATION) -lc -lmicrohttpd -lyder -lorcania -lpthread
 OUTPUT=libulfius.so
-VERSION=2.1
+VERSION=2.2
 
-ifneq (($(JANSSONFLAG)),"")
+ifndef JANSSONFLAG
 LJANSSON=-ljansson
 endif
 
-ifneq (($(CURLFLAG)),"")
+ifndef CURLFLAG
 LCURL=-lcurl
 endif
 
-ifneq (($(WEBSOCKETFLAG)),"")
+ifndef WEBSOCKETFLAG
 LWEBSOCKET=-lgnutls
 endif
 
@@ -46,6 +46,9 @@ libulfius.so: ulfius.o u_map.o u_request.o u_response.o u_send_request.o u_webso
 	$(CC) -shared -Wl,-soname,$(OUTPUT) -o $(OUTPUT).$(VERSION) ulfius.o u_map.o u_request.o u_response.o u_send_request.o u_websocket.o $(LIBS) $(LJANSSON) $(LCURL) $(LWEBSOCKET)
 	ln -sf $(OUTPUT).$(VERSION) $(OUTPUT)
 
+libulfius.a: ulfius.o u_map.o u_request.o u_response.o u_send_request.o u_websocket.o
+	ar rcs libulfius.a ulfius.o u_map.o u_request.o u_response.o u_send_request.o u_websocket.o
+
 ulfius.o: ulfius.h u_private.h ulfius.c
 	$(CC) $(CFLAGS) ulfius.c
 
@@ -65,15 +68,19 @@ u_send_request.o: ulfius.h u_private.h u_send_request.c
 	$(CC) $(CFLAGS) u_send_request.c
 
 clean:
-	rm -f *.o *.so $(OUTPUT) $(OUTPUT).*
+	rm -f *.o *.so *.a $(OUTPUT) $(OUTPUT).*
 
 install: all
 	cp $(OUTPUT).$(VERSION) $(PREFIX)/lib
 	cp ulfius.h $(PREFIX)/include
-	ldconfig
+	-ldconfig
+
+static-install: static
+	cp libulfius.a $(PREFIX)/lib
+	cp ulfius.h $(PREFIX)/include
 
 uninstall:
-	rm -f $(PREFIX)/lib/$(OUTPUT)
+	rm -f $(PREFIX)/lib/$(OUTPUT) libulfius.a
 	rm -f $(PREFIX)/lib/$(OUTPUT).*
 	rm -f $(PREFIX)/include/ulfius.h
 
@@ -84,3 +91,11 @@ debug: libulfius.so
 release: ADDITIONALFLAGS=-O3
 
 release: libulfius.so
+
+static: ADDITIONALFLAGS=-O3
+
+static: libulfius.a
+
+static-debug: ADDITIONALFLAGS=-DDEBUG -g -O0
+
+static-debug: libulfius.a
diff --git a/src/u_map.c b/src/u_map.c
index cabded0..af8cfc1 100644
--- a/src/u_map.c
+++ b/src/u_map.c
@@ -512,7 +512,7 @@ const char * u_map_get_case(const struct _u_map * u_map, const char * key) {
  * return -1 if no match found
  * search is case sensitive
  */
-ssize_t u_map_get_length(const struct _u_map * u_map, const const char * key) {
+ssize_t u_map_get_length(const struct _u_map * u_map, const char * key) {
   int i;
   if (u_map != NULL && key != NULL) {
     for (i=0; u_map->keys[i] != NULL; i++) {
@@ -531,7 +531,7 @@ ssize_t u_map_get_length(const struct _u_map * u_map, const const char * key) {
  * return -1 if no match found
  * search is case insensitive
  */
-ssize_t u_map_get_case_length(const struct _u_map * u_map, const const char * key) {
+ssize_t u_map_get_case_length(const struct _u_map * u_map, const char * key) {
   int i;
   if (u_map != NULL && key != NULL) {
     for (i=0; u_map->keys[i] != NULL; i++) {
diff --git a/src/u_request.c b/src/u_request.c
index 6aa020c..dac1fe1 100644
--- a/src/u_request.c
+++ b/src/u_request.c
@@ -414,7 +414,7 @@ int ulfius_set_json_body_request(struct _u_request * request, json_t * body) {
 
     request->binary_body = (void*) json_dumps(body, JSON_COMPACT);
     if (request->binary_body == NULL) {
-      y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for dest->binary_body");
+      y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for request->binary_body");
       return U_ERROR_MEMORY;
     }
     request->binary_body_length = strlen((char*)request->binary_body);
diff --git a/src/u_response.c b/src/u_response.c
index 46ca09a..bc98bb4 100644
--- a/src/u_response.c
+++ b/src/u_response.c
@@ -572,7 +572,7 @@ int ulfius_set_string_body_response(struct _u_response * response, const unsigne
     response->binary_body = o_malloc(binary_body_length);
     
     if (response->binary_body == NULL) {
-      y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for dest->binary_body");
+      y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for response->binary_body");
       return U_ERROR_MEMORY;
     } else {
       response->status = status;
@@ -599,7 +599,7 @@ int ulfius_set_binary_body_response(struct _u_response * response, const unsigne
 
     response->binary_body = o_malloc(length);
     if (response->binary_body == NULL) {
-      y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for dest->binary_body");
+      y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for response->binary_body");
       return U_ERROR_MEMORY;
     }
     memcpy(response->binary_body, binary_body, length);
@@ -676,7 +676,7 @@ int ulfius_set_json_body_response(struct _u_response * response, const unsigned
 
     response->binary_body = (void*) json_dumps(binary_body, JSON_COMPACT);
     if (response->binary_body == NULL) {
-      y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for dest->binary_body");
+      y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for response->binary_body");
       return U_ERROR_MEMORY;
     }
     response->binary_body_length = strlen((char*)response->binary_body);
diff --git a/src/ulfius.c b/src/ulfius.c
index 022b021..37a2cdf 100644
--- a/src/ulfius.c
+++ b/src/ulfius.c
@@ -127,6 +127,7 @@ static void * ulfius_uri_logger (void * cls, const char * uri) {
   struct connection_info_struct * con_info = o_malloc (sizeof (struct connection_info_struct));
   if (con_info != NULL) {
     con_info->callback_first_iteration = 1;
+    con_info->u_instance = NULL;
     con_info->request = o_malloc(sizeof(struct _u_request));
     if (con_info->request == NULL) {
       y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for con_info->request");
@@ -220,22 +221,39 @@ static int mhd_iterate_post_data (void * coninfo_cls, enum MHD_ValueKind kind, c
   
   struct connection_info_struct * con_info = coninfo_cls;
   size_t cur_size = size;
-  char * data_dup = o_strndup(data, size); // Force value to end with a NULL character
+  char * data_dup, * filename_param;
   
-  if (con_info->max_post_param_size > 0) {
-    if (off > con_info->max_post_param_size) {
+  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;
-    } else if (off + size > con_info->max_post_param_size) {
-      cur_size = con_info->max_post_param_size - off;
+    } else {
+      return MHD_NO;
     }
-  }
-  
-  if (cur_size > 0 && data_dup != NULL && u_map_put_binary((struct _u_map *)con_info->request->map_post_body, key, data_dup, off, cur_size + 1) == U_OK) {
-    o_free(data_dup);
-    return MHD_YES;
   } else {
-    o_free(data_dup);
-    return MHD_NO;
+    data_dup = o_strndup(data, size); // Force value to end with a NULL character
+    if (con_info->max_post_param_size > 0) {
+      if (off > con_info->max_post_param_size) {
+        return MHD_YES;
+      } else if (off + size > con_info->max_post_param_size) {
+        cur_size = con_info->max_post_param_size - off;
+      }
+    }
+    
+    if (filename != NULL) {
+      filename_param = msprintf("%s_filename", key);
+      if (u_map_put((struct _u_map *)con_info->request->map_post_body, filename_param, filename) != U_OK) {
+        y_log_message(Y_LOG_LEVEL_ERROR, "ulfius - Error u_map_put filename value");
+      }
+      o_free(filename_param);
+    }
+    
+    if (cur_size > 0 && data_dup != NULL && u_map_put_binary((struct _u_map *)con_info->request->map_post_body, key, data_dup, off, cur_size + 1) == U_OK) {
+      o_free(data_dup);
+      return MHD_YES;
+    } else {
+      o_free(data_dup);
+      return MHD_NO;
+    }
   }
 }
 
@@ -272,6 +290,11 @@ static int ulfius_webservice_dispatcher (void * cls, struct MHD_Connection * con
     return MHD_NO;
   }
   
+  if (con_info->u_instance == NULL) {
+    con_info->u_instance = (struct _u_instance *)cls;
+  
+  }
+  
   if (con_info->callback_first_iteration) {
     con_info->callback_first_iteration = 0;
     so_client = MHD_get_connection_info (connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS)->client_addr;
@@ -305,7 +328,6 @@ static int ulfius_webservice_dispatcher (void * cls, struct MHD_Connection * con
     }
     return MHD_YES;
   } else if (*upload_data_size != 0) {
-
     size_t body_len = con_info->request->binary_body_length + *upload_data_size, upload_data_size_current = *upload_data_size;
     
     if (((struct _u_instance *)cls)->max_post_body_size > 0 && con_info->request->binary_body_length + *upload_data_size > ((struct _u_instance *)cls)->max_post_body_size) {
@@ -321,6 +343,12 @@ static int ulfius_webservice_dispatcher (void * cls, struct MHD_Connection * con
       } else {
         memcpy((char*)con_info->request->binary_body + con_info->request->binary_body_length, upload_data, upload_data_size_current);
         con_info->request->binary_body_length += upload_data_size_current;
+        // Handles request binary_body
+        const char * content_type = u_map_get_case(con_info->request->map_header, ULFIUS_HTTP_HEADER_CONTENT);
+        if (0 == o_strncmp(MHD_HTTP_POST_ENCODING_FORM_URLENCODED, content_type, strlen(MHD_HTTP_POST_ENCODING_FORM_URLENCODED)) || 
+            0 == o_strncmp(MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, content_type, strlen(MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA))) {
+          MHD_post_process (con_info->post_processor, upload_data, *upload_data_size);
+        }
         *upload_data_size = 0;
         return MHD_YES;
       }
@@ -328,13 +356,6 @@ static int ulfius_webservice_dispatcher (void * cls, struct MHD_Connection * con
       return MHD_YES;
     }
   } else {
-    // Handles request binary_body
-    const char * content_type = u_map_get_case(con_info->request->map_header, ULFIUS_HTTP_HEADER_CONTENT);
-    if (0 == o_strncmp(MHD_HTTP_POST_ENCODING_FORM_URLENCODED, content_type, strlen(MHD_HTTP_POST_ENCODING_FORM_URLENCODED)) || 
-        0 == o_strncmp(MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, content_type, strlen(MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA))) {
-      MHD_post_process (con_info->post_processor, con_info->request->binary_body, con_info->request->binary_body_length);
-    }
-    
     // Check if the endpoint has one or more matches
     current_endpoint_list = ulfius_endpoint_match(method, url, endpoint_list);
     
@@ -571,12 +592,12 @@ static int ulfius_webservice_dispatcher (void * cls, struct MHD_Connection * con
             mhd_ret = MHD_queue_basic_auth_fail_response (connection, auth_realm, mhd_response);
           } else if (inner_error == U_CALLBACK_UNAUTHORIZED) {
             mhd_ret = MHD_queue_response (connection, MHD_HTTP_UNAUTHORIZED, mhd_response);
-  #ifndef U_DISABLE_WEBSOCKET
+#ifndef U_DISABLE_WEBSOCKET
           } else if (upgrade_protocol) {
             mhd_ret = MHD_queue_response (connection,
                                           MHD_HTTP_SWITCHING_PROTOCOLS,
                                           mhd_response);
-  #endif
+#endif
           } else {
             mhd_ret = MHD_queue_response (connection, response->status, mhd_response);
           }
@@ -1079,6 +1100,45 @@ int ulfius_set_default_endpoint(struct _u_instance * u_instance,
 }
 
 /**
+ * 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) {
+  if (u_instance != NULL && file_upload_callback != NULL) {
+    u_instance->file_upload_callback = file_upload_callback;
+    u_instance->file_upload_cls = cls;
+    return U_OK;
+  } else {
+    return U_ERROR_PARAMS;
+  }
+}
+
+/**
  * ulfius_clean_instance
  * 
  * Clean memory allocated by a struct _u_instance *
@@ -1134,6 +1194,8 @@ int ulfius_init_instance(struct _u_instance * u_instance, unsigned int port, str
     u_instance->default_endpoint = NULL;
     u_instance->max_post_param_size = 0;
     u_instance->max_post_body_size = 0;
+    u_instance->file_upload_callback = NULL;
+    u_instance->file_upload_cls = NULL;
 #ifndef U_DISABLE_WEBSOCKET
     u_instance->websocket_handler = o_malloc(sizeof(struct _websocket_handler));
     if (u_instance->websocket_handler == NULL) {
@@ -1152,7 +1214,7 @@ int ulfius_init_instance(struct _u_instance * u_instance, unsigned int port, str
     }
     ((struct _websocket_handler *)u_instance->websocket_handler)->pthread_init = 1;
 #else
-	  u_instance->websocket_handler = NULL;
+    u_instance->websocket_handler = NULL;
 #endif
     return U_OK;
   } else {
diff --git a/src/ulfius.h b/src/ulfius.h
index 1483fad..7f32a66 100644
--- a/src/ulfius.h
+++ b/src/ulfius.h
@@ -56,7 +56,7 @@
 #define U_ERROR_LIBCURL      5 // Error in libcurl execution
 #define U_ERROR_NOT_FOUND    6 // Something was not found
 
-#define ULFIUS_VERSION 2.1
+#define ULFIUS_VERSION 2.2
 
 #define U_CALLBACK_CONTINUE     0
 #define U_CALLBACK_COMPLETE     1
@@ -118,7 +118,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;
@@ -233,16 +233,27 @@ struct _u_instance {
   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;
 };
 
 /**
  * Structures used to facilitate data manipulations (internal)
  */
 struct connection_info_struct {
+  struct _u_instance       * u_instance;
   struct MHD_PostProcessor * post_processor;
   int                        has_post_processor;
   int                        callback_first_iteration;
-  struct _u_request *        request;
+  struct _u_request        * request;
   size_t                     max_post_param_size;
   struct _u_map              map_url_initial;
 };
@@ -300,6 +311,37 @@ int ulfius_start_secure_framework(struct _u_instance * u_instance, const char *
  */
 int ulfius_stop_framework(struct _u_instance * u_instance);
 
+/**
+ * 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);
+
 /***********************************
  * Endpoints functions declarations
  ***********************************/

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-iot/ulfius.git



More information about the Debian-iot-packaging mailing list