1 /** 2 * 3 * @file ulfius.h 4 * @brief Ulfius framework 5 * 6 * REST framework library 7 * 8 * ulfius.h: public structures and functions declarations 9 * 10 * Copyright 2015-2020 Nicolas Mora <mail@babelouest.org> 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU Lesser General Public License 14 * as published by the Free Software Foundation; 15 * version 2.1 of the License. 16 * 17 * This library is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU GENERAL PUBLIC LICENSE for more details. 21 * 22 * You should have received a copy of the GNU General Public 23 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 24 * 25 */ 26 27 #ifndef __ULFIUS_H__ 28 #define __ULFIUS_H__ 29 30 #ifdef __cplusplus 31 extern "C" 32 { 33 #endif 34 35 #include "ulfius-cfg.h" 36 37 /** External dependencies **/ 38 39 #ifndef U_DISABLE_GNUTLS 40 #ifndef _GNU_SOURCE 41 #define _GNU_SOURCE 42 #endif 43 #include <gnutls/gnutls.h> 44 #include <gnutls/x509.h> 45 #endif 46 47 #ifndef U_DISABLE_WEBSOCKET 48 #include <poll.h> 49 #include <zlib.h> 50 #ifndef POLLRDHUP 51 #define POLLRDHUP 0x2000 52 #endif 53 #endif 54 55 #include <pthread.h> 56 #include <microhttpd.h> 57 58 #if defined(_WIN32) && !defined(U_DISABLE_WEBSOCKET) 59 #define U_DISABLE_WEBSOCKET 60 #endif 61 62 #if (MHD_VERSION < 0x00095300) && !defined(U_DISABLE_WEBSOCKET) 63 #define U_DISABLE_WEBSOCKET 64 #endif 65 66 /** Angharad libraries **/ 67 #include <orcania.h> 68 69 /** To disable all yder log messages, this flag must be enabled **/ 70 #ifndef U_DISABLE_YDER 71 #include <yder.h> 72 #else 73 74 #define Y_LOG_MODE_NONE 0 75 #define Y_LOG_MODE_CONSOLE 0 76 #define Y_LOG_MODE_SYSLOG 0 77 #define Y_LOG_MODE_FILE 0 78 #define Y_LOG_MODE_JOURNALD 0 79 #define Y_LOG_MODE_CALLBACK 0 80 #define Y_LOG_MODE_CURRENT 0 81 82 #define Y_LOG_LEVEL_NONE 0 83 #define Y_LOG_LEVEL_DEBUG 0 84 #define Y_LOG_LEVEL_INFO 0 85 #define Y_LOG_LEVEL_WARNING 0 86 #define Y_LOG_LEVEL_ERROR 0 87 #define Y_LOG_LEVEL_CURRENT 0 88 89 int y_init_logs(const char * app, const unsigned long init_mode, const unsigned long init_level, const char * init_log_file, const char * message); 90 int y_set_logs_callback(void (* y_callback_log_message) (void * cls, const char * app_name, const time_t date, const unsigned long level, const char * message), void * cls, const char * message); 91 void y_log_message(const unsigned long type, const char * message, ...); 92 int y_close_logs(); 93 #endif 94 95 #ifndef U_DISABLE_JANSSON 96 #include <jansson.h> 97 #endif 98 99 /** 100 * @defgroup const Constants 101 * @{ 102 */ 103 104 #define ULFIUS_STREAM_BLOCK_SIZE_DEFAULT 1024 105 #define U_STREAM_END MHD_CONTENT_READER_END_OF_STREAM 106 #define U_STREAM_ERROR MHD_CONTENT_READER_END_WITH_ERROR 107 #define U_STREAM_SIZE_UNKNOWN MHD_SIZE_UNKNOWN 108 #define U_STREAM_SIZE_UNKOWN U_STREAM_SIZE_UNKNOWN // Backward compatibility 109 110 #define U_OK 0 ///< No error 111 #define U_ERROR 1 ///< Error 112 #define U_ERROR_MEMORY 2 ///< Error in memory allocation 113 #define U_ERROR_PARAMS 3 ///< Error in input parameters 114 #define U_ERROR_LIBMHD 4 ///< Error in libmicrohttpd execution 115 #define U_ERROR_LIBCURL 5 ///< Error in libcurl execution 116 #define U_ERROR_NOT_FOUND 6 ///< Something was not found 117 #define U_ERROR_DISCONNECTED 7 ///< Connection closed 118 119 #define U_CALLBACK_CONTINUE 0 ///< Callback exited with success, continue to next callback 120 #define U_CALLBACK_IGNORE 1 ///< Callback decided to be ignored, request.callback_position will not be incremented, continue to next callback 121 #define U_CALLBACK_COMPLETE 2 ///< Callback exited with success, exit callback list 122 #define U_CALLBACK_UNAUTHORIZED 3 ///< Request is unauthorized, exit callback list and return status 401 123 #define U_CALLBACK_ERROR 4 ///< Error during request process, exit callback list and return status 500 124 125 #define U_COOKIE_SAME_SITE_NONE 0 ///< Set same_site cookie property to 0 126 #define U_COOKIE_SAME_SITE_STRICT 1 ///< Set same_site cookie property to strict 127 #define U_COOKIE_SAME_SITE_LAX 2 ///< Set same_site cookie property to lax 128 129 #define U_USE_IPV4 0x0001 ///< Use instance in IPV4 mode only 130 #define U_USE_IPV6 0x0010 ///< Use instance in IPV6 mode only 131 #define U_USE_ALL (U_USE_IPV4|U_USE_IPV6) ///< Use instance in both IPV4 and IPV6 mode 132 133 #define U_SSL_VERIFY_PEER 0x0001 ///< Verify TLS session with peers 134 #define U_SSL_VERIFY_HOSTNAME 0x0010 ///< Verify TLS session with hostname 135 136 /** 137 * Options available to set or get properties using 138 * ulfius_set_request_properties or ulfius_set_request_properties 139 */ 140 typedef enum { 141 U_OPT_NONE = 0, ///< Empty option to complete a ulfius_set_request_properties or ulfius_set_request_properties 142 U_OPT_HTTP_VERB = 1, ///< http method (GET, POST, PUT, DELETE, etc.), expected option value type: const char * 143 U_OPT_HTTP_URL = 2, ///< full url used to call this callback function or full url to call when used in a ulfius_send_http_request, expected option value type: const char * 144 U_OPT_HTTP_PROXY = 3, ///< proxy address to use for outgoing connections, used by ulfius_send_http_request, expected option value type: const char * 145 #if MHD_VERSION >= 0x00095208 146 U_OPT_NETWORK_TYPE = 4, ///< Force connect to ipv4, ipv6 addresses or both, values available are U_USE_ALL, U_USE_IPV4 or U_USE_IPV6, expected option value type: unsigned short 147 #endif 148 U_OPT_CHECK_SERVER_CERTIFICATE = 5, ///< check server certificate and hostname, default true, used by ulfius_send_http_request, expected option value type: int 149 U_OPT_CHECK_SERVER_CERTIFICATE_FLAG = 6, ///< check certificate peer and or server hostname if check_server_certificate is enabled, values available are U_SSL_VERIFY_PEER, U_SSL_VERIFY_HOSTNAME or both, default value is both (U_SSL_VERIFY_PEER|U_SSL_VERIFY_HOSTNAME), used by ulfius_send_http_request, expected option value type: int 150 U_OPT_CHECK_PROXY_CERTIFICATE = 7, ///< check proxy certificate and hostname, default true, used by ulfius_send_http_request, requires libcurl >= 7.52, expected option value type: int 151 U_OPT_CHECK_PROXY_CERTIFICATE_FLAG = 8, ///< check certificate peer and or proxy hostname if check_proxy_certificate is enabled, values available are U_SSL_VERIFY_PEER, U_SSL_VERIFY_HOSTNAME or both, default value is both (U_SSL_VERIFY_PEER|U_SSL_VERIFY_HOSTNAME), used by ulfius_send_http_request, requires libcurl >= 7.52, expected option value type: int 152 U_OPT_FOLLOW_REDIRECT = 9, ///< follow url redirections, used by ulfius_send_http_request, expected option value type: int 153 U_OPT_CA_PATH = 10, ///< specify a path to CA certificates instead of system path, used by ulfius_send_http_request, expected option value type: const char * 154 U_OPT_TIMEOUT = 11, ///< connection timeout used by ulfius_send_http_request, default is 0 _or_ Timeout in seconds to close the connection because of inactivity between the client and the server, expected option value type: unsigned long 155 U_OPT_AUTH_BASIC_USER = 12, ///< basic authentication username, expected option value type: const char * 156 U_OPT_AUTH_BASIC_PASSWORD = 13, ///< basic authentication password, expected option value type: const char * 157 U_OPT_URL_PARAMETER = 14, ///< Add to the map containing the url variables, both from the route and the ?key=value variables, expected option value type: const char *, const char * 158 U_OPT_HEADER_PARAMETER = 15, ///< Add to the map containing the header variables, expected option value type: const char *, const char * 159 U_OPT_COOKIE_PARAMETER = 16, ///< Add to the map containing the cookie variables, expected option value type: const char *, const char * 160 U_OPT_POST_BODY_PARAMETER = 17, ///< Add to the map containing the post body variables (if available), expected option value type: const char *, const char * 161 U_OPT_URL_PARAMETER_REMOVE = 18, ///< Remove from the map containing the url variables, both from the route and the ?key=value variables, expected option value type: const char * 162 U_OPT_HEADER_PARAMETER_REMOVE = 19, ///< Remove from map containing the header variables, expected option value type: const char * 163 U_OPT_COOKIE_PARAMETER_REMOVE = 20, ///< Remove from map containing the cookie variables, expected option value type: const char * 164 U_OPT_POST_BODY_PARAMETER_REMOVE = 21, ///< Remove from map containing the post body variables (if available), expected option value type: const char * 165 U_OPT_BINARY_BODY = 22, ///< Set a raw body to the request or the reponse, expected option value type: const char *, size_t 166 U_OPT_STRING_BODY = 23, ///< Set a char * body to the request or the reponse, expected option value type: const char * 167 #ifndef U_DISABLE_JANSSON 168 U_OPT_JSON_BODY = 24, ///< Set a stringified json_t * body to the request or the reponse, expected option value type: json_t * 169 #endif 170 #ifndef U_DISABLE_GNUTLS 171 U_OPT_CLIENT_CERT_FILE = 25, ///< path to client certificate file for sending http requests with certificate authentication, available only if GnuTLS support is enabled, expected option value type: const char * 172 U_OPT_CLIENT_KEY_FILE = 26, ///< path to client key file for sending http requests with certificate authentication, available only if GnuTLS support is enabled, expected option value type: const char * 173 U_OPT_CLIENT_KEY_PASSWORD = 27, ///< password to unlock client key file, available only if GnuTLS support is enabled, expected option value type: const char * 174 #endif 175 U_OPT_STATUS = 28, ///< HTTP response status code (200, 404, 500, etc), expected option value type: long 176 U_OPT_AUTH_REALM = 29, ///< realm to send to the client response on authenticationb failed, expected option value type: const char * 177 U_OPT_SHARED_DATA = 30, ///< any data shared between callback functions, must be allocated and freed by the callback functions, expected option value type: void * 178 U_OPT_HTTP_URL_APPEND = 31 ///< append char * value to the current url, expected option value type: const char * 179 } u_option; 180 181 /** 182 * @} 183 */ 184 185 /************* 186 * Structures 187 *************/ 188 189 /** 190 * @defgroup struct Structures 191 * structures definitions 192 * @{ 193 */ 194 195 /** 196 * struct _u_map 197 */ 198 struct _u_map { 199 int nb_values; /* !< Values count */ 200 char ** keys; /* !< Array of keys */ 201 char ** values; /* !< Array of values */ 202 size_t * lengths; /* !< Lengths of each values */ 203 }; 204 205 /** 206 * struct _u_cookie 207 * the structure containing the response cookie parameters 208 */ 209 struct _u_cookie { 210 char * key; /* !< key if the cookie */ 211 char * value; /* !< value of the cookie */ 212 char * expires; /* !< expiration date of the cookie */ 213 unsigned int max_age; /* !< duration of the cookie in seconds */ 214 char * domain; /* !< domain for the cookie */ 215 char * path; /* !< url path for the cookie */ 216 int secure; /* !< flag to set cookie secure or not */ 217 int http_only; /* !< flag to set cookie for HTTP connections only or not */ 218 int same_site; /* !< flag to set same_site option to the cookie */ 219 }; 220 221 /** 222 * 223 * @struct _u_request 224 * @brief definition of the parameters available in a struct _u_request 225 * 226 */ 227 struct _u_request { 228 char * http_protocol; /* !< http protocol used (1.0 or 1.1) */ 229 char * http_verb; /* !< http method (GET, POST, PUT, DELETE, etc.) */ 230 char * http_url; /* !< full url used to call this callback function or full url to call when used in a ulfius_send_http_request */ 231 char * url_path; /* !< url path only used to call this callback function (ex, if http_url is /path/?param=1, url_path is /path/) */ 232 char * proxy; /* !<proxy address to use for outgoing connections, used by ulfius_send_http_request */ 233 #if MHD_VERSION >= 0x00095208 234 unsigned short network_type; /* !< Force connect to ipv4, ipv6 addresses or both, values available are U_USE_ALL, U_USE_IPV4 or U_USE_IPV6 */ 235 #endif 236 int check_server_certificate; /* !< check server certificate and hostname, default true, used by ulfius_send_http_request */ 237 int check_server_certificate_flag; /* !< check certificate peer and or server hostname if check_server_certificate is enabled, values available are U_SSL_VERIFY_PEER, U_SSL_VERIFY_HOSTNAME or both, default value is both (U_SSL_VERIFY_PEER|U_SSL_VERIFY_HOSTNAME), used by ulfius_send_http_request */ 238 int check_proxy_certificate; /* !< check proxy certificate and hostname, default true, used by ulfius_send_http_request, requires libcurl >= 7.52 */ 239 int check_proxy_certificate_flag; /* !< check certificate peer and or proxy hostname if check_proxy_certificate is enabled, values available are U_SSL_VERIFY_PEER, U_SSL_VERIFY_HOSTNAME or both, default value is both (U_SSL_VERIFY_PEER|U_SSL_VERIFY_HOSTNAME), used by ulfius_send_http_request, requires libcurl >= 7.52 */ 240 int follow_redirect; /* !< follow url redirections, used by ulfius_send_http_request */ 241 char * ca_path; /* !< specify a path to CA certificates instead of system path, used by ulfius_send_http_request */ 242 unsigned long timeout; /* !< connection timeout used by ulfius_send_http_request, default is 0 */ 243 struct sockaddr * client_address; /* !< IP address of the client */ 244 char * auth_basic_user; /* !< basic authentication username */ 245 char * auth_basic_password; /* !< basic authentication password */ 246 struct _u_map * map_url; /* !< map containing the url variables, both from the route and the ?key=value variables */ 247 struct _u_map * map_header; /* !< map containing the header variables */ 248 struct _u_map * map_cookie; /* !< map containing the cookie variables */ 249 struct _u_map * map_post_body; /* !< map containing the post body variables (if available) */ 250 void * binary_body; /* !< raw body */ 251 size_t binary_body_length; /* !< length of raw body */ 252 unsigned int callback_position; /* !< position of the current callback function in the callback list, starts at 0 */ 253 #ifndef U_DISABLE_GNUTLS 254 gnutls_x509_crt_t client_cert; /* !< x509 certificate of the client if the instance uses client certificate authentication and the client is authenticated, available only if GnuTLS support is enabled */ 255 char * client_cert_file; /* !< path to client certificate file for sending http requests with certificate authentication, available only if GnuTLS support is enabled */ 256 char * client_key_file; /* !< path to client key file for sending http requests with certificate authentication, available only if GnuTLS support is enabled */ 257 char * client_key_password; /* !< password to unlock client key file, available only if GnuTLS support is enabled */ 258 #endif 259 }; 260 261 /** 262 * 263 * @struct _u_response 264 * @brief definition of the parameters available in a struct _u_response 265 * 266 */ 267 struct _u_response { 268 long status; /* !< HTTP status code (200, 404, 500, etc) */ 269 char * protocol; /* !< HTTP Protocol sent */ 270 struct _u_map * map_header; /* !< map containing the header variables */ 271 unsigned int nb_cookies; /* !< number of cookies sent */ 272 struct _u_cookie * map_cookie; /* !< array of cookies sent */ 273 char * auth_realm; /* !< realm to send to the client on authenticationb failed */ 274 void * binary_body; /* !< raw binary content */ 275 size_t binary_body_length; /* !< length of the binary_body */ 276 ssize_t (* stream_callback) (void * stream_user_data, uint64_t offset, char * out_buf, size_t max); /* !< callback function to stream data in response body */ 277 void (* stream_callback_free) (void * stream_user_data); /* !< callback function to free data allocated for streaming */ 278 uint64_t stream_size; /* !< size of the streamed data (U_STREAM_SIZE_UNKNOWN if unknown) */ 279 size_t stream_block_size; /* !< size of each block to be streamed, set according to your system */ 280 void * stream_user_data; /* !< user defined data that will be available in your callback stream functions */ 281 void * websocket_handle; /* !< handle for websocket extension */ 282 void * shared_data; /* !< any data shared between callback functions, must be allocated and freed by the callback functions */ 283 void (* free_shared_data)(void * shared_data); /* !< pointer to a function that will free shared_data */ 284 unsigned int timeout; /* !< Timeout in seconds to close the connection because of inactivity between the client and the server */ 285 }; 286 287 /** 288 * 289 * @struct _u_endpoint 290 * @brief Contains all informations needed for an endpoint 291 * 292 */ 293 struct _u_endpoint { 294 char * http_method; /* !< http verb (GET, POST, PUT, etc.) in upper case */ 295 char * url_prefix; /* !< prefix for the url (optional) */ 296 char * url_format; /* !< string used to define the endpoint format, separate words with / to define a variable in the url, prefix it with @ or :, example: /test/resource/:name/elements, on an url_format that ends with '*', the rest of the url will not be tested */ 297 unsigned int priority; /* !< endpoint priority in descending order (0 is the higher priority) */ 298 int (* callback_function)(const struct _u_request * request, /* !< pointer to a function that will be executed each time the endpoint is called, you must declare the function as described. */ 299 struct _u_response * response, 300 void * user_data); 301 void * user_data; /* !< pointer to a data or a structure that will be available in callback_function */ 302 }; 303 304 /** 305 * 306 * @struct _u_instance 307 * @brief Contains the needed data for an ulfius instance to work 308 * 309 */ 310 struct _u_instance { 311 struct MHD_Daemon * mhd_daemon; /* !< pointer to the libmicrohttpd daemon */ 312 int status; /* !< status of the current instance, status are U_STATUS_STOP, U_STATUS_RUNNING or U_STATUS_ERROR */ 313 unsigned int port; /* !< port number to listen to */ 314 #if MHD_VERSION >= 0x00095208 315 unsigned short network_type; /* !< Listen to ipv4 and or ipv6 connections, values available are U_USE_ALL, U_USE_IPV4 or U_USE_IPV6 */ 316 #endif 317 struct sockaddr_in * bind_address; /* !< ipv4 address to listen to (optional) */ 318 struct sockaddr_in6 * bind_address6; /* !< ipv6 address to listen to (optional) */ 319 unsigned int timeout; /* !< Timeout to close the connection because of inactivity between the client and the server */ 320 int nb_endpoints; /* !< Number of available endpoints */ 321 char * default_auth_realm; /* !< Default realm on authentication error */ 322 struct _u_endpoint * endpoint_list; /* !< List of available endpoints */ 323 struct _u_endpoint * default_endpoint; /* !< Default endpoint if no other endpoint match the current url */ 324 struct _u_map * default_headers; /* !< Default headers that will be added to all response->map_header */ 325 size_t max_post_param_size; /* !< maximum size for a post parameter, 0 means no limit, default 0 */ 326 size_t max_post_body_size; /* !< maximum size for the entire post body, 0 means no limit, default 0 */ 327 void * websocket_handler; /* !< handler for the websocket structure */ 328 int (* file_upload_callback) (const struct _u_request * request, /* !< callback function to manage file upload by blocks */ 329 const char * key, 330 const char * filename, 331 const char * content_type, 332 const char * transfer_encoding, 333 const char * data, 334 uint64_t off, 335 size_t size, 336 void * cls); 337 void * file_upload_cls; /* !< any pointer to pass to the file_upload_callback function */ 338 int mhd_response_copy_data; /* !< to choose between MHD_RESPMEM_MUST_COPY and MHD_RESPMEM_MUST_FREE, only if you use MHD < 0.9.61, otherwise this option is skipped because it's useless */ 339 int check_utf8; /* !< check that all parameters values in the request (url, header and post_body), are valid utf8 strings, if a parameter value has non utf8 character, the value, will be ignored, default 1 */ 340 #ifndef U_DISABLE_GNUTLS 341 int use_client_cert_auth; /* !< Internal variable use to indicate if the instance uses client certificate authentication, Do not change this value, available only if websocket support is enabled */ 342 #endif 343 }; 344 345 /** 346 * @} 347 */ 348 349 /** 350 * Structures used to facilitate data manipulations (internal) 351 */ 352 struct connection_info_struct { 353 struct _u_instance * u_instance; 354 struct MHD_PostProcessor * post_processor; 355 int has_post_processor; 356 int callback_first_iteration; 357 struct _u_request * request; 358 size_t max_post_param_size; 359 struct _u_map map_url_initial; 360 }; 361 362 /********************************** 363 * Instance functions declarations 364 **********************************/ 365 366 /** 367 * @defgroup mem memory 368 * memory management function 369 * @{ 370 */ 371 372 /** 373 * free data allocated by ulfius functions 374 * @param data data to free 375 */ 376 void u_free(void * data); 377 378 /** 379 * Initialize global parameters 380 * This function isn't thread-safe so it must be called once before any call to 381 * ulfius_send_http_request, ulfius_send_http_streaming_request, ulfius_send_smtp_email or ulfius_send_smtp_rich_email 382 * The function ulfius_send_request_close must be called when ulfius send request functions are no longer needed 383 * @return U_OK on success 384 */ 385 int ulfius_global_init(); 386 387 /** 388 * Close global parameters 389 */ 390 void ulfius_global_close(); 391 392 /** 393 * @} 394 */ 395 396 /** 397 * @defgroup instance struct _u_instance 398 * struct _u_instance management functions 399 * @{ 400 */ 401 402 /** 403 * ulfius_init_instance 404 * 405 * Initialize a struct _u_instance * with default values 406 * Binds to IPV4 addresses only 407 * @param u_instance the ulfius instance to initialize 408 * @param port tcp port to bind to, must be between 1 and 65535 409 * @param bind_address IPv4 address to listen to, optional, the reference is borrowed, the structure isn't copied 410 * @param default_auth_realm default realm to send to the client on authentication error 411 * @return U_OK on success 412 */ 413 int ulfius_init_instance(struct _u_instance * u_instance, unsigned int port, struct sockaddr_in * bind_address, const char * default_auth_realm); 414 415 #if MHD_VERSION >= 0x00095208 416 /** 417 * ulfius_init_instance_ipv6 418 * 419 * Initialize a struct _u_instance * with default values 420 * Binds to IPV6 and IPV4 addresses or IPV6 addresses only 421 * @param port tcp port to bind to, must be between 1 and 65535 422 * @param bind_address IPv6 address to listen to, optional, the reference is borrowed, the structure isn't copied 423 * @param network_type Type of network to listen to, values available are U_USE_IPV6 or U_USE_ALL 424 * @param default_auth_realm default realm to send to the client on authentication error 425 * @return U_OK on success 426 */ 427 int ulfius_init_instance_ipv6(struct _u_instance * u_instance, unsigned int port, struct sockaddr_in6 * bind_address, unsigned short network_type, const char * default_auth_realm); 428 #endif 429 430 /** 431 * ulfius_clean_instance 432 * 433 * Clean memory allocated by a struct _u_instance * 434 * @param u_instance an Ulfius instance 435 */ 436 void ulfius_clean_instance(struct _u_instance * u_instance); 437 438 /** 439 * ulfius_start_framework 440 * Initializes the framework and run the webservice based on the parameters given 441 * 442 * @param u_instance pointer to a struct _u_instance that describe its port and bind address 443 * @return U_OK on success 444 */ 445 int ulfius_start_framework(struct _u_instance * u_instance); 446 447 /** 448 * ulfius_start_secure_framework 449 * Initializes the framework and run the webservice based on the parameters given using an HTTPS connection 450 * 451 * @param u_instance pointer to a struct _u_instance that describe its port and bind address 452 * @param key_pem private key for the server 453 * @param cert_pem server certificate 454 * @return U_OK on success 455 */ 456 int ulfius_start_secure_framework(struct _u_instance * u_instance, const char * key_pem, const char * cert_pem); 457 458 #ifndef U_DISABLE_GNUTLS 459 /** 460 * ulfius_start_secure_ca_trust_framework 461 * Initializes the framework and run the webservice based on the parameters given using an HTTPS connection 462 * And using a root server to authenticate client connections 463 * 464 * @param u_instance pointer to a struct _u_instance that describe its port and bind address 465 * @param key_pem private key for the server 466 * @param cert_pem server certificate 467 * @param root_ca_pem client root CA you're willing to trust for this instance 468 * @return U_OK on success 469 */ 470 int ulfius_start_secure_ca_trust_framework(struct _u_instance * u_instance, const char * key_pem, const char * cert_pem, const char * root_ca_pem); 471 #endif 472 473 /** 474 * ulfius_start_framework_with_mhd_options 475 * Initializes the framework and run the webservice based on the specified MHD options table given in parameter 476 * Read https://www.gnu.org/software/libmicrohttpd/tutorial.html for more information 477 * This is for user who know what they do, Ulfius' options used in other `ulfius_start_framework_*` 478 * are good for most use cases where you need a multi-threaded HTTP webservice 479 * Some struct MHD_OptionItem may cause unexpected problems with Ulfius API 480 * If you find an unresolved issue with this function you can open an issue in GitHub 481 * But some issues may not be solvable if fixing them would break Ulfius API or philosophy 482 * i.e.: you're on your own 483 * @param u_instance pointer to a struct _u_instance that describe its port and bind address 484 * @param mhd_flags OR-ed combination of MHD_FLAG values 485 * @param mhd_ops struct MHD_OptionItem * options table, 486 * - MUST contain an option with the fllowing value: {.option = MHD_OPTION_NOTIFY_COMPLETED; .value = (intptr_t)mhd_request_completed; .ptr_value = NULL;} 487 * - MUST contain an option with the fllowing value: {.option = MHD_OPTION_URI_LOG_CALLBACK; .value = (intptr_t)ulfius_uri_logger; .ptr_value = NULL;} 488 * - MUST end with a terminal struct MHD_OptionItem: {.option = MHD_OPTION_END; .value = 0; .ptr_value = NULL;} 489 * @return U_OK on success 490 */ 491 int ulfius_start_framework_with_mhd_options(struct _u_instance * u_instance, unsigned int mhd_flags, struct MHD_OptionItem * options); 492 493 /** 494 * Internal functions externalized to use ulfius_start_framework_with_mhd_options 495 */ 496 void mhd_request_completed (void *cls, struct MHD_Connection *connection, void **con_cls, enum MHD_RequestTerminationCode toe); 497 void * ulfius_uri_logger (void * cls, const char * uri); 498 499 /** 500 * ulfius_stop_framework 501 * 502 * Stop the webservice 503 * @param u_instance pointer to a struct _u_instance that describe its port and bind address 504 * @return U_OK on success 505 */ 506 int ulfius_stop_framework(struct _u_instance * u_instance); 507 508 /** 509 * ulfius_set_upload_file_callback_function 510 * 511 * Set the callback function to handle file upload 512 * Used to facilitate large files upload management 513 * The callback function file_upload_callback will be called 514 * multiple times, with the uploaded file in striped in parts 515 * 516 * Warning: If this function is used, all the uploaded files 517 * for the instance will be managed via this function, and they 518 * will no longer be available in the struct _u_request in the 519 * ulfius callback function afterwards. 520 * 521 * Thanks to Thad Phetteplace for the help on this feature 522 * 523 * @param u_instance pointer to a struct _u_instance that describe its port and bind address 524 * @param file_upload_callback Pointer to a callback function that will handle all file uploads 525 * @param cls a pointer that will be passed to file_upload_callback each tim it's called 526 * @return U_OK on success 527 */ 528 int ulfius_set_upload_file_callback_function(struct _u_instance * u_instance, 529 int (* file_upload_callback) (const struct _u_request * request, 530 const char * key, 531 const char * filename, 532 const char * content_type, 533 const char * transfer_encoding, 534 const char * data, 535 uint64_t off, 536 size_t size, 537 void * cls), 538 void * cls); 539 540 /** 541 * @} 542 */ 543 544 /** 545 * @defgroup endpoints struct _u_endpoint 546 * struct _u_endpoint management functions 547 * @{ 548 */ 549 550 /*********************************** 551 * Endpoints functions declarations 552 ***********************************/ 553 554 /** 555 * Add a struct _u_endpoint * to the specified u_instance 556 * Can be done during the execution of the webservice for injection 557 * @param u_instance pointer to a struct _u_instance that describe its port and bind address 558 * @param u_endpoint pointer to a struct _u_endpoint that will be copied in the u_instance endpoint_list 559 * @return U_OK on success 560 */ 561 int ulfius_add_endpoint(struct _u_instance * u_instance, const struct _u_endpoint * u_endpoint); 562 563 /** 564 * Add a struct _u_endpoint * to the specified u_instance with its values specified 565 * Can be done during the execution of the webservice for injection 566 * @param u_instance pointer to a struct _u_instance that describe its port and bind address 567 * @param http_method http verb (GET, POST, PUT, etc.) in upper case 568 * @param url_prefix prefix for the url (optional) 569 * @param url_format string used to define the endpoint format 570 * separate words with / 571 * to define a variable in the url, prefix it with @ or : 572 * example: /test/resource/:name/elements 573 * on an url_format that ends with '*', the rest of the url will not be tested 574 * @param priority endpoint priority in descending order (0 is the higher priority) 575 * @param callback_function a pointer to a function that will be executed each time the endpoint is called 576 * you must declare the function as described. 577 * @param user_data a pointer to a data or a structure that will be available in callback_function 578 * @return U_OK on success 579 */ 580 int ulfius_add_endpoint_by_val(struct _u_instance * u_instance, 581 const char * http_method, 582 const char * url_prefix, 583 const char * url_format, 584 unsigned int priority, 585 int (* callback_function)(const struct _u_request * request, // Input parameters (set by the framework) 586 struct _u_response * response, // Output parameters (set by the user) 587 void * user_data), 588 void * user_data); 589 590 /** 591 * Add a struct _u_endpoint * list to the specified u_instance 592 * Can be done during the execution of the webservice for injection 593 * @param u_instance pointer to a struct _u_instance that describe its port and bind address 594 * @param u_endpoint_list pointer to an array of struct _u_endpoint ending with a ulfius_empty_endpoint() that will be copied in the u_instance endpoint_list 595 * @return U_OK on success 596 */ 597 int ulfius_add_endpoint_list(struct _u_instance * u_instance, const struct _u_endpoint ** u_endpoint_list); 598 599 /** 600 * Remove a struct _u_endpoint * from the specified u_instance 601 * Can be done during the execution of the webservice for injection 602 * @param u_instance pointer to a struct _u_instance that describe its port and bind address 603 * @param u_endpoint pointer to a struct _u_endpoint that will be removed in the u_instance endpoint_list 604 * The parameters _u_endpoint.http_method, _u_endpoint.url_prefix and _u_endpoint.url_format are strictly compared for the match 605 * If no endpoint is found, return U_ERROR_NOT_FOUND 606 * @return U_OK on success 607 */ 608 int ulfius_remove_endpoint(struct _u_instance * u_instance, const struct _u_endpoint * u_endpoint); 609 610 /** 611 * ulfius_set_default_endpoint 612 * Set the default endpoint 613 * This endpoint will be called if no endpoint match the url called 614 * @param u_instance pointer to a struct _u_instance that describe its port and bind address 615 * @param callback_function a pointer to a function that will be executed each time the endpoint is called 616 * you must declare the function as described. 617 * @param user_data a pointer to a data or a structure that will be available in callback_function 618 * to remove a default endpoint, call ulfius_set_default_endpoint with NULL parameter for callback_function 619 * @return U_OK on success 620 */ 621 int ulfius_set_default_endpoint(struct _u_instance * u_instance, 622 int (* callback_function)(const struct _u_request * request, struct _u_response * response, void * user_data), 623 void * user_data); 624 625 /** 626 * Remove a struct _u_endpoint * from the specified u_instance 627 * using the specified values used to identify an endpoint 628 * Can be done during the execution of the webservice for injection 629 * The parameters _u_endpoint.http_method, _u_endpoint.url_prefix and _u_endpoint.url_format are strictly compared for the match 630 * If no endpoint is found, return U_ERROR_NOT_FOUND 631 * @param u_instance pointer to a struct _u_instance that describe its port and bind address 632 * @param http_method http_method used by the endpoint 633 * @param url_prefix url_prefix used by the endpoint 634 * @param url_format url_format used by the endpoint 635 * @return U_OK on success 636 */ 637 int ulfius_remove_endpoint_by_val(struct _u_instance * u_instance, const char * http_method, const char * url_prefix, const char * url_format); 638 639 /** 640 * ulfius_empty_endpoint 641 * @return empty endpoint that goes at the end of an endpoint list 642 */ 643 const struct _u_endpoint * ulfius_empty_endpoint(); 644 645 /** 646 * ulfius_copy_endpoint 647 * makes a copy of an endpoint with duplicate values 648 * @param dest the endpoint destination 649 * @param source the endpoint source 650 * @return U_OK on success 651 */ 652 int ulfius_copy_endpoint(struct _u_endpoint * dest, const struct _u_endpoint * source); 653 654 /** 655 * u_copy_endpoint_list 656 * makes a copy of an endpoint list with duplicate values 657 * @param endpoint_list an array of struct _u_endpoint * finishing with a ulfius_empty_endpoint() 658 * @return a list with duplicate values 659 * returned value must be free'd after use 660 */ 661 struct _u_endpoint * ulfius_duplicate_endpoint_list(const struct _u_endpoint * endpoint_list); 662 663 /** 664 * ulfius_clean_endpoint 665 * free allocated memory by an endpoint 666 * @param endpoint the endpoint to cleanup 667 */ 668 void ulfius_clean_endpoint(struct _u_endpoint * endpoint); 669 670 /** 671 * ulfius_clean_endpoint_list 672 * free allocated memory by an endpoint list 673 * @param endpoint_list the list of endpoints to cleanup, finishing with a ulfius_empty_endpoint() 674 */ 675 void ulfius_clean_endpoint_list(struct _u_endpoint * endpoint_list); 676 677 /** 678 * ulfius_equals_endpoints 679 * Compare 2 endpoints 680 * @param endpoint1 the first endpoint to compare 681 * @param endpoint2 the second endpoint to compare 682 * @return true if their method, prefix and format are the same or if both are NULL, false otherwise 683 */ 684 int ulfius_equals_endpoints(const struct _u_endpoint * endpoint1, const struct _u_endpoint * endpoint2); 685 686 /** 687 * @} 688 */ 689 690 /** 691 * @defgroup http_smtp_client Client HTTP and SMTP 692 * client HTTP and SMTP requests management functions 693 * @{ 694 */ 695 696 #ifndef U_DISABLE_CURL 697 /******************************************** 698 * Requests/Responses functions declarations 699 ********************************************/ 700 701 /** 702 * ulfius_send_http_request 703 * Send a HTTP request and store the result into a _u_response 704 * @param request the struct _u_request that contains all the input parameters to perform the HTTP request 705 * @param response the struct _u_response that will be filled with all response parameter values, optional, may be NULL 706 * @return U_OK on success 707 */ 708 int ulfius_send_http_request(const struct _u_request * request, struct _u_response * response); 709 710 /** 711 * ulfius_send_http_streaming_request 712 * Send a HTTP request and store the result into a _u_response 713 * Except for the body which will be available using write_body_function in the write_body_data 714 * @param request the struct _u_request that contains all the input parameters to perform the HTTP request 715 * @param response the struct _u_response that will be filled with all response parameter values, optional, may be NULL 716 * @param write_body_function a pointer to a function that will be used to receive response body in chunks 717 * @param write_body_data a user-defined poitner that will be passed in parameter to write_body_function 718 * @return U_OK on success 719 */ 720 int ulfius_send_http_streaming_request(const struct _u_request * request, struct _u_response * response, size_t (* write_body_function)(void * contents, size_t size, size_t nmemb, void * user_data), void * write_body_data); 721 722 /** 723 * ulfius_send_smtp_email 724 * Send an email using libcurl 725 * email is plain/text and UTF8 charset 726 * @param host smtp server host name 727 * @param port tcp port number (optional, 0 for default) 728 * @param use_tls true if the connection is tls secured 729 * @param verify_certificate true if you want to disable the certificate verification on a tls server 730 * @param user connection user name (optional, NULL: no user name) 731 * @param password connection password (optional, NULL: no password) 732 * @param from from address (mandatory) 733 * @param to to recipient address (mandatory) 734 * @param cc cc recipient address (optional, NULL: no cc) 735 * @param bcc bcc recipient address (optional, NULL: no bcc) 736 * @param subject email subject (mandatory) 737 * @param mail_body email body (mandatory) 738 * @return U_OK on success 739 */ 740 int ulfius_send_smtp_email(const char * host, 741 const int port, 742 const int use_tls, 743 const int verify_certificate, 744 const char * user, 745 const char * password, 746 const char * from, 747 const char * to, 748 const char * cc, 749 const char * bcc, 750 const char * subject, 751 const char * mail_body); 752 753 /** 754 * Send an email using libcurl 755 * email has the content-type specified in parameter 756 * @param host smtp server host name 757 * @param port tcp port number (optional, 0 for default) 758 * @param use_tls true if the connection is tls secured 759 * @param verify_certificate true if you want to disable the certificate verification on a tls server 760 * @param user connection user name (optional, NULL: no user name) 761 * @param password connection password (optional, NULL: no password) 762 * @param from from address (mandatory) 763 * @param to to recipient address (mandatory) 764 * @param cc cc recipient address (optional, NULL: no cc) 765 * @param bcc bcc recipient address (optional, NULL: no bcc) 766 * @param content_type: content-type to add to the e-mail body 767 * @param subject email subject (mandatory) 768 * @param mail_body email body (mandatory) 769 * @return U_OK on success 770 */ 771 772 int ulfius_send_smtp_rich_email(const char * host, 773 const int port, 774 const int use_tls, 775 const int verify_certificate, 776 const char * user, 777 const char * password, 778 const char * from, 779 const char * to, 780 const char * cc, 781 const char * bcc, 782 const char * content_type, 783 const char * subject, 784 const char * mail_body); 785 #endif 786 787 /** 788 * @} 789 */ 790 791 /** 792 * @defgroup cookie Cookies 793 * Cookies management functions 794 * @{ 795 */ 796 797 /** 798 * ulfius_add_cookie_to_response 799 * add a cookie to the cookie map 800 * @param response the response to add the cookie to 801 * @param key the cookie key 802 * @param value the cookie value 803 * @param expires the expiration date of the ccokie in ISO format (optional) 804 * @param max_age the maximum age of the cookie in seconds (optional) 805 * @param domain the domain of the cookie (optional) 806 * @param path the path of the cookie (optional) 807 * @param secure wether the cookie must be secure or not (optional) 808 * @param http_only wether the cookie must be used only for http requests or not (optional) 809 * @return U_OK on success 810 */ 811 int ulfius_add_cookie_to_response(struct _u_response * response, const char * key, const char * value, const char * expires, const unsigned int max_age, 812 const char * domain, const char * path, const int secure, const int http_only); 813 814 /** 815 * ulfius_add_same_site_cookie_to_response 816 * add a cookie to the cookie map with a SameSite attribute 817 * @param response the response to add the cookie to 818 * @param key the cookie key 819 * @param value the cookie value 820 * @param expires the expiration date of the ccokie in ISO format (optional) 821 * @param max_age the maximum age of the cookie in seconds (optional) 822 * @param domain the domain of the cookie (optional) 823 * @param path the path of the cookie (optional) 824 * @param secure wether the cookie must be secure or not (optional) 825 * @param http_only wether the cookie must be used only for http requests or not (optional) 826 * @param same_site parameter must have one of the following values: 827 * - U_COOKIE_SAME_SITE_NONE - No SameSite attribute 828 * - U_COOKIE_SAME_SITE_STRICT - SameSite attribute set to 'Strict' 829 * - U_COOKIE_SAME_SITE_LAX - SameSite attribute set to 'Lax' 830 * @return U_OK on success 831 */ 832 int ulfius_add_same_site_cookie_to_response(struct _u_response * response, const char * key, const char * value, const char * expires, const unsigned int max_age, 833 const char * domain, const char * path, const int secure, const int http_only, const int same_site); 834 835 /** 836 * @} 837 */ 838 839 /** 840 * @defgroup parameters URL, POST and Header parameters 841 * URL, POST and Header management functions 842 * @{ 843 */ 844 845 /** 846 * ulfius_add_header_to_response 847 * add a header to the response 848 * @param response the response to be updated 849 * @param key the key of the header 850 * @param value the value of the header 851 * @return U_OK on success 852 */ 853 int ulfius_add_header_to_response(struct _u_response * response, const char * key, const char * value); 854 855 /** 856 * ulfius_set_string_body_request 857 * Set a string string_body to a request, replace any existing body in the request 858 * @param request the request to be updated 859 * @param string_body string to set to the body response must end with a '\0' character 860 * @return U_OK on success 861 */ 862 int ulfius_set_string_body_request(struct _u_request * request, const char * string_body); 863 864 /** 865 * ulfius_set_binary_body_request 866 * Set a binary binary_body to a request, replace any existing body in the request 867 * @param request the request to be updated 868 * @param binary_body an array of char to set to the body response 869 * @param length the length of binary_body to set to the request body 870 * return U_OK on success 871 */ 872 int ulfius_set_binary_body_request(struct _u_request * request, const char * binary_body, const size_t length); 873 874 /** 875 * ulfius_set_empty_body_request 876 * Set an empty request body 877 * @param request the request to be updated 878 * @return U_OK on success 879 */ 880 int ulfius_set_empty_body_request(struct _u_request * request); 881 882 /** 883 * ulfius_set_string_body_response 884 * Add a string body to a response, replace any existing body in the response 885 * @param response the response to be updated 886 * @param status the http status code to set to the response 887 * @param body the string body to set, must end with a '\0' character 888 * @return U_OK on success 889 */ 890 int ulfius_set_string_body_response(struct _u_response * response, const unsigned int status, const char * body); 891 892 /** 893 * ulfius_set_binary_body_response 894 * Add a binary body to a response, replace any existing body in the response 895 * @param response the response to be updated 896 * @param status the http status code to set to the response 897 * @param body the array of char to set 898 * @param length the length of body to set to the request body 899 * @return U_OK on success 900 */ 901 int ulfius_set_binary_body_response(struct _u_response * response, const unsigned int status, const char * body, const size_t length); 902 903 /** 904 * ulfius_set_empty_body_response 905 * Set an empty response with only a status 906 * @param response the response to be updated 907 * @param status the http status code to set to the response 908 * @return U_OK on success 909 */ 910 int ulfius_set_empty_body_response(struct _u_response * response, const unsigned int status); 911 912 /** 913 * @} 914 */ 915 916 /** 917 * @defgroup stream Response streaming 918 * Response streaming function 919 * @{ 920 */ 921 922 /** 923 * ulfius_set_stream_response 924 * Set an stream response with a status 925 * @param response the response to be updated 926 * @param status the http status code to set to the response 927 * @param stream_callback a pointer to a function that will handle the response stream 928 * @param stream_callback_free a pointer to a function that will free its allocated resoures during stream_callback 929 * @param stream_size size of the streamed data (U_STREAM_SIZE_UNKNOWN if unknown) 930 * @param stream_block_size preferred size of each stream chunk, may be overwritten by the system if necessary 931 * @param stream_user_data a user-defined pointer that will be available in stream_callback and stream_callback_free 932 * @return U_OK on success 933 */ 934 int ulfius_set_stream_response(struct _u_response * response, 935 const unsigned int status, 936 ssize_t (* stream_callback) (void * stream_user_data, uint64_t offset, char * out_buf, size_t max), 937 void (* stream_callback_free) (void * stream_user_data), 938 uint64_t stream_size, 939 size_t stream_block_size, 940 void * stream_user_data); 941 942 /** 943 * @} 944 */ 945 946 /** 947 * @defgroup request_response_cookie struct _u_request, struct _u_response and struct _u_cookie 948 * struct _u_request, struct _u_response and struct _u_cookie management functions 949 * @{ 950 */ 951 952 /** 953 * ulfius_init_request 954 * Initialize a request structure by allocating inner elements 955 * @param request the request to initialize 956 * @return U_OK on success 957 */ 958 int ulfius_init_request(struct _u_request * request); 959 960 /** 961 * ulfius_clean_request 962 * clean the specified request's inner elements 963 * user must free the parent pointer if needed after clean 964 * or use ulfius_clean_request_full 965 * @param request the request to cleanup 966 * @return U_OK on success 967 */ 968 int ulfius_clean_request(struct _u_request * request); 969 970 /** 971 * ulfius_clean_request_full 972 * clean the specified request and all its elements 973 * @param request the request to cleanup 974 * @return U_OK on success 975 */ 976 int ulfius_clean_request_full(struct _u_request * request); 977 978 /** 979 * ulfius_copy_request 980 * Copy the source request elements into the dest request 981 * @param dest the request to receive the copied data 982 * @param source the source request to copy 983 * @return U_OK on success 984 */ 985 int ulfius_copy_request(struct _u_request * dest, const struct _u_request * source); 986 987 /** 988 * ulfius_set_request_properties 989 * Set a list of properties to a request 990 * return U_OK on success 991 */ 992 int ulfius_set_request_properties(struct _u_request * request, ...); 993 994 /** 995 * Initialize a response structure by allocating inner elements 996 * @param response the response to initialize 997 * @return U_OK on success 998 */ 999 int ulfius_init_response(struct _u_response * response); 1000 1001 /** 1002 * ulfius_clean_response 1003 * clean the specified response's inner elements 1004 * user must free the parent pointer if needed after clean 1005 * or use ulfius_clean_response_full 1006 * @param response the response to cleanup 1007 * @return U_OK on success 1008 */ 1009 int ulfius_clean_response(struct _u_response * response); 1010 1011 /** 1012 * clean the specified response and all its elements 1013 * @param response the response to cleanup 1014 * @return U_OK on success 1015 */ 1016 int ulfius_clean_response_full(struct _u_response * response); 1017 1018 /** 1019 * Copy the source response elements into the dest response 1020 * @param dest the response to receive the copied data 1021 * @param source the source response to copy 1022 * @return U_OK on success 1023 */ 1024 int ulfius_copy_response(struct _u_response * dest, const struct _u_response * source); 1025 1026 /** 1027 * ulfius_clean_cookie 1028 * clean the cookie's elements 1029 * @param cookie the cookie structure to cleanup 1030 * @return U_OK on success 1031 */ 1032 int ulfius_clean_cookie(struct _u_cookie * cookie); 1033 1034 /** 1035 * Copy the cookie source elements into dest elements 1036 * @param dest the cookie to receive the copied data 1037 * @param source the cookie response to copy 1038 * @return U_OK on success 1039 */ 1040 int ulfius_copy_cookie(struct _u_cookie * dest, const struct _u_cookie * source); 1041 1042 /** 1043 * create a new request based on the source elements 1044 * returned value must be cleaned after use 1045 * @param request the request to duplicate 1046 * @return a heap-allocated request 1047 */ 1048 struct _u_request * ulfius_duplicate_request(const struct _u_request * request); 1049 1050 /** 1051 * create a new response based on the source elements 1052 * return value must be cleaned after use 1053 * @param response the response to duplicate 1054 * @return a heap-allocated response 1055 */ 1056 struct _u_response * ulfius_duplicate_response(const struct _u_response * response); 1057 1058 /** 1059 * Set a list of properties to a response 1060 * @param response the response to set values to 1061 * @return U_OK on success 1062 */ 1063 int ulfius_set_response_properties(struct _u_response * response, ...); 1064 1065 /** 1066 * Adds a shared_data pointer to the response 1067 * and the function to free the shared_data at the end of the callback list 1068 * @param response the response to set values to 1069 * @param shared_data a pointer that will be transmitted to every callback 1070 * @param free_shared_data a pointer to a function that will free shared_data at the end of the callback list 1071 * @return U_OK on success 1072 */ 1073 int ulfius_set_response_shared_data(struct _u_response * response, void * shared_data, void (* free_shared_data) (void * shared_data)); 1074 1075 /** 1076 * @} 1077 */ 1078 1079 /** 1080 * @defgroup url_encode URL Encode 1081 * URL Encode functions 1082 * @{ 1083 */ 1084 1085 /** 1086 * Returns a url-decoded version of str 1087 * returned value must be cleaned after use 1088 * Thanks Geek Hideout! 1089 * http://www.geekhideout.com/urlcode.shtml 1090 * @param str the string to decode 1091 * @return a heap-allocated string 1092 */ 1093 char * ulfius_url_decode(const char * str); 1094 1095 /** 1096 * Returns a url-encoded version of str 1097 * returned value must be cleaned after use 1098 * Thanks Geek Hideout! 1099 * http://www.geekhideout.com/urlcode.shtml 1100 * @param str the string to encode 1101 * @return a heap-allocated string 1102 */ 1103 char * ulfius_url_encode(const char * str); 1104 1105 /** 1106 * @} 1107 */ 1108 1109 /** 1110 * @defgroup request_response_cookie struct _u_request, struct _u_response and struct _u_cookie 1111 * struct _u_request, struct _u_response and struct _u_cookie management functions 1112 * @{ 1113 */ 1114 1115 #ifndef U_DISABLE_JANSSON 1116 /** 1117 * ulfius_get_json_body_request 1118 * Get JSON structure from the request body if the request is valid 1119 * In case of an error in getting or parsing JSON data in the request, 1120 * the structure json_error_t * json_error will be filled with an error 1121 * message if json_error is not NULL 1122 * @param request the request to retrieve the JSON data 1123 * @param json_error a json_error_t reference that will contain decoding errors if any, may be NULL 1124 * @return a json_t * containing the JSON decoded, NULL on error 1125 */ 1126 json_t * ulfius_get_json_body_request(const struct _u_request * request, json_error_t * json_error); 1127 1128 /** 1129 * ulfius_set_json_body_request 1130 * Add a json_t j_body to a request 1131 * @param request the request to retrieve the JSON data 1132 * @param j_body a json_t to stringify in the body 1133 * @return U_OK on success 1134 */ 1135 int ulfius_set_json_body_request(struct _u_request * request, json_t * j_body); 1136 1137 /** 1138 * ulfius_get_json_body_response 1139 * Get JSON structure from the response body if the response is valid 1140 * In case of an error in getting or parsing JSON data in the response, 1141 * the structure json_error_t * json_error will be filled with an error 1142 * message if json_error is not NULL 1143 * @param response the response to retrieve the JSON data 1144 * @param json_error a json_error_t reference that will contain decoding errors if any, may be NULL 1145 * @return a json_t * containing the JSON decoded, NULL on error 1146 */ 1147 json_t * ulfius_get_json_body_response(struct _u_response * response, json_error_t * json_error); 1148 1149 /** 1150 * ulfius_set_json_body_response 1151 * Add a json_t j_body to a response 1152 * @param response the response to retrieve the JSON data 1153 * @param status the HTTP status for the response 1154 * @param j_body a json_t to stringify in the body 1155 * @return U_OK on success 1156 */ 1157 int ulfius_set_json_body_response(struct _u_response * response, const unsigned int status, const json_t * j_body); 1158 #endif 1159 1160 /** 1161 * @} 1162 */ 1163 1164 /** 1165 * @defgroup u_map struct _u_map 1166 * struct _u_map management functions 1167 * @{ 1168 */ 1169 1170 /************************************************************************ 1171 * _u_map declarations * 1172 * _u_map is a simple map structure that handles sets of key/value maps * 1173 ************************************************************************/ 1174 1175 /** 1176 * initialize a struct _u_map 1177 * this function MUST be called after a declaration or allocation 1178 * @param u_map the _u_map to initialize 1179 * @return U_OK on success 1180 */ 1181 int u_map_init(struct _u_map * u_map); 1182 1183 /** 1184 * free the struct _u_map's inner components 1185 * @param u_map the _u_map to cleanup 1186 * @return U_OK on success 1187 */ 1188 int u_map_clean(struct _u_map * u_map); 1189 1190 /** 1191 * free the struct _u_map and its components 1192 * @param u_map the _u_map to cleanup 1193 * @return U_OK on success 1194 */ 1195 int u_map_clean_full(struct _u_map * u_map); 1196 1197 /** 1198 * free an enum return by functions u_map_enum_keys or u_map_enum_values 1199 * @param array the string array to cleanup 1200 * @return U_OK on success 1201 */ 1202 int u_map_clean_enum(char ** array); 1203 1204 /** 1205 * returns an array containing all the keys in the struct _u_map 1206 * @param u_map the _u_map to retreive the keys from 1207 * @return an array of char * ending with a NULL element 1208 */ 1209 const char ** u_map_enum_keys(const struct _u_map * u_map); 1210 1211 /** 1212 * returns an array containing all the values in the struct _u_map 1213 * @param u_map the _u_map to retreive the values from 1214 * @return an array of char * ending with a NULL element 1215 */ 1216 const char ** u_map_enum_values(const struct _u_map * u_map); 1217 1218 /** 1219 * Detects if the key exists in the _u_map 1220 * search is case sensitive 1221 * @param u_map the _u_map to analyze 1222 * @param key the key to look for 1223 * @return true if the sprcified u_map contains the specified key 1224 * false otherwise 1225 */ 1226 int u_map_has_key(const struct _u_map * u_map, const char * key); 1227 1228 /** 1229 * Detects if the value exists in the _u_map, value must be a char * string 1230 * search is case sensitive 1231 * @param u_map the _u_map to analyze 1232 * @param value the value to look for 1233 * @return true if the sprcified u_map contains the specified value 1234 * false otherwise 1235 */ 1236 int u_map_has_value(const struct _u_map * u_map, const char * value); 1237 1238 /** 1239 * Detects if the value exists in the _u_map, value may be any byte array 1240 * search is case sensitive 1241 * @param u_map the _u_map to analyze 1242 * @param value the value to look for 1243 * @param length the length of the value to look for 1244 * @return true if the sprcified u_map contains the specified value up until the specified length 1245 * false otherwise 1246 */ 1247 int u_map_has_value_binary(const struct _u_map * u_map, const char * value, size_t length); 1248 1249 /** 1250 * Detects if the key exists in the _u_map 1251 * search is case insensitive 1252 * @param u_map the _u_map to analyze 1253 * @param key the key to look for 1254 * @return true if the sprcified u_map contains the specified key 1255 * false otherwise 1256 */ 1257 int u_map_has_key_case(const struct _u_map * u_map, const char * key); 1258 1259 /** 1260 * Detects if the key exists in the _u_map 1261 * search is case insensitive 1262 * @param u_map the _u_map to analyze 1263 * @param value the value to look for 1264 * @return true if the sprcified u_map contains the specified value 1265 * false otherwise 1266 */ 1267 int u_map_has_value_case(const struct _u_map * u_map, const char * value); 1268 1269 /** 1270 * add the specified key/value pair into the specified u_map 1271 * if the u_map already contains a pair with the same key, replace the value 1272 * @param u_map the _u_map to update 1273 * @param key the key string 1274 * @param value the value string 1275 * @return U_OK on success 1276 */ 1277 int u_map_put(struct _u_map * u_map, const char * key, const char * value); 1278 1279 /** 1280 * add the specified key/binary value pair into the specified u_map 1281 * if the u_map already contains a pair with the same key, 1282 * replace the value at the specified offset with the specified length 1283 * @param u_map the _u_map to update 1284 * @param key the key string 1285 * @param value the value binary 1286 * @param offset the start offset to set value in u_map value 1287 * @param length the length of value to set 1288 * @return U_OK on success 1289 */ 1290 int u_map_put_binary(struct _u_map * u_map, const char * key, const char * value, uint64_t offset, size_t length); 1291 1292 /** 1293 * get the value length corresponding to the specified key in the u_map 1294 * search is case sensitive 1295 * @param u_map the _u_map to analyze 1296 * @param key the key look for 1297 * @return the value length if found, -1 if no match found 1298 */ 1299 ssize_t u_map_get_length(const struct _u_map * u_map, const char * key); 1300 1301 /** 1302 * get the value length corresponding to the specified key in the u_map 1303 * search is case insensitive 1304 * @param u_map the _u_map to analyze 1305 * @param key the key look for 1306 * @return the value length if found, -1 if no match found 1307 */ 1308 ssize_t u_map_get_case_length(const struct _u_map * u_map, const char * key); 1309 1310 /** 1311 * get the value corresponding to the specified key in the u_map 1312 * search is case sensitive 1313 * @param u_map the _u_map to analyze 1314 * @param key the key to look for 1315 * @return the value if key exists NULL if no match found 1316 */ 1317 const char * u_map_get(const struct _u_map * u_map, const char * key); 1318 1319 /** 1320 * get the value corresponding to the specified key in the u_map 1321 * search is case insensitive 1322 * @param u_map the _u_map to analyze 1323 * @param key the key to look for 1324 * @return the value if key exists NULL if no match found 1325 */ 1326 const char * u_map_get_case(const struct _u_map * u_map, const char * key); 1327 1328 /** 1329 * remove an pair key/value that has the specified key 1330 * search is case sensitive 1331 * @param u_map the _u_map to analyze 1332 * @param key the key to look for 1333 * @return U_OK on success, U_NOT_FOUND if key was not found, error otherwise 1334 */ 1335 int u_map_remove_from_key(struct _u_map * u_map, const char * key); 1336 1337 /** 1338 * remove all pairs key/value that has the specified key (case insensitive search) 1339 * search is case insensitive 1340 * @param u_map the _u_map to analyze 1341 * @param key the key to look for 1342 * @return U_OK on success, U_NOT_FOUND if key was not found, error otherwise 1343 */ 1344 int u_map_remove_from_key_case(struct _u_map * u_map, const char * key); 1345 1346 /** 1347 * remove all pairs key/value that has the specified value 1348 * search is case sensitive 1349 * @param u_map the _u_map to analyze 1350 * @param value the value to look for 1351 * @return U_OK on success, U_NOT_FOUND if key was not found, error otherwise 1352 */ 1353 int u_map_remove_from_value(struct _u_map * u_map, const char * value); 1354 1355 /** 1356 * remove all pairs key/value that has the specified value 1357 * search is case insensitive 1358 * @param u_map the _u_map to analyze 1359 * @param value the value to look for 1360 * @return U_OK on success, U_NOT_FOUND if key was not found, error otherwise 1361 */ 1362 int u_map_remove_from_value_case(struct _u_map * u_map, const char * value); 1363 1364 /** 1365 * remove all pairs key/value that has the specified value up until the specified length 1366 * @param u_map the _u_map to analyze 1367 * @param key the key to look for 1368 * @param length the length of key 1369 * @return U_OK on success, U_NOT_FOUND if key was not found, error otherwise 1370 */ 1371 int u_map_remove_from_value_binary(struct _u_map * u_map, const char * key, size_t length); 1372 1373 /** 1374 * remove the pair key/value at the specified index 1375 * @param u_map the _u_map to analyze 1376 * @param index the position of the tuple to remove 1377 * @return U_OK on success, U_NOT_FOUND if index is out of bound, error otherwise 1378 */ 1379 int u_map_remove_at(struct _u_map * u_map, const int index); 1380 1381 /** 1382 * Create an exact copy of the specified struct _u_map 1383 * @param source the _u_map to copy 1384 * @return a reference to the copy, NULL otherwise 1385 * returned value must be free'd after use 1386 */ 1387 struct _u_map * u_map_copy(const struct _u_map * source); 1388 1389 /** 1390 * Copy all key/values pairs of source into dest 1391 * If a key is already present in dest, value is overwritten 1392 * @param dest the _u_map to update 1393 * @param source the _u_map to copy 1394 * @return U_OK on success, error otherwise 1395 */ 1396 int u_map_copy_into(struct _u_map * dest, const struct _u_map * source); 1397 1398 /** 1399 * Count the number of elements in the _u_map 1400 * @param source the _u_map to analyze 1401 * @return the number of key/values pair in the specified struct _u_map 1402 * Return -1 on error 1403 */ 1404 int u_map_count(const struct _u_map * source); 1405 1406 /** 1407 * Empty a struct u_map of all its elements 1408 * @param u_map the _u_map to empty 1409 * @return U_OK on success, error otherwise 1410 */ 1411 int u_map_empty(struct _u_map * u_map); 1412 1413 /** 1414 * @} 1415 */ 1416 1417 /** 1418 * @defgroup websocket Websockets 1419 * Websocket management functions 1420 * @{ 1421 */ 1422 1423 #ifndef U_DISABLE_WEBSOCKET 1424 1425 /********************************** 1426 * Websocket functions declarations 1427 **********************************/ 1428 1429 #define U_WEBSOCKET_USER_AGENT "Ulfius Websocket Client Framework" 1430 1431 #define U_WEBSOCKET_MAGIC_STRING "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" 1432 #define U_WEBSOCKET_UPGRADE_VALUE "websocket" 1433 #define U_WEBSOCKET_BAD_REQUEST_BODY "Error in websocket handshake, wrong parameters" 1434 #define U_WEBSOCKET_USEC_WAIT 50 1435 #define WEBSOCKET_MAX_CLOSE_TRY 10 1436 1437 #define U_WEBSOCKET_BIT_FIN 0x80 1438 #define U_WEBSOCKET_MASK 0x80 1439 #define U_WEBSOCKET_LEN_MASK 0x7F 1440 #define U_WEBSOCKET_OPCODE_CONTINUE 0x00 1441 #define U_WEBSOCKET_OPCODE_TEXT 0x01 1442 #define U_WEBSOCKET_OPCODE_BINARY 0x02 1443 #define U_WEBSOCKET_OPCODE_CLOSE 0x08 1444 #define U_WEBSOCKET_OPCODE_PING 0x09 1445 #define U_WEBSOCKET_OPCODE_PONG 0x0A 1446 #define U_WEBSOCKET_OPCODE_CLOSED 0xFD 1447 #define U_WEBSOCKET_OPCODE_ERROR 0xFE 1448 #define U_WEBSOCKET_OPCODE_NONE 0xFF 1449 1450 #define U_WEBSOCKET_NONE 0 1451 #define U_WEBSOCKET_SERVER 1 1452 #define U_WEBSOCKET_CLIENT 2 1453 1454 #define U_WEBSOCKET_STATUS_OPEN 0 1455 #define U_WEBSOCKET_STATUS_CLOSE 1 1456 #define U_WEBSOCKET_STATUS_ERROR 2 1457 1458 #define U_WEBSOCKET_RSV1 0x40 1459 #define U_WEBSOCKET_RSV2 0x20 1460 #define U_WEBSOCKET_RSV3 0x10 1461 1462 #define WEBSOCKET_RESPONSE_HTTP 0x0001 1463 #define WEBSOCKET_RESPONSE_UPGRADE 0x0002 1464 #define WEBSOCKET_RESPONSE_CONNECTION 0x0004 1465 #define WEBSOCKET_RESPONSE_ACCEPT 0x0008 1466 #define WEBSOCKET_RESPONSE_PROTCOL 0x0010 1467 #define WEBSOCKET_RESPONSE_EXTENSION 0x0020 1468 1469 #define WEBSOCKET_DEFLATE_CHUNK_SIZE 32768 1470 #define WEBSOCKET_DEFLATE_WINDOWS_BITS 15 1471 1472 #define U_WEBSOCKET_KEEP_NONE 0x00 1473 #define U_WEBSOCKET_KEEP_INCOMING 0x01 1474 #define U_WEBSOCKET_KEEP_OUTCOMING 0x10 1475 1476 /** 1477 * @struct _websocket_deflate_context websocket extension permessage-deflate context 1478 */ 1479 struct _websocket_deflate_context { 1480 z_stream infstream; 1481 z_stream defstream; 1482 int deflate_mask; 1483 int inflate_mask; 1484 uint server_no_context_takeover; 1485 uint client_no_context_takeover; 1486 uint server_max_window_bits; 1487 uint client_max_window_bits; 1488 }; 1489 1490 /** 1491 * @struct _websocket_extension Websocket extension structure 1492 * contains callback functions and context to handle websocket extensions 1493 */ 1494 struct _websocket_extension { 1495 char * extension_server; 1496 char * extension_client; 1497 uint8_t rsv; 1498 int (* websocket_extension_message_out_perform)(const uint8_t opcode, 1499 const uint64_t data_len_in, 1500 const char * data_in, 1501 uint64_t * data_len_out, 1502 char ** data_out, 1503 const uint64_t fragment_len, 1504 void * user_data, 1505 void * context); 1506 void * websocket_extension_message_out_perform_user_data; 1507 int (* websocket_extension_message_in_perform)(const uint8_t opcode, 1508 const uint64_t data_len_in, 1509 const char * data_in, 1510 uint64_t * data_len_out, 1511 char ** data_out, 1512 const uint64_t fragment_len, 1513 void * user_data, 1514 void * context); 1515 void * websocket_extension_message_in_perform_user_data; 1516 int (* websocket_extension_server_match)(const char * extension_client, 1517 const char ** extension_client_list, 1518 char ** extension_server, 1519 void * user_data, 1520 void ** context); 1521 void * websocket_extension_server_match_user_data; 1522 int (* websocket_extension_client_match)(const char * extension_server, 1523 void * user_data, 1524 void ** context); 1525 void * websocket_extension_client_match_user_data; 1526 void (* websocket_extension_free_context)(void * user_data, 1527 void * context); 1528 void * websocket_extension_free_context_user_data; 1529 int enabled; 1530 void * context; 1531 }; 1532 1533 /** 1534 * @struct _websocket_manager Websocket manager structure 1535 * contains among other things the socket 1536 * the status (open, closed), and the list of incoming and outcoming messages 1537 * Used on public callback functions 1538 */ 1539 struct _websocket_manager { 1540 struct _websocket_message_list * message_list_incoming; /* !< list of incoming messages */ 1541 struct _websocket_message_list * message_list_outcoming; /* !< list of outcoming messages */ 1542 int keep_messages; /* !< keep incoming and/or outcoming messages, flags available are U_WEBSOCKET_KEEP_INCOMING, U_WEBSOCKET_KEEP_OUTCOMING, U_WEBSOCKET_KEEP_NONE, default is U_WEBSOCKET_KEEP_INCOMING|U_WEBSOCKET_KEEP_OUTCOMING */ 1543 int connected; /* !< flag to know if the websocket is connected or not */ 1544 int ping_sent; /* !< flag to know if the websocket has sent a ping frame or not, before receiving a pong */ 1545 int close_flag; /* !< flag to set before closing a websocket */ 1546 MHD_socket mhd_sock; /* !< reference to libmicrohttpd's socket for websocket server */ 1547 int tcp_sock; /* !< tcp socket for websocket client */ 1548 int tls; /* !< set to 1 if the websocket is in a TLS socket */ 1549 gnutls_session_t gnutls_session; /* !< GnuTLS session for websocket client */ 1550 gnutls_certificate_credentials_t xcred; /* !< certificate credential used by GnuTLS */ 1551 char * protocol; /* !< websocket protocol */ 1552 char * extensions; /* !< websocket extension */ 1553 pthread_mutex_t read_lock; /* !< mutex to read data in the socket */ 1554 pthread_mutex_t write_lock; /* !< mutex to write data in the socket */ 1555 pthread_mutex_t status_lock; /* !< mutex to broadcast new status */ 1556 pthread_cond_t status_cond; /* !< condition to broadcast new status */ 1557 struct pollfd fds_in; 1558 struct pollfd fds_out; 1559 int type; 1560 int rsv_expected; 1561 struct _pointer_list * websocket_extension_list; 1562 }; 1563 1564 /** 1565 * @struct _websocket_message websocket message structure 1566 * contains all the data of a websocket message 1567 * and the timestamp of when it was sent of received 1568 */ 1569 struct _websocket_message { 1570 time_t datestamp; /* !< date stamp of the message */ 1571 uint8_t rsv; /* !< flags RSV1-3 of the message */ 1572 uint8_t opcode; /* !< opcode for the message (string or binary) */ 1573 uint8_t has_mask; /* !< does the message contain a mask? */ 1574 uint8_t mask[4]; /* !< mask used if any */ 1575 size_t data_len; /* !< length of the data */ 1576 char * data; /* !< message data */ 1577 size_t fragment_len; /* !< length of the fragment, 0 if not fragmented */ 1578 uint8_t fin; /* !< flag fin (end of fragmented message) */ 1579 }; 1580 1581 /** 1582 * @struct _websocket_message_list List of websocket messages 1583 */ 1584 struct _websocket_message_list { 1585 struct _websocket_message ** list; /* !< messages list */ 1586 size_t len; /* !< message list length */ 1587 }; 1588 1589 /** 1590 * @struct _websocket websocket structure 1591 * contains all the data of the websocket 1592 */ 1593 struct _websocket { 1594 struct _u_instance * instance; /* !< reference to the ulfius instance if any */ 1595 struct _u_request * request; /* !< refrence to the ulfius request of any */ 1596 void (* websocket_manager_callback) (const struct _u_request * request, /* !< reference to a function called after the websocket handshake */ 1597 struct _websocket_manager * websocket_manager, 1598 void * websocket_manager_user_data); 1599 void * websocket_manager_user_data; /* !< a user-defined reference that will be available in websocket_manager_callback */ 1600 void (* websocket_incoming_message_callback) (const struct _u_request * request, /* !< reference to a function called each time a message arrives */ 1601 struct _websocket_manager * websocket_manager, 1602 const struct _websocket_message * message, 1603 void * websocket_incoming_user_data); 1604 void * websocket_incoming_user_data; /* !< a user-defined reference that will be available in websocket_incoming_message_callback */ 1605 void (* websocket_onclose_callback) (const struct _u_request * request, /* !< reference to a function called after the websocket connection ends */ 1606 struct _websocket_manager * websocket_manager, 1607 void * websocket_onclose_user_data); 1608 void * websocket_onclose_user_data; /* !< a user-defined reference that will be available in websocket_onclose_callback */ 1609 struct _websocket_manager * websocket_manager; /* !< refrence to the websocket manager if any */ 1610 struct MHD_UpgradeResponseHandle * urh; /* !< reference used by libmicrohttpd to upgrade the connection */ 1611 }; 1612 1613 /** 1614 * @struct _websocket_client_handler Handler for the websocket client, to allow the program to know the status of a websocket client 1615 */ 1616 struct _websocket_client_handler { 1617 struct _websocket * websocket; /* !< the websocket to use */ 1618 struct _u_response * response; /* !< the response attached to the websocket */ 1619 }; 1620 1621 /********************************/ 1622 /** Common websocket functions **/ 1623 /********************************/ 1624 1625 /** 1626 * Sends a message in the websocket 1627 * @param websocket_manager the websocket manager to use for sending the message 1628 * @param opcode the opcode to use 1629 * values available are U_WEBSOCKET_OPCODE_TEXT, U_WEBSOCKET_OPCODE_BINARY, U_WEBSOCKET_OPCODE_PING, U_WEBSOCKET_OPCODE_PONG, U_WEBSOCKET_OPCODE_CLOSE 1630 * @param data_len the length of the data to send 1631 * @param data the data to send 1632 * @return U_OK on success 1633 */ 1634 int ulfius_websocket_send_message(struct _websocket_manager * websocket_manager, 1635 const uint8_t opcode, 1636 const uint64_t data_len, 1637 const char * data); 1638 1639 /** 1640 * Send a fragmented message in the websocket 1641 * each fragment size will be at most fragment_len 1642 * @param websocket_manager the websocket manager to use for sending the message 1643 * @param opcode the opcode to use 1644 * values available are U_WEBSOCKET_OPCODE_TEXT, U_WEBSOCKET_OPCODE_BINARY, U_WEBSOCKET_OPCODE_PING, U_WEBSOCKET_OPCODE_PONG, U_WEBSOCKET_OPCODE_CLOSE 1645 * @param data_len the length of the data to send 1646 * @param data the data to send 1647 * @param fragment_len the maximum length of each fragment 1648 * @return U_OK on success 1649 */ 1650 int ulfius_websocket_send_fragmented_message(struct _websocket_manager * websocket_manager, 1651 const uint8_t opcode, 1652 const uint64_t data_len, 1653 const char * data, 1654 const uint64_t fragment_len); 1655 1656 /** 1657 * Sends a JSON message in the websocket 1658 * @param websocket_manager the websocket manager to use for sending the message 1659 * @param message the message to send 1660 * @return U_OK on success 1661 */ 1662 #ifndef U_DISABLE_JANSSON 1663 int ulfius_websocket_send_json_message(struct _websocket_manager * websocket_manager, 1664 json_t * message); 1665 #endif 1666 1667 /** 1668 * Return the first message of the message list 1669 * Return NULL if message_list has no message 1670 * Use it with struct _websocket_manager->message_list_incoming 1671 * or struct _websocket_manager->message_list_outcoming 1672 * @param message_list the list to pop the first message 1673 * @return a _websocket_message reference 1674 * Returned value must be cleared after use 1675 */ 1676 struct _websocket_message * ulfius_websocket_pop_first_message(struct _websocket_message_list * message_list); 1677 1678 /** 1679 * Clear data of a websocket message 1680 * @param message the message to cleanup 1681 */ 1682 void ulfius_clear_websocket_message(struct _websocket_message * message); 1683 1684 /********************************/ 1685 /** Server websocket functions **/ 1686 /********************************/ 1687 1688 /** 1689 * Set a websocket in the response 1690 * You must set at least websocket_manager_callback or websocket_incoming_message_callback 1691 * @param response struct _u_response to send back the websocket initialization, mandatory 1692 * @param websocket_protocol list of protocols, separated by a comma, or NULL if no protocols are accepted 1693 * @param websocket_extensions list of extensions, separated by a comma, or NULL if no extensions are accepted 1694 * @param websocket_manager_callback callback function called right after the handshake acceptance, optional 1695 * @param websocket_manager_user_data any data that will be given to the websocket_manager_callback, optional 1696 * @param websocket_incoming_message_callback callback function called on each incoming complete message, optional 1697 * @param websocket_incoming_user_data any data that will be given to the websocket_incoming_message_callback, optional 1698 * @param websocket_onclose_callback callback function called right before closing the websocket, must be complete for the websocket to close 1699 * @param websocket_onclose_user_data any data that will be given to the websocket_onclose_callback, optional 1700 * @return U_OK on success 1701 */ 1702 int ulfius_set_websocket_response(struct _u_response * response, 1703 const char * websocket_protocol, 1704 const char * websocket_extensions, 1705 void (* websocket_manager_callback) (const struct _u_request * request, 1706 struct _websocket_manager * websocket_manager, 1707 void * websocket_manager_user_data), 1708 void * websocket_manager_user_data, 1709 void (* websocket_incoming_message_callback) (const struct _u_request * request, 1710 struct _websocket_manager * websocket_manager, 1711 const struct _websocket_message * message, 1712 void * websocket_incoming_user_data), 1713 void * websocket_incoming_user_data, 1714 void (* websocket_onclose_callback) (const struct _u_request * request, 1715 struct _websocket_manager * websocket_manager, 1716 void * websocket_onclose_user_data), 1717 void * websocket_onclose_user_data); 1718 1719 /** 1720 * Adds a set of callback functions to perform a message transformation via an extension 1721 * @param response struct _u_response to send back the websocket initialization, mandatory 1722 * @param extension_server the expected extension value 1723 * @param rsv the expected rsv flag attached to this extension 1724 * @param websocket_extension_message_out_perform a callback function called before a message is sent to the server 1725 * @param websocket_extension_message_out_perform_user_data a user-defined pointer passed to websocket_extension_message_out_perform 1726 * @param websocket_extension_message_in_perform a callback function called after a message is received from the server 1727 * @param websocket_extension_message_in_perform_user_data a user-defined pointer passed to websocket_extension_message_in_perform 1728 * @param websocket_extension_server_match a callback function called on handshake response to match an extensions value with the given callback message perform extensions 1729 * if NULL, then extension_client and the extension sent by the server will be compared for an exact match to enable this extension 1730 * @param websocket_extension_server_match_user_data a user-defined pointer passed to websocket_extension_server_match 1731 * @param websocket_extension_free_context a callback function called during the websocket close to free the context created in websocket_extension_server_match 1732 * @param websocket_extension_free_context_user_data a user-defined pointer passed to websocket_extension_free_context 1733 * @return U_OK on success 1734 */ 1735 int ulfius_add_websocket_extension_message_perform(struct _u_response * response, 1736 const char * extension_server, 1737 uint8_t rsv, 1738 int (* websocket_extension_message_out_perform)(const uint8_t opcode, 1739 const uint64_t data_len_in, 1740 const char * data_in, 1741 uint64_t * data_len_out, 1742 char ** data_out, 1743 const uint64_t fragment_len, 1744 void * user_data, 1745 void * context), 1746 void * websocket_extension_message_out_perform_user_data, 1747 int (* websocket_extension_message_in_perform)(const uint8_t opcode, 1748 const uint64_t data_len_in, 1749 const char * data_in, 1750 uint64_t * data_len_out, 1751 char ** data_out, 1752 const uint64_t fragment_len, 1753 void * user_data, 1754 void * context), 1755 void * websocket_extension_message_in_perform_user_data, 1756 int (* websocket_extension_server_match)(const char * extension_client, 1757 const char ** extension_client_list, 1758 char ** extension_server, 1759 void * user_data, 1760 void ** context), 1761 void * websocket_extension_server_match_user_data, 1762 void (* websocket_extension_free_context)(void * user_data, 1763 void * context), 1764 void * websocket_extension_free_context_user_data); 1765 1766 /** 1767 * websocket_extension_message_out_perform used in 1768 * ulfius_add_websocket_deflate_extension and ulfius_add_websocket_client_deflate_extension 1769 * will compress the message in data_in and set the result in *data_out 1770 * @param opcode the opcode of the message to send 1771 * @param data_len_in length of data_in 1772 * @param data_in payload data to transform 1773 * @param data_len_out length of *data_out to be set by the function 1774 * @param data_out result of the transformed data_in 1775 * @param fragment_len fragmentation length of the message 1776 * @param user_data user-defined data 1777 * @param context context of the extension 1778 * @return U_OK on success 1779 */ 1780 int websocket_extension_message_out_deflate(const uint8_t opcode, 1781 const uint64_t data_len_in, 1782 const char * data_in, 1783 uint64_t * data_len_out, 1784 char ** data_out, 1785 const uint64_t fragment_len, 1786 void * user_data, 1787 void * context); 1788 1789 /** 1790 * websocket_extension_message_in_perform used in 1791 * ulfius_add_websocket_deflate_extension and ulfius_add_websocket_client_deflate_extension 1792 * @param opcode the opcode of the message to send 1793 * @param data_len_in length of data_in 1794 * @param data_in payload data to transform 1795 * @param data_len_out length of *data_out to be set by the function 1796 * @param data_out result of the transformed data_in 1797 * @param fragment_len fragmentation length of the message 1798 * @param user_data user-defined data 1799 * @param context context of the extension 1800 * @return U_OK on success 1801 */ 1802 int websocket_extension_message_in_inflate(const uint8_t opcode, 1803 const uint64_t data_len_in, 1804 const char * data_in, 1805 uint64_t * data_len_out, 1806 char ** data_out, 1807 const uint64_t fragment_len, 1808 void * user_data, 1809 void * context); 1810 1811 /** 1812 * Free deflate extension context 1813 * @param user_data user-defined data 1814 * @param context context of the extension 1815 * @return U_OK on success 1816 */ 1817 void websocket_extension_deflate_free_context(void * user_data, void * context); 1818 1819 /** 1820 * websocket_extension_server_match used in ulfius_add_websocket_deflate_extension 1821 * @param extension_client the extension value to check 1822 * @param extension_client_list the list of all extension_client to match 1823 * @param extension_server the extension value to return to the client 1824 * @param user_data user-defined data 1825 * @param context context to allocate 1826 * @return U_OK on success 1827 */ 1828 int websocket_extension_server_match_deflate(const char * extension_client, const char ** extension_client_list, char ** extension_server, void * user_data, void ** context); 1829 1830 /** 1831 * Adds the required extension message perform to implement message compression according to 1832 * RFC 7692: Compression Extensions for WebSocket 1833 * https://tools.ietf.org/html/rfc7692 1834 * Due to limited implementation, will force response parameters to server_no_context_takeover; client_no_context_takeover 1835 * @param response struct _u_response to send back the websocket initialization, mandatory 1836 * @return U_OK on success 1837 */ 1838 int ulfius_add_websocket_deflate_extension(struct _u_response * response); 1839 1840 /** 1841 * Sets the websocket in closing mode 1842 * The websocket will not necessarily be closed at the return of this function, 1843 * it will process through the end of the `websocket_manager_callback` 1844 * and the `websocket_onclose_callback` calls first. 1845 * This function has no effect if the websocket isn't connected 1846 * @param websocket_manager the _websocket_manager to send close signal to 1847 * @return U_OK on success, U_ERROR on error 1848 */ 1849 int ulfius_websocket_send_close_signal(struct _websocket_manager * websocket_manager); 1850 1851 /** 1852 * Get the websocket status 1853 * @param websocket_manager the _websocket_manager to analyze 1854 * @return the status of the websocket connection 1855 * Returned values can be U_WEBSOCKET_STATUS_OPEN or U_WEBSOCKET_STATUS_CLOSE 1856 * wether the websocket is open or closed, or U_WEBSOCKET_STATUS_ERROR on error 1857 */ 1858 int ulfius_websocket_status(struct _websocket_manager * websocket_manager); 1859 1860 /** 1861 * Wait until the websocket connection is closed or the timeout in milliseconds is reached 1862 * if timeout is 0, no timeout is set 1863 * @param websocket_manager the _websocket_manager to analyze 1864 * @param timeout timeout in milliseconds 1865 * @return U_WEBSOCKET_STATUS_OPEN or U_WEBSOCKET_STATUS_CLOSE 1866 * wether the websocket is open or closed, or U_WEBSOCKET_STATUS_ERROR on error 1867 */ 1868 int ulfius_websocket_wait_close(struct _websocket_manager * websocket_manager, unsigned int timeout); 1869 1870 /********************************/ 1871 /** Client websocket functions **/ 1872 /********************************/ 1873 1874 /** 1875 * Open a websocket client connection 1876 * @param request the request to use to open the websocket connection 1877 * @param websocket_manager_callback a reference to a function called after the handshake, may be NULL 1878 * @param websocket_manager_user_data a user-defined pointer passed to websocket_manager_callback 1879 * @param websocket_incoming_message_callback a reference to a function called each time a message arrives in the websocket, may be NULL 1880 * @param websocket_incoming_user_data a user-defined pointer passed to websocket_incoming_message_callback 1881 * @param websocket_onclose_callback a reference to a function called after the websocket connection is closed, may be NULL 1882 * @param websocket_onclose_user_data a user-defined pointer passed to websocket_onclose_callback 1883 * @param websocket_client_handler the handler of the websocket 1884 * @param response the response attached with the websocket 1885 * @return U_OK on success 1886 */ 1887 int ulfius_open_websocket_client_connection(struct _u_request * request, 1888 void (* websocket_manager_callback) (const struct _u_request * request, 1889 struct _websocket_manager * websocket_manager, 1890 void * websocket_manager_user_data), 1891 void * websocket_manager_user_data, 1892 void (* websocket_incoming_message_callback) (const struct _u_request * request, 1893 struct _websocket_manager * websocket_manager, 1894 const struct _websocket_message * message, 1895 void * websocket_incoming_user_data), 1896 void * websocket_incoming_user_data, 1897 void (* websocket_onclose_callback) (const struct _u_request * request, 1898 struct _websocket_manager * websocket_manager, 1899 void * websocket_onclose_user_data), 1900 void * websocket_onclose_user_data, 1901 struct _websocket_client_handler * websocket_client_handler, 1902 struct _u_response * response); 1903 1904 /** 1905 * Adds a set of callback functions to perform a message transformation via an extension 1906 * @param websocket_client_handler the handler of the websocket 1907 * @param extension the expected extension value 1908 * @param websocket_extension_message_out_perform a callback function called before a message is sent to the client 1909 * @param websocket_extension_message_out_perform_user_data a user-defined pointer passed to websocket_extension_message_out_perform 1910 * @param websocket_extension_message_in_perform a callback function called after a message is received from the client 1911 * @param websocket_extension_message_in_perform_user_data a user-defined pointer passed to websocket_extension_message_in_perform 1912 * @param websocket_extension_client_match a callback function called on handshake response to match an extensions value with the given callback message perform extensions 1913 * if NULL, then extension and the extension sent by the client will be compared for an exact match to enable this extension 1914 * @param websocket_extension_client_match_user_data a user-defined pointer passed to websocket_extension_client_match 1915 * @param websocket_extension_free_context a callback function called during the websocket close to free the context created in websocket_extension_server_match 1916 * @param websocket_extension_free_context_user_data a user-defined pointer passed to websocket_extension_free_context 1917 * @return U_OK on success 1918 */ 1919 int ulfius_add_websocket_client_extension_message_perform(struct _websocket_client_handler * websocket_client_handler, 1920 const char * extension, 1921 uint8_t rsv, 1922 int (* websocket_extension_message_out_perform)(const uint8_t opcode, 1923 const uint64_t data_len_in, 1924 const char * data_in, 1925 uint64_t * data_len_out, 1926 char ** data_out, 1927 const uint64_t fragment_len, 1928 void * user_data, 1929 void * context), 1930 void * websocket_extension_message_out_perform_user_data, 1931 int (* websocket_extension_message_in_perform)(const uint8_t opcode, 1932 const uint64_t data_len_in, 1933 const char * data_in, 1934 uint64_t * data_len_out, 1935 char ** data_out, 1936 const uint64_t fragment_len, 1937 void * user_data, 1938 void * context), 1939 void * websocket_extension_message_in_perform_user_data, 1940 int (* websocket_extension_client_match)(const char * extension_server, 1941 void * user_data, 1942 void ** context), 1943 void * websocket_extension_client_match_user_data, 1944 void (* websocket_extension_free_context)(void * user_data, 1945 void * context), 1946 void * websocket_extension_free_context_user_data); 1947 1948 /** 1949 * websocket_extension_client_match used in ulfius_add_websocket_deflate_extension 1950 * @param extension_server the extension value to check 1951 * @param user_data user-defined data 1952 * @param context context to allocate 1953 * @return U_OK on success 1954 */ 1955 int websocket_extension_client_match_deflate(const char * extension_server, void * user_data, void ** context); 1956 1957 /** 1958 * Adds the required extension message perform to implement message compression according to 1959 * RFC 7692: Compression Extensions for WebSocket 1960 * https://tools.ietf.org/html/rfc7692 1961 * @param websocket_client_handler the handler of the websocket 1962 * @return U_OK on success 1963 */ 1964 int ulfius_add_websocket_client_deflate_extension(struct _websocket_client_handler * websocket_client_handler); 1965 1966 /** 1967 * Send a close signal to the websocket 1968 * @param websocket_client_handler the handler to the websocket connection 1969 * @return U_OK when the signal is sent, U_ERROR on error 1970 */ 1971 int ulfius_websocket_client_connection_send_close_signal(struct _websocket_client_handler * websocket_client_handler); 1972 1973 /** 1974 * Closes a websocket client connection 1975 * @param websocket_client_handler the handler to the websocket connection 1976 * @return U_OK when the websocket is closed, U_ERROR on error 1977 */ 1978 int ulfius_websocket_client_connection_close(struct _websocket_client_handler * websocket_client_handler); 1979 1980 /** 1981 * Returns the status of the websocket client connection 1982 * @param websocket_client_handler the handler to the websocket connection 1983 * @return U_WEBSOCKET_STATUS_OPEN or U_WEBSOCKET_STATUS_CLOSE 1984 * wether the websocket is open or closed, or U_WEBSOCKET_STATUS_ERROR on error 1985 */ 1986 int ulfius_websocket_client_connection_status(struct _websocket_client_handler * websocket_client_handler); 1987 1988 /** 1989 * Wait until the websocket client connection is closed or the timeout in milliseconds is reached 1990 * if timeout is 0, no timeout is set 1991 * @param websocket_client_handler the handler to the websocket connection 1992 * @param timeout timeout in milliseconds 1993 * @return U_WEBSOCKET_STATUS_OPEN or U_WEBSOCKET_STATUS_CLOSE 1994 * wether the websocket is open or closed, or U_WEBSOCKET_STATUS_ERROR on error 1995 */ 1996 int ulfius_websocket_client_connection_wait_close(struct _websocket_client_handler * websocket_client_handler, unsigned int timeout); 1997 1998 /** 1999 * Set values for a struct _u_request to open a websocket 2000 * request must be previously initialized 2001 * @param request the request to use to open the websocket 2002 * @param url the url of the websocket service 2003 * @param websocket_protocol the protocol for the websocket, may be NULL 2004 * @param websocket_extensions the extension for the websocket, may be NULL 2005 * @return U_OK on success 2006 */ 2007 int ulfius_set_websocket_request(struct _u_request * request, 2008 const char * url, 2009 const char * websocket_protocol, 2010 const char * websocket_extensions); 2011 2012 #endif 2013 2014 /** Macro values **/ 2015 #define ULFIUS_URL_SEPARATOR "/" 2016 #define ULFIUS_HTTP_ENCODING_JSON "application/json" 2017 #define ULFIUS_HTTP_HEADER_CONTENT "Content-Type" 2018 #define ULFIUS_HTTP_NOT_FOUND_BODY "Resource not found" 2019 #define ULFIUS_HTTP_ERROR_BODY "Server Error" 2020 2021 #define ULFIUS_COOKIE_ATTRIBUTE_EXPIRES "Expires" 2022 #define ULFIUS_COOKIE_ATTRIBUTE_MAX_AGE "Max-Age" 2023 #define ULFIUS_COOKIE_ATTRIBUTE_DOMAIN "Domain" 2024 #define ULFIUS_COOKIE_ATTRIBUTE_PATH "Path" 2025 #define ULFIUS_COOKIE_ATTRIBUTE_SECURE "Secure" 2026 #define ULFIUS_COOKIE_ATTRIBUTE_HTTPONLY "HttpOnly" 2027 2028 #define ULFIUS_POSTBUFFERSIZE 65536 2029 2030 #define U_STATUS_STOP 0 2031 #define U_STATUS_RUNNING 1 2032 #define U_STATUS_ERROR 2 2033 2034 #ifndef U_DISABLE_WEBSOCKET 2035 2036 /** 2037 * @struct _websocket_handle handle for a websocket 2038 */ 2039 struct _websocket_handle { 2040 char * websocket_protocol; /* !< protocol for the websocket */ 2041 char * websocket_extensions; /* !< extensions for the websocket */ 2042 void (* websocket_manager_callback) (const struct _u_request * request, /* !< callback function for working with the websocket */ 2043 struct _websocket_manager * websocket_manager, 2044 void * websocket_manager_user_data); 2045 void * websocket_manager_user_data; /* !< user-defined data that will be handled to websocket_manager_callback */ 2046 void (* websocket_incoming_message_callback) (const struct _u_request * request, /* !< callback function that will be called every time a message arrives from the client in the websocket */ 2047 struct _websocket_manager * websocket_manager, 2048 const struct _websocket_message * message, 2049 void * websocket_incoming_user_data); 2050 void * websocket_incoming_user_data; /* !< user-defined data that will be handled to websocket_incoming_message_callback */ 2051 void (* websocket_onclose_callback) (const struct _u_request * request, /* !< callback function that will be called if the websocket is open while the program calls ulfius_stop_framework */ 2052 struct _websocket_manager * websocket_manager, 2053 void * websocket_onclose_user_data); 2054 void * websocket_onclose_user_data; /* !< user-defined data that will be handled to websocket_onclose_callback */ 2055 int rsv_expected; 2056 struct _pointer_list * websocket_extension_list; 2057 }; 2058 2059 /** 2060 * @struct _websocket_handler handler for the websockets list 2061 */ 2062 struct _websocket_handler { 2063 pthread_mutex_t websocket_active_lock; /* !< mutex to change nb_websocket_active value */ 2064 size_t nb_websocket_active; /* !< number of active websocket */ 2065 struct _websocket ** websocket_active; /* !< array of active websocket */ 2066 pthread_mutex_t websocket_close_lock; /* !< mutex to broadcast close signal */ 2067 pthread_cond_t websocket_close_cond; /* !< condition to broadcast close signal */ 2068 int pthread_init; 2069 }; 2070 2071 #endif // U_DISABLE_WEBSOCKET 2072 2073 /** 2074 * @} 2075 */ 2076 2077 /** 2078 * @defgroup cert TLS client certificate 2079 * TLS client certificate management functions 2080 * @{ 2081 */ 2082 2083 #ifndef U_DISABLE_GNUTLS 2084 /* 2085 * ulfius_export_client_certificate_pem 2086 * Exports the client certificate using PEM format 2087 * @param request struct _u_request used 2088 * @return the certificate in PEM format 2089 * returned value must be u_free'd after use 2090 */ 2091 char * ulfius_export_client_certificate_pem(const struct _u_request * request); 2092 2093 /* 2094 * ulfius_import_client_certificate_pem 2095 * Imports the client certificate using PEM format 2096 * @param request struct _u_request used 2097 * @param str_cert client certificate in PEM format 2098 * @return U_OK on success 2099 */ 2100 int ulfius_import_client_certificate_pem(struct _u_request * request, const char * str_cert); 2101 2102 #endif // U_DISABLE_GNUTLS 2103 2104 /** 2105 * @} 2106 */ 2107 2108 #ifdef __cplusplus 2109 } 2110 #endif 2111 2112 #endif // __ULFIUS_H__ 2113