Import Upstream version 2.2
Thorsten Alteholz
6 years ago
0 | 0 | *.o |
1 | example_programs/*/*.o | |
2 | example_programs/*/valgrind*.txt | |
3 | src/*.o | |
4 | src/*.so | |
5 | src/*.so.* | |
1 | *.so | |
2 | *.so.* | |
3 | *.a | |
6 | 4 | example_programs/auth_example/auth_client |
7 | 5 | example_programs/auth_example/auth_server |
8 | 6 | example_programs/injection_example/injection_example |
17 | 15 | example_programs/multiple_callbacks_example/multiple_callbacks_example |
18 | 16 | example_programs/sheep_counter/sheep_counter |
19 | 17 | example_programs/websocket_example/websocket_example |
18 | example_programs/*/valgrind*.txt | |
20 | 19 | test/valgrind*.txt |
21 | 20 | test/*.o |
22 | 21 | test/core |
732 | 732 | |
733 | 733 | 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. |
734 | 734 | |
735 | 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. | |
736 | ||
737 | This function `ulfius_set_upload_file_callback_function` has the following prototype: | |
738 | ||
739 | ```C | |
740 | /** | |
741 | * ulfius_set_upload_file_callback_function | |
742 | * | |
743 | * Set the callback function to handle file upload | |
744 | * Used to facilitate large files upload management | |
745 | * The callback function file_upload_callback will be called | |
746 | * multiple times, with the uploaded file in striped in parts | |
747 | * | |
748 | * Warning: If this function is used, all the uploaded files | |
749 | * for the instance will be managed via this function, and they | |
750 | * will no longer be available in the struct _u_request in the | |
751 | * ulfius callback function afterwards. | |
752 | * | |
753 | * Thanks to Thad Phetteplace for the help on this feature | |
754 | * | |
755 | * u_instance: pointer to a struct _u_instance that describe its port and bind address | |
756 | * file_upload_callback: Pointer to a callback function that will handle all file uploads | |
757 | * cls: a pointer that will be passed to file_upload_callback each tim it's called | |
758 | */ | |
759 | int ulfius_set_upload_file_callback_function(struct _u_instance * u_instance, | |
760 | int (* file_upload_callback) (const struct _u_request * request, | |
761 | const char * key, | |
762 | const char * filename, | |
763 | const char * content_type, | |
764 | const char * transfer_encoding, | |
765 | const char * data, | |
766 | uint64_t off, | |
767 | size_t size, | |
768 | void * cls), | |
769 | void * cls); | |
770 | ``` | |
771 | ||
772 | 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. | |
773 | ||
735 | 774 | See `examples/sheep_counter` for a file upload example. |
736 | 775 | |
737 | 776 | ### Streaming data |
1013 | 1052 | * return -1 if no match found |
1014 | 1053 | * search is case sensitive |
1015 | 1054 | */ |
1016 | size_t u_map_get_length(const struct _u_map * u_map, const const char * key); | |
1055 | size_t u_map_get_length(const struct _u_map * u_map, const char * key); | |
1017 | 1056 | |
1018 | 1057 | /** |
1019 | 1058 | * get the value length corresponding to the specified key in the u_map |
1020 | 1059 | * return -1 if no match found |
1021 | 1060 | * search is case insensitive |
1022 | 1061 | */ |
1023 | size_t u_map_get_case_length(const struct _u_map * u_map, const const char * key); | |
1062 | size_t u_map_get_case_length(const struct _u_map * u_map, const char * key); | |
1024 | 1063 | |
1025 | 1064 | /** |
1026 | 1065 | * get the value corresponding to the specified key in the u_map |
1027 | 1066 | * return NULL if no match found |
1028 | 1067 | * search is case sensitive |
1029 | 1068 | */ |
1030 | const char * u_map_get(const struct _u_map * u_map, const const char * key); | |
1069 | const char * u_map_get(const struct _u_map * u_map, const char * key); | |
1031 | 1070 | |
1032 | 1071 | /** |
1033 | 1072 | * get the value corresponding to the specified key in the u_map |
0 | 0 | # Install Ulfius |
1 | 1 | |
2 | ## Prerequisites | |
2 | ## Debian-ish packages | |
3 | 3 | |
4 | ### External dependencies | |
4 | [![Packaging status](https://repology.org/badge/vertical-allrepos/ulfius.svg)](https://repology.org/metapackage/ulfius) | |
5 | ||
6 | 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: | |
7 | ||
8 | ```shell | |
9 | # apt install libulfius-dev # Or apt install libulfius.1 if you don't need the development files | |
10 | ``` | |
11 | ||
12 | ## Manual install | |
13 | ||
14 | ### Prerequisites | |
15 | ||
16 | #### External dependencies | |
5 | 17 | |
6 | 18 | To install all the external dependencies, for Debian based distributions (Debian, Ubuntu, Raspbian, etc.), run as root: |
7 | 19 | |
9 | 21 | # apt-get install libmicrohttpd-dev libjansson-dev libcurl4-gnutls-dev libgnutls28-dev libgcrypt20-dev |
10 | 22 | ``` |
11 | 23 | |
12 | ### Note | |
24 | #### Note | |
13 | 25 | |
14 | 26 | 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. |
15 | 27 | |
19 | 31 | |
20 | 32 | If you want to use the websocket server functions, you need to install libmicrohttpd 0.9.53 minimum version. |
21 | 33 | |
22 | ## Installation | |
34 | ### Installation | |
35 | ||
36 | #### Install Ulfius as a shared library | |
23 | 37 | |
24 | 38 | Download Ulfius source code from Github, get the submodules, compile and install each submodule, then compile and install ulfius: |
25 | 39 | |
36 | 50 | $ sudo make install |
37 | 51 | ``` |
38 | 52 | |
53 | #### Update Ulfius | |
54 | ||
39 | 55 | If you update Ulfius from a previous version, you must install the corresponding version of the submodules as well: |
40 | 56 | |
41 | 57 | ```shell |
50 | 66 | $ make |
51 | 67 | $ sudo make install |
52 | 68 | ``` |
69 | ||
70 | #### Disable dependencies | |
53 | 71 | |
54 | 72 | To disable libcurl functions, append the option `CURLFLAG=-DU_DISABLE_CURL` to the make command when you build Ulfius: |
55 | 73 | |
81 | 99 | $ make CURLFLAG=-DU_DISABLE_CURL JANSSONFLAG=-DU_DISABLE_JANSSON |
82 | 100 | ``` |
83 | 101 | |
102 | #### Installation directory | |
103 | ||
84 | 104 | 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. |
105 | ||
106 | ```shell | |
107 | $ make PREFIX=/tmp install # to install ulfius in /tmp/lib for example | |
108 | ``` | |
109 | ||
110 | You can install Ulfius without root permission if your user has write access to `$(PREFIX)`. | |
111 | 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. | |
112 | If you choose to install Ulfius in another directory, you must set your environment variable `LD_LIBRARY_PATH` properly. | |
113 | ||
114 | #### Install from a `.zip` archive | |
85 | 115 | |
86 | 116 | 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: |
87 | 117 | |
89 | 119 | $ cd ulfius/ |
90 | 120 | $ git submodule update --init |
91 | 121 | ``` |
122 | ||
123 | #### Install as a static archive | |
124 | ||
125 | To install Ulfius library as a static archive, `libulfius.a`, use the make commands `make static*`: | |
126 | ||
127 | The archives `liborcania.a` and `libyder.a` must previously be installed in the $(PREFIX) directory. | |
128 | ||
129 | ```shell | |
130 | $ cd ulfius/src | |
131 | $ make static && sudo make static-install # or make PREFIX=/tmp static-install if you want to install in `/tmp/lib` | |
132 | ``` | |
133 | ||
134 | The example program `example_program/simple_example` has a static make command to test and validate building a program with the archive. | |
135 |
0 | 0 | # Ulfius |
1 | 1 | |
2 | Web Framework for REST Applications in C. | |
2 | HTTP Framework for REST Applications in C. | |
3 | 3 | |
4 | 4 | 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. |
5 | 5 | |
89 | 89 | - [Hutch](https://github.com/babelouest/hutch), a safe locker for passwords and other secrets, using encryption on the client side only |
90 | 90 | - [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 |
91 | 91 | |
92 | ## What's new in Ulfius 2.1 ? | |
92 | ## What's new in Ulfius 2.2? | |
93 | ||
94 | 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. | |
95 | ||
96 | ## What's new in Ulfius 2.1? | |
93 | 97 | |
94 | 98 | 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. |
95 | 99 | |
102 | 106 | |
103 | 107 | 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. |
104 | 108 | |
105 | ## What's new in Ulfius 2.0 ? | |
109 | ## What's new in Ulfius 2.0? | |
106 | 110 | |
107 | 111 | 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. |
108 | 112 |
39 | 39 | // Callback function used to upload file |
40 | 40 | int callback_upload_file (const struct _u_request * request, struct _u_response * response, void * user_data); |
41 | 41 | |
42 | // File upload callback function | |
43 | int file_upload_callback (const struct _u_request * request, | |
44 | const char * key, | |
45 | const char * filename, | |
46 | const char * content_type, | |
47 | const char * transfer_encoding, | |
48 | const char * data, | |
49 | uint64_t off, | |
50 | size_t size, | |
51 | void * user_data); | |
42 | 52 | /** |
43 | 53 | * decode a u_map into a string |
44 | 54 | */ |
50 | 60 | keys = u_map_enum_keys(map); |
51 | 61 | for (i=0; keys[i] != NULL; i++) { |
52 | 62 | value = u_map_get(map, keys[i]); |
53 | 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); | |
63 | 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); | |
54 | 64 | line = o_malloc((len+1)*sizeof(char)); |
55 | 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); | |
65 | 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); | |
56 | 66 | if (to_return != NULL) { |
57 | 67 | len = strlen(to_return) + strlen(line) + 1; |
58 | 68 | to_return = o_realloc(to_return, (len+1)*sizeof(char)); |
96 | 106 | // Initialize the instance |
97 | 107 | struct _u_instance instance; |
98 | 108 | |
109 | y_init_logs("sheep_counter", Y_LOG_MODE_CONSOLE, Y_LOG_LEVEL_DEBUG, NULL, "Starting sheep_counter"); | |
110 | ||
99 | 111 | if (ulfius_init_instance(&instance, PORT, NULL, NULL) != U_OK) { |
100 | 112 | y_log_message(Y_LOG_LEVEL_ERROR, "Error ulfius_init_instance, abort"); |
101 | 113 | return(1); |
103 | 115 | |
104 | 116 | // Max post param size is 16 Kb, which means an uploaded file is no more than 16 Kb |
105 | 117 | instance.max_post_param_size = 16*1024; |
118 | ||
119 | if (ulfius_set_upload_file_callback_function(&instance, &file_upload_callback, "my cls") != U_OK) { | |
120 | y_log_message(Y_LOG_LEVEL_ERROR, "Error ulfius_set_upload_file_callback_function"); | |
121 | } | |
106 | 122 | |
107 | 123 | // MIME types that will define the static files |
108 | 124 | struct _u_map mime_types; |
140 | 156 | printf("End framework\n"); |
141 | 157 | ulfius_stop_framework(&instance); |
142 | 158 | ulfius_clean_instance(&instance); |
159 | ||
160 | y_close_logs(); | |
143 | 161 | |
144 | 162 | return 0; |
145 | 163 | } |
270 | 288 | o_free(string_body); |
271 | 289 | return U_CALLBACK_CONTINUE; |
272 | 290 | } |
291 | ||
292 | /** | |
293 | * File upload callback function | |
294 | */ | |
295 | int file_upload_callback (const struct _u_request * request, | |
296 | const char * key, | |
297 | const char * filename, | |
298 | const char * content_type, | |
299 | const char * transfer_encoding, | |
300 | const char * data, | |
301 | uint64_t off, | |
302 | size_t size, | |
303 | void * cls) { | |
304 | 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); | |
305 | return U_OK; | |
306 | } |
1 | 1 | <html> |
2 | 2 | <body> |
3 | 3 | |
4 | <form action="/upload" method="post" enctype="multipart/form-data"> | |
4 | <form action="upload" method="post" enctype="multipart/form-data"> | |
5 | <input type="text" name="textParam" value="textValue"> | |
5 | 6 | Select files to upload:<br> |
6 | <input type="file" name="fileToUpload1" id="fileToUpload"><br> | |
7 | <input type="file" name="fileToUpload1" id="fileToUpload" value=""><br> | |
7 | 8 | <input type="submit" value="Upload File" name="submit"> |
8 | 9 | </form> |
9 | 10 | |
10 | 11 | </body> |
11 | 12 | </html> |
12 |
11 | 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
13 | 13 | # |
14 | ||
14 | PREFIX=/usr/local | |
15 | 15 | LIBYDER_LOCATION=../../lib/yder/src |
16 | 16 | CC=gcc |
17 | 17 | CFLAGS=-c -Wall -I$(LIBYDER_LOCATION) -D_REENTRANT $(ADDITIONALFLAGS) |
38 | 38 | |
39 | 39 | test: simple_example |
40 | 40 | LD_LIBRARY_PATH=$(ULFIUS_LOCATION):${LD_LIBRARY_PATH} ./simple_example |
41 | ||
42 | static: simple_example.o | |
43 | $(CC) -o simple_example simple_example.o $(PREFIX)/lib/liborcania.a $(PREFIX)/lib/libyder.a $(PREFIX)/lib/libulfius.a -ljansson -lmicrohttpd -lpthread -lgnutls |
5 | 5 | |
6 | 6 | ```bash |
7 | 7 | $ make test |
8 | ``` | |
9 | ||
10 | ## Compile with Ulfius built as a static archive | |
11 | ||
12 | Ulfius must be built as a static archive and installed in the $(PREFIX) directory. | |
13 | ||
14 | ```bash | |
15 | $ make static | |
8 | 16 | ``` |
9 | 17 | |
10 | 18 | ### https connection |
25 | 25 | CFLAGS=-c -pedantic -std=gnu99 -fPIC -Wall -D_REENTRANT -I$(PREFIX)/include -I$(LIBORCANIA_LOCATION) -I$(LIBYDER_LOCATION) $(ADDITIONALFLAGS) $(JANSSONFLAG) $(CURLFLAG) $(WEBSOCKETFLAG) |
26 | 26 | LIBS=-L$(PREFIX)/lib -L$(LIBORCANIA_LOCATION) -L$(LIBYDER_LOCATION) -lc -lmicrohttpd -lyder -lorcania -lpthread |
27 | 27 | OUTPUT=libulfius.so |
28 | VERSION=2.1 | |
28 | VERSION=2.2 | |
29 | 29 | |
30 | ifneq (($(JANSSONFLAG)),"") | |
30 | ifndef JANSSONFLAG | |
31 | 31 | LJANSSON=-ljansson |
32 | 32 | endif |
33 | 33 | |
34 | ifneq (($(CURLFLAG)),"") | |
34 | ifndef CURLFLAG | |
35 | 35 | LCURL=-lcurl |
36 | 36 | endif |
37 | 37 | |
38 | ifneq (($(WEBSOCKETFLAG)),"") | |
38 | ifndef WEBSOCKETFLAG | |
39 | 39 | LWEBSOCKET=-lgnutls |
40 | 40 | endif |
41 | 41 | |
44 | 44 | libulfius.so: ulfius.o u_map.o u_request.o u_response.o u_send_request.o u_websocket.o |
45 | 45 | $(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) |
46 | 46 | ln -sf $(OUTPUT).$(VERSION) $(OUTPUT) |
47 | ||
48 | libulfius.a: ulfius.o u_map.o u_request.o u_response.o u_send_request.o u_websocket.o | |
49 | ar rcs libulfius.a ulfius.o u_map.o u_request.o u_response.o u_send_request.o u_websocket.o | |
47 | 50 | |
48 | 51 | ulfius.o: ulfius.h u_private.h ulfius.c |
49 | 52 | $(CC) $(CFLAGS) ulfius.c |
64 | 67 | $(CC) $(CFLAGS) u_send_request.c |
65 | 68 | |
66 | 69 | clean: |
67 | rm -f *.o *.so $(OUTPUT) $(OUTPUT).* | |
70 | rm -f *.o *.so *.a $(OUTPUT) $(OUTPUT).* | |
68 | 71 | |
69 | 72 | install: all |
70 | 73 | cp $(OUTPUT).$(VERSION) $(PREFIX)/lib |
71 | 74 | cp ulfius.h $(PREFIX)/include |
72 | ldconfig | |
75 | -ldconfig | |
76 | ||
77 | static-install: static | |
78 | cp libulfius.a $(PREFIX)/lib | |
79 | cp ulfius.h $(PREFIX)/include | |
73 | 80 | |
74 | 81 | uninstall: |
75 | rm -f $(PREFIX)/lib/$(OUTPUT) | |
82 | rm -f $(PREFIX)/lib/$(OUTPUT) libulfius.a | |
76 | 83 | rm -f $(PREFIX)/lib/$(OUTPUT).* |
77 | 84 | rm -f $(PREFIX)/include/ulfius.h |
78 | 85 | |
83 | 90 | release: ADDITIONALFLAGS=-O3 |
84 | 91 | |
85 | 92 | release: libulfius.so |
93 | ||
94 | static: ADDITIONALFLAGS=-O3 | |
95 | ||
96 | static: libulfius.a | |
97 | ||
98 | static-debug: ADDITIONALFLAGS=-DDEBUG -g -O0 | |
99 | ||
100 | static-debug: libulfius.a |
511 | 511 | * return -1 if no match found |
512 | 512 | * search is case sensitive |
513 | 513 | */ |
514 | ssize_t u_map_get_length(const struct _u_map * u_map, const const char * key) { | |
514 | ssize_t u_map_get_length(const struct _u_map * u_map, const char * key) { | |
515 | 515 | int i; |
516 | 516 | if (u_map != NULL && key != NULL) { |
517 | 517 | for (i=0; u_map->keys[i] != NULL; i++) { |
530 | 530 | * return -1 if no match found |
531 | 531 | * search is case insensitive |
532 | 532 | */ |
533 | ssize_t u_map_get_case_length(const struct _u_map * u_map, const const char * key) { | |
533 | ssize_t u_map_get_case_length(const struct _u_map * u_map, const char * key) { | |
534 | 534 | int i; |
535 | 535 | if (u_map != NULL && key != NULL) { |
536 | 536 | for (i=0; u_map->keys[i] != NULL; i++) { |
413 | 413 | |
414 | 414 | request->binary_body = (void*) json_dumps(body, JSON_COMPACT); |
415 | 415 | if (request->binary_body == NULL) { |
416 | y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for dest->binary_body"); | |
416 | y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for request->binary_body"); | |
417 | 417 | return U_ERROR_MEMORY; |
418 | 418 | } |
419 | 419 | request->binary_body_length = strlen((char*)request->binary_body); |
571 | 571 | response->binary_body = o_malloc(binary_body_length); |
572 | 572 | |
573 | 573 | if (response->binary_body == NULL) { |
574 | y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for dest->binary_body"); | |
574 | y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for response->binary_body"); | |
575 | 575 | return U_ERROR_MEMORY; |
576 | 576 | } else { |
577 | 577 | response->status = status; |
598 | 598 | |
599 | 599 | response->binary_body = o_malloc(length); |
600 | 600 | if (response->binary_body == NULL) { |
601 | y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for dest->binary_body"); | |
601 | y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for response->binary_body"); | |
602 | 602 | return U_ERROR_MEMORY; |
603 | 603 | } |
604 | 604 | memcpy(response->binary_body, binary_body, length); |
675 | 675 | |
676 | 676 | response->binary_body = (void*) json_dumps(binary_body, JSON_COMPACT); |
677 | 677 | if (response->binary_body == NULL) { |
678 | y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for dest->binary_body"); | |
678 | y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for response->binary_body"); | |
679 | 679 | return U_ERROR_MEMORY; |
680 | 680 | } |
681 | 681 | response->binary_body_length = strlen((char*)response->binary_body); |
126 | 126 | struct connection_info_struct * con_info = o_malloc (sizeof (struct connection_info_struct)); |
127 | 127 | if (con_info != NULL) { |
128 | 128 | con_info->callback_first_iteration = 1; |
129 | con_info->u_instance = NULL; | |
129 | 130 | con_info->request = o_malloc(sizeof(struct _u_request)); |
130 | 131 | if (con_info->request == NULL) { |
131 | 132 | y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for con_info->request"); |
219 | 220 | |
220 | 221 | struct connection_info_struct * con_info = coninfo_cls; |
221 | 222 | size_t cur_size = size; |
222 | char * data_dup = o_strndup(data, size); // Force value to end with a NULL character | |
223 | ||
224 | if (con_info->max_post_param_size > 0) { | |
225 | if (off > con_info->max_post_param_size) { | |
223 | char * data_dup, * filename_param; | |
224 | ||
225 | if (filename != NULL && con_info->u_instance != NULL && con_info->u_instance->file_upload_callback != NULL) { | |
226 | 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) { | |
226 | 227 | return MHD_YES; |
227 | } else if (off + size > con_info->max_post_param_size) { | |
228 | cur_size = con_info->max_post_param_size - off; | |
229 | } | |
230 | } | |
231 | ||
232 | 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) { | |
233 | o_free(data_dup); | |
234 | return MHD_YES; | |
235 | } else { | |
236 | o_free(data_dup); | |
237 | return MHD_NO; | |
228 | } else { | |
229 | return MHD_NO; | |
230 | } | |
231 | } else { | |
232 | data_dup = o_strndup(data, size); // Force value to end with a NULL character | |
233 | if (con_info->max_post_param_size > 0) { | |
234 | if (off > con_info->max_post_param_size) { | |
235 | return MHD_YES; | |
236 | } else if (off + size > con_info->max_post_param_size) { | |
237 | cur_size = con_info->max_post_param_size - off; | |
238 | } | |
239 | } | |
240 | ||
241 | if (filename != NULL) { | |
242 | filename_param = msprintf("%s_filename", key); | |
243 | if (u_map_put((struct _u_map *)con_info->request->map_post_body, filename_param, filename) != U_OK) { | |
244 | y_log_message(Y_LOG_LEVEL_ERROR, "ulfius - Error u_map_put filename value"); | |
245 | } | |
246 | o_free(filename_param); | |
247 | } | |
248 | ||
249 | 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) { | |
250 | o_free(data_dup); | |
251 | return MHD_YES; | |
252 | } else { | |
253 | o_free(data_dup); | |
254 | return MHD_NO; | |
255 | } | |
238 | 256 | } |
239 | 257 | } |
240 | 258 | |
269 | 287 | if (con_info == NULL) { |
270 | 288 | y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error con_info is NULL"); |
271 | 289 | return MHD_NO; |
290 | } | |
291 | ||
292 | if (con_info->u_instance == NULL) { | |
293 | con_info->u_instance = (struct _u_instance *)cls; | |
294 | ||
272 | 295 | } |
273 | 296 | |
274 | 297 | if (con_info->callback_first_iteration) { |
304 | 327 | } |
305 | 328 | return MHD_YES; |
306 | 329 | } else if (*upload_data_size != 0) { |
307 | ||
308 | 330 | size_t body_len = con_info->request->binary_body_length + *upload_data_size, upload_data_size_current = *upload_data_size; |
309 | 331 | |
310 | 332 | 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) { |
320 | 342 | } else { |
321 | 343 | memcpy((char*)con_info->request->binary_body + con_info->request->binary_body_length, upload_data, upload_data_size_current); |
322 | 344 | con_info->request->binary_body_length += upload_data_size_current; |
345 | // Handles request binary_body | |
346 | const char * content_type = u_map_get_case(con_info->request->map_header, ULFIUS_HTTP_HEADER_CONTENT); | |
347 | if (0 == o_strncmp(MHD_HTTP_POST_ENCODING_FORM_URLENCODED, content_type, strlen(MHD_HTTP_POST_ENCODING_FORM_URLENCODED)) || | |
348 | 0 == o_strncmp(MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, content_type, strlen(MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA))) { | |
349 | MHD_post_process (con_info->post_processor, upload_data, *upload_data_size); | |
350 | } | |
323 | 351 | *upload_data_size = 0; |
324 | 352 | return MHD_YES; |
325 | 353 | } |
327 | 355 | return MHD_YES; |
328 | 356 | } |
329 | 357 | } else { |
330 | // Handles request binary_body | |
331 | const char * content_type = u_map_get_case(con_info->request->map_header, ULFIUS_HTTP_HEADER_CONTENT); | |
332 | if (0 == o_strncmp(MHD_HTTP_POST_ENCODING_FORM_URLENCODED, content_type, strlen(MHD_HTTP_POST_ENCODING_FORM_URLENCODED)) || | |
333 | 0 == o_strncmp(MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, content_type, strlen(MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA))) { | |
334 | MHD_post_process (con_info->post_processor, con_info->request->binary_body, con_info->request->binary_body_length); | |
335 | } | |
336 | ||
337 | 358 | // Check if the endpoint has one or more matches |
338 | 359 | current_endpoint_list = ulfius_endpoint_match(method, url, endpoint_list); |
339 | 360 | |
570 | 591 | mhd_ret = MHD_queue_basic_auth_fail_response (connection, auth_realm, mhd_response); |
571 | 592 | } else if (inner_error == U_CALLBACK_UNAUTHORIZED) { |
572 | 593 | mhd_ret = MHD_queue_response (connection, MHD_HTTP_UNAUTHORIZED, mhd_response); |
573 | #ifndef U_DISABLE_WEBSOCKET | |
594 | #ifndef U_DISABLE_WEBSOCKET | |
574 | 595 | } else if (upgrade_protocol) { |
575 | 596 | mhd_ret = MHD_queue_response (connection, |
576 | 597 | MHD_HTTP_SWITCHING_PROTOCOLS, |
577 | 598 | mhd_response); |
578 | #endif | |
599 | #endif | |
579 | 600 | } else { |
580 | 601 | mhd_ret = MHD_queue_response (connection, response->status, mhd_response); |
581 | 602 | } |
1078 | 1099 | } |
1079 | 1100 | |
1080 | 1101 | /** |
1102 | * ulfius_set_upload_file_callback_function | |
1103 | * | |
1104 | * Set the callback function to handle file upload | |
1105 | * Used to facilitate large files upload management | |
1106 | * The callback function file_upload_callback will be called | |
1107 | * multiple times, with the uploaded file in striped in parts | |
1108 | * | |
1109 | * Warning: If this function is used, all the uploaded files | |
1110 | * for the instance will be managed via this function, and they | |
1111 | * will no longer be available in the struct _u_request in the | |
1112 | * ulfius callback function afterwards. | |
1113 | * | |
1114 | * Thanks to Thad Phetteplace for the help on this feature | |
1115 | * | |
1116 | * u_instance: pointer to a struct _u_instance that describe its port and bind address | |
1117 | * file_upload_callback: Pointer to a callback function that will handle all file uploads | |
1118 | * cls: a pointer that will be passed to file_upload_callback each tim it's called | |
1119 | */ | |
1120 | int ulfius_set_upload_file_callback_function(struct _u_instance * u_instance, | |
1121 | int (* file_upload_callback) (const struct _u_request * request, | |
1122 | const char * key, | |
1123 | const char * filename, | |
1124 | const char * content_type, | |
1125 | const char * transfer_encoding, | |
1126 | const char * data, | |
1127 | uint64_t off, | |
1128 | size_t size, | |
1129 | void * cls), | |
1130 | void * cls) { | |
1131 | if (u_instance != NULL && file_upload_callback != NULL) { | |
1132 | u_instance->file_upload_callback = file_upload_callback; | |
1133 | u_instance->file_upload_cls = cls; | |
1134 | return U_OK; | |
1135 | } else { | |
1136 | return U_ERROR_PARAMS; | |
1137 | } | |
1138 | } | |
1139 | ||
1140 | /** | |
1081 | 1141 | * ulfius_clean_instance |
1082 | 1142 | * |
1083 | 1143 | * Clean memory allocated by a struct _u_instance * |
1133 | 1193 | u_instance->default_endpoint = NULL; |
1134 | 1194 | u_instance->max_post_param_size = 0; |
1135 | 1195 | u_instance->max_post_body_size = 0; |
1196 | u_instance->file_upload_callback = NULL; | |
1197 | u_instance->file_upload_cls = NULL; | |
1136 | 1198 | #ifndef U_DISABLE_WEBSOCKET |
1137 | 1199 | u_instance->websocket_handler = o_malloc(sizeof(struct _websocket_handler)); |
1138 | 1200 | if (u_instance->websocket_handler == NULL) { |
1151 | 1213 | } |
1152 | 1214 | ((struct _websocket_handler *)u_instance->websocket_handler)->pthread_init = 1; |
1153 | 1215 | #else |
1154 | u_instance->websocket_handler = NULL; | |
1216 | u_instance->websocket_handler = NULL; | |
1155 | 1217 | #endif |
1156 | 1218 | return U_OK; |
1157 | 1219 | } else { |
55 | 55 | #define U_ERROR_LIBCURL 5 // Error in libcurl execution |
56 | 56 | #define U_ERROR_NOT_FOUND 6 // Something was not found |
57 | 57 | |
58 | #define ULFIUS_VERSION 2.1 | |
58 | #define ULFIUS_VERSION 2.2 | |
59 | 59 | |
60 | 60 | #define U_CALLBACK_CONTINUE 0 |
61 | 61 | #define U_CALLBACK_COMPLETE 1 |
117 | 117 | char * http_protocol; |
118 | 118 | char * http_verb; |
119 | 119 | char * http_url; |
120 | char * proxy; | |
120 | char * proxy; | |
121 | 121 | int check_server_certificate; |
122 | 122 | long timeout; |
123 | 123 | struct sockaddr * client_address; |
232 | 232 | size_t max_post_param_size; |
233 | 233 | size_t max_post_body_size; |
234 | 234 | void * websocket_handler; |
235 | int (* file_upload_callback) (const struct _u_request * request, | |
236 | const char * key, | |
237 | const char * filename, | |
238 | const char * content_type, | |
239 | const char * transfer_encoding, | |
240 | const char * data, | |
241 | uint64_t off, | |
242 | size_t size, | |
243 | void * cls); | |
244 | void * file_upload_cls; | |
235 | 245 | }; |
236 | 246 | |
237 | 247 | /** |
238 | 248 | * Structures used to facilitate data manipulations (internal) |
239 | 249 | */ |
240 | 250 | struct connection_info_struct { |
251 | struct _u_instance * u_instance; | |
241 | 252 | struct MHD_PostProcessor * post_processor; |
242 | 253 | int has_post_processor; |
243 | 254 | int callback_first_iteration; |
244 | struct _u_request * request; | |
255 | struct _u_request * request; | |
245 | 256 | size_t max_post_param_size; |
246 | 257 | struct _u_map map_url_initial; |
247 | 258 | }; |
298 | 309 | * return U_OK on success |
299 | 310 | */ |
300 | 311 | int ulfius_stop_framework(struct _u_instance * u_instance); |
312 | ||
313 | /** | |
314 | * ulfius_set_upload_file_callback_function | |
315 | * | |
316 | * Set the callback function to handle file upload | |
317 | * Used to facilitate large files upload management | |
318 | * The callback function file_upload_callback will be called | |
319 | * multiple times, with the uploaded file in striped in parts | |
320 | * | |
321 | * Warning: If this function is used, all the uploaded files | |
322 | * for the instance will be managed via this function, and they | |
323 | * will no longer be available in the struct _u_request in the | |
324 | * ulfius callback function afterwards. | |
325 | * | |
326 | * Thanks to Thad Phetteplace for the help on this feature | |
327 | * | |
328 | * u_instance: pointer to a struct _u_instance that describe its port and bind address | |
329 | * file_upload_callback: Pointer to a callback function that will handle all file uploads | |
330 | * cls: a pointer that will be passed to file_upload_callback each tim it's called | |
331 | */ | |
332 | int ulfius_set_upload_file_callback_function(struct _u_instance * u_instance, | |
333 | int (* file_upload_callback) (const struct _u_request * request, | |
334 | const char * key, | |
335 | const char * filename, | |
336 | const char * content_type, | |
337 | const char * transfer_encoding, | |
338 | const char * data, | |
339 | uint64_t off, | |
340 | size_t size, | |
341 | void * cls), | |
342 | void * cls); | |
301 | 343 | |
302 | 344 | /*********************************** |
303 | 345 | * Endpoints functions declarations |