Hello community, here is the log from the commit of package ulfius for openSUSE:Factory checked in at 2019-07-24 20:33:50 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ulfius (Old) and /work/SRC/openSUSE:Factory/.ulfius.new.4126 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ulfius" Wed Jul 24 20:33:50 2019 rev:6 rq:717781 version:2.6.2 Changes: -------- --- /work/SRC/openSUSE:Factory/ulfius/ulfius.changes 2019-07-08 15:11:42.843384755 +0200 +++ /work/SRC/openSUSE:Factory/.ulfius.new.4126/ulfius.changes 2019-07-24 20:33:52.562585008 +0200 @@ -1,0 +2,12 @@ +Fri Jul 19 06:59:59 UTC 2019 - Martin Hauke <[email protected]> + +- Update to version 2.6.2 + * Fix memory leak in `ulfius_set_string_body_request` and + `ulfius_set_string_body_response` + * Call callback function websocket_onclose_callback on all times, + even if the websocket hasn't properly worked, so the calling + program can avoid memory leak and broken resources, fix #126 +- Add patch (fixes a compilation error on Tumbleweed): + * 0001-Cast-option-value-for-curl_easy_setopt-on-CURLOPT_PO.patch + +------------------------------------------------------------------- Old: ---- ulfius-2.6.1.tar.gz New: ---- 0001-Cast-option-value-for-curl_easy_setopt-on-CURLOPT_PO.patch ulfius-2.6.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ulfius.spec ++++++ --- /var/tmp/diff_new_pack.0KpLTl/_old 2019-07-24 20:33:53.086584950 +0200 +++ /var/tmp/diff_new_pack.0KpLTl/_new 2019-07-24 20:33:53.090584949 +0200 @@ -19,13 +19,14 @@ %define sover 2_6 Name: ulfius -Version: 2.6.1 +Version: 2.6.2 Release: 0 Summary: Web Framework for REST Applications in C License: MIT Group: Development/Languages/C and C++ URL: https://github.com/babelouest/ulfius Source: https://github.com/babelouest/ulfius/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz +Patch0: 0001-Cast-option-value-for-curl_easy_setopt-on-CURLOPT_PO.patch BuildRequires: cmake BuildRequires: gcc-c++ BuildRequires: pkgconfig @@ -69,6 +70,7 @@ %prep %setup -q +%patch0 -p1 %build %cmake \ ++++++ 0001-Cast-option-value-for-curl_easy_setopt-on-CURLOPT_PO.patch ++++++ >From c0d9933e28c2dea4b8589739fe6dfe5ecfe59310 Mon Sep 17 00:00:00 2001 From: Nicolas Mora <[email protected]> Date: Thu, 18 Jul 2019 19:31:56 -0400 Subject: [PATCH] Cast option value for curl_easy_setopt on CURLOPT_POSTFIELDSIZE and CURLOPT_POSTFIELDSIZE_LARGE options to curl_off_t, to help gcc 9.1 to be less annoyed by incompatible types (but in fact they probably are compatible), closes #128 --- src/u_send_request.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/u_send_request.c b/src/u_send_request.c index 0a8010d..0370c6f 100644 --- a/src/u_send_request.c +++ b/src/u_send_request.c @@ -370,13 +370,13 @@ int ulfius_send_http_streaming_request(const struct _u_request * request, // Set body content if (copy_request->binary_body_length && copy_request->binary_body != NULL) { if (copy_request->binary_body_length < 2147483648) { - if (curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, copy_request->binary_body_length) != CURLE_OK) { + if (curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, (curl_off_t)copy_request->binary_body_length) != CURLE_OK) { y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error setting POST fields size"); ret = U_ERROR_LIBCURL; break; } } else { - if (curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE_LARGE, copy_request->binary_body_length) != CURLE_OK) { + if (curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)copy_request->binary_body_length) != CURLE_OK) { y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error setting POST fields size large"); ret = U_ERROR_LIBCURL; break; -- 2.16.4 ++++++ ulfius-2.6.1.tar.gz -> ulfius-2.6.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ulfius-2.6.1/API.md new/ulfius-2.6.2/API.md --- old/ulfius-2.6.1/API.md 2019-07-01 16:22:23.000000000 +0200 +++ new/ulfius-2.6.2/API.md 2019-07-08 13:28:16.000000000 +0200 @@ -24,7 +24,8 @@ - [Websocket management](#websocket-management) - [Messages manipulation](#messages-manipulation) - [Server-side websocket](#server-side-websocket) - - [Starting a websocket communication](#starting-a-websocket-communication) + - [Open a websocket communication](#open-a-websocket-communication) + - [Close a websocket communication](#close-a-websocket-communication) - [Websocket status](#websocket-status) - [Client-side websocket](#client-side-websocket) - [Prepare the request](#prepare-the-request) @@ -1081,7 +1082,7 @@ #### Server-side websocket -##### Opening a websocket communication +##### Open a websocket communication To start a websocket communication between the client and your application, you must use the dedicated function `ulfius_start_websocket_cb` with proper values: @@ -1139,7 +1140,7 @@ For each of these callback function, you can specify a `*_user_data` pointer containing any data you need. -##### Closing a websocket communication +##### Close a websocket communication To close a websocket communication from the server, you can do one of the following: @@ -1147,7 +1148,12 @@ - Send a message with the opcode `U_WEBSOCKET_OPCODE_CLOSE` - Call the function `ulfius_websocket_wait_close` or `ulfius_websocket_send_close_signal` described below -If no `websocket_manager_callback` is specified, you can send a `U_WEBSOCKET_OPCODE_CLOSE` in the `websocket_incoming_message_callback` function when you need, or call the function `ulfius_websocket_send_close_signal`: +If no `websocket_manager_callback` is specified, you can send a `U_WEBSOCKET_OPCODE_CLOSE` in the `websocket_incoming_message_callback` function when you need, or call the function `ulfius_websocket_send_close_signal`. + +If a callback function `websocket_onclose_callback` has been specified, this function will be executed on every case at the end of the websocket connection. + +If the websocket handshake hasn't been correctly completed or if an error appears during the handshake connection, the callback `websocket_onclose_callback` will be called anyway, even if the callback functions `websocket_manager_callback` or `websocket_incoming_message_callback` are skipped due to no websocket connection. +This is to allow the calling program to close opened resources or clean allocated memory. Beware that in this specific case, the parameter `struct _websocket_manager * websocket_manager` may be `NULL`. ##### Websocket status diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ulfius-2.6.1/CHANGELOG.md new/ulfius-2.6.2/CHANGELOG.md --- old/ulfius-2.6.1/CHANGELOG.md 2019-07-01 16:22:23.000000000 +0200 +++ new/ulfius-2.6.2/CHANGELOG.md 2019-07-08 13:28:16.000000000 +0200 @@ -1,5 +1,11 @@ # Ulfius Changelog +## 2.6.2 + +- Clean build process +- Fix memory leak in `ulfius_set_string_body_request` and `ulfius_set_string_body_response` +- Call callback function websocket_onclose_callback on all times, even if the websocket hasn't properly worked, so the calling program can avoid memory leak and broken resources, fix #126 + ## 2.6.1 - Fix package dependencies in cmake script diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ulfius-2.6.1/CMakeLists.txt new/ulfius-2.6.2/CMakeLists.txt --- old/ulfius-2.6.1/CMakeLists.txt 2019-07-01 16:22:23.000000000 +0200 +++ new/ulfius-2.6.2/CMakeLists.txt 2019-07-08 13:28:16.000000000 +0200 @@ -30,13 +30,13 @@ set(PROJECT_BUGREPORT_PATH "https://github.com/babelouest/ulfius/issues") set(LIBRARY_VERSION_MAJOR "2") set(LIBRARY_VERSION_MINOR "6") -set(LIBRARY_VERSION_PATCH "1") +set(LIBRARY_VERSION_PATCH "2") set(PROJECT_VERSION "${LIBRARY_VERSION_MAJOR}.${LIBRARY_VERSION_MINOR}.${LIBRARY_VERSION_PATCH}") set(LIBRARY_VERSION "${LIBRARY_VERSION_MAJOR}.${LIBRARY_VERSION_MINOR}.${LIBRARY_VERSION_PATCH}") set(LIBRARY_SOVERSION "${LIBRARY_VERSION_MAJOR}.${LIBRARY_VERSION_MINOR}") -set(ORCANIA_VERSION_REQUIRED "2.0.0") -set(YDER_VERSION_REQUIRED "1.4.6") +set(ORCANIA_VERSION_REQUIRED "2.0.1") +set(YDER_VERSION_REQUIRED "1.4.7") # cmake modules @@ -298,7 +298,7 @@ include(FindCheck) find_package(Check REQUIRED) if (CHECK_FOUND) - if (NOT WIN32) + if (NOT WIN32 AND NOT APPLE) include(FindSubunit) find_package(Subunit REQUIRED) endif () @@ -311,9 +311,15 @@ set(LIBS ulfius ${LIBS} ${CHECK_LIBRARIES}) if (NOT WIN32) find_package(Threads REQUIRED) - set(LIBS ${LIBS} ${SUBUNIT_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} m rt) + set(LIBS ${LIBS} ${CMAKE_THREAD_LIBS_INIT} m) endif () - + if (NOT APPLE) + set(LIBS ${LIBS} rt) + endif () + if (NOT WIN32 AND NOT APPLE) + set(LIBS ${LIBS} ${SUBUNIT_LIBRARIES} rt) + endif () + set(TESTS core u_map framework) if (WITH_WEBSOCKET) set(TESTS ${TESTS} websocket) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ulfius-2.6.1/src/Makefile new/ulfius-2.6.2/src/Makefile --- old/ulfius-2.6.1/src/Makefile 2019-07-01 16:22:23.000000000 +0200 +++ new/ulfius-2.6.2/src/Makefile 2019-07-08 13:28:16.000000000 +0200 @@ -32,9 +32,13 @@ CC=gcc CFLAGS+=-c -pedantic -std=gnu99 -fPIC -Wall -Werror -Wextra -D_REENTRANT -I$(ULFIUS_INCLUDE) $(ADDITIONALFLAGS) $(CPPFLAGS) LIBS=-L$(DESTDIR)/lib -lc -lmicrohttpd -lorcania -lpthread $(LDFLAGS) +SONAME = -soname +ifeq ($(shell uname -s),Darwin) + SONAME = -install_name +endif OBJECTS=ulfius.o u_map.o u_request.o u_response.o u_send_request.o u_websocket.o yuarel.o OUTPUT=libulfius.so -VERSION=2.6.1 +VERSION=2.6.2 ifndef JANSSONFLAG DISABLE_JANSSON=0 @@ -167,7 +171,7 @@ $(CC) $(CFLAGS) $< libulfius.so: $(OBJECTS) - $(CC) -shared -fPIC -Wl,-soname,$(OUTPUT) -o $(OUTPUT).$(VERSION) $(OBJECTS) $(LIBS) $(LYDER) $(LJANSSON) $(LCURL) $(LGNUTLS) + $(CC) -shared -fPIC -Wl,$(SONAME),$(OUTPUT) -o $(OUTPUT).$(VERSION) $(OBJECTS) $(LIBS) $(LYDER) $(LJANSSON) $(LCURL) $(LGNUTLS) ln -sf $(OUTPUT).$(VERSION) $(OUTPUT) libulfius.a: $(OBJECTS) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ulfius-2.6.1/src/u_request.c new/ulfius-2.6.2/src/u_request.c --- old/ulfius-2.6.1/src/u_request.c 2019-07-01 16:22:23.000000000 +0200 +++ new/ulfius-2.6.2/src/u_request.c 2019-07-08 13:28:16.000000000 +0200 @@ -526,6 +526,8 @@ */ int ulfius_set_string_body_request(struct _u_request * request, const char * string_body) { if (request != NULL && string_body != NULL) { + // Free all the bodies available + o_free(request->binary_body); request->binary_body = o_strdup(string_body); if (request->binary_body == NULL) { y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for request->binary_body"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ulfius-2.6.1/src/u_response.c new/ulfius-2.6.2/src/u_response.c --- old/ulfius-2.6.1/src/u_response.c 2019-07-01 16:22:23.000000000 +0200 +++ new/ulfius-2.6.2/src/u_response.c 2019-07-08 13:28:16.000000000 +0200 @@ -568,6 +568,8 @@ */ int ulfius_set_string_body_response(struct _u_response * response, const unsigned int status, const char * string_body) { if (response != NULL && string_body != NULL) { + // Free all the bodies available + o_free(response->binary_body); response->binary_body = o_strdup(string_body); if (response->binary_body == NULL) { y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for response->binary_body"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ulfius-2.6.1/src/u_send_request.c new/ulfius-2.6.2/src/u_send_request.c --- old/ulfius-2.6.1/src/u_send_request.c 2019-07-01 16:22:23.000000000 +0200 +++ new/ulfius-2.6.2/src/u_send_request.c 2019-07-08 13:28:16.000000000 +0200 @@ -566,11 +566,12 @@ res = curl_easy_perform(curl_handle); if (res != CURLE_OK) { y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error curl_easy_perform"); + y_log_message(Y_LOG_LEVEL_DEBUG, "Ulfius - libcurl error: %d, error message '%s'", res, curl_easy_strerror(res)); ret = U_ERROR_LIBCURL; break; } else if (res == CURLE_OK && response != NULL) { if (curl_easy_getinfo (curl_handle, CURLINFO_RESPONSE_CODE, &response->status) != CURLE_OK) { - y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error executing http request, libcurl error: %d, error message %s", res, curl_easy_strerror(res)); + y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error executing http request, libcurl error: %d, error message '%s'", res, curl_easy_strerror(res)); ret = U_ERROR_LIBCURL; break; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ulfius-2.6.1/src/u_websocket.c new/ulfius-2.6.2/src/u_websocket.c --- old/ulfius-2.6.1/src/u_websocket.c 2019-07-01 16:22:23.000000000 +0200 +++ new/ulfius-2.6.2/src/u_websocket.c 2019-07-08 13:28:16.000000000 +0200 @@ -833,6 +833,9 @@ if (thread_ret_websocket || thread_detach_websocket) { y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error creating or detaching websocket manager thread, return code: %d, detach code: %d", thread_ret_websocket, thread_detach_websocket); + if (websocket->websocket_onclose_callback != NULL) { + websocket->websocket_onclose_callback(websocket->request, websocket->websocket_manager, websocket->websocket_onclose_user_data); + } ulfius_clear_websocket(websocket); } } else { @@ -1179,10 +1182,15 @@ */ int ulfius_clear_websocket(struct _websocket * websocket) { if (websocket != NULL) { - if (websocket->websocket_manager->type == U_WEBSOCKET_SERVER && MHD_upgrade_action (websocket->urh, MHD_UPGRADE_ACTION_CLOSE) != MHD_YES) { + if (websocket->websocket_manager != NULL && + websocket->urh != NULL && + websocket->websocket_manager->type == U_WEBSOCKET_SERVER && + MHD_upgrade_action (websocket->urh, MHD_UPGRADE_ACTION_CLOSE) != MHD_YES) { y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error sending MHD_UPGRADE_ACTION_CLOSE frame to urh"); } - ulfius_instance_remove_websocket_active(websocket->instance, websocket); + if (websocket->instance != NULL) { + ulfius_instance_remove_websocket_active(websocket->instance, websocket); + } ulfius_clean_request_full(websocket->request); websocket->request = NULL; ulfius_clear_websocket_manager(websocket->websocket_manager); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ulfius-2.6.1/src/ulfius.c new/ulfius-2.6.2/src/ulfius.c --- old/ulfius-2.6.1/src/ulfius.c 2019-07-01 16:22:23.000000000 +0200 +++ new/ulfius-2.6.2/src/ulfius.c 2019-07-08 13:28:16.000000000 +0200 @@ -546,24 +546,25 @@ #ifndef U_DISABLE_WEBSOCKET } else if (((struct _websocket_handle *)response->websocket_handle)->websocket_manager_callback != NULL || ((struct _websocket_handle *)response->websocket_handle)->websocket_incoming_message_callback != NULL) { - // if the session is a valid websocket request, - // Initiate an UPGRADE session, - // then run the websocket callback functions with initialized data - if (NULL != o_strcasestr(u_map_get_case(con_info->request->map_header, "upgrade"), U_WEBSOCKET_UPGRADE_VALUE) && - NULL != u_map_get_case(con_info->request->map_header, "Sec-WebSocket-Key") && - NULL != u_map_get_case(con_info->request->map_header, "Origin") && - NULL != o_strcasestr(u_map_get_case(con_info->request->map_header, "Connection"), "Upgrade") && - 0 == o_strcmp(con_info->request->http_protocol, "HTTP/1.1") && - 0 == o_strcmp(u_map_get_case(con_info->request->map_header, "Sec-WebSocket-Version"), "13") && - 0 == o_strcmp(con_info->request->http_verb, "GET")) { - int ret_protocol = 0, ret_extensions = 0; - // Check websocket_protocol and websocket_extensions to match ours - if ((ret_extensions = ulfius_check_list_match(u_map_get(con_info->request->map_header, "Sec-WebSocket-Extensions"), ((struct _websocket_handle *)response->websocket_handle)->websocket_extensions, ";", &extension)) == U_OK && - (ret_protocol = ulfius_check_first_match(u_map_get(con_info->request->map_header, "Sec-WebSocket-Protocol"), ((struct _websocket_handle *)response->websocket_handle)->websocket_protocol, ",", &protocol)) == U_OK) { - char websocket_accept[32] = {0}; - if (ulfius_generate_handshake_answer(u_map_get(con_info->request->map_header, "Sec-WebSocket-Key"), websocket_accept)) { - struct _websocket * websocket = o_malloc(sizeof(struct _websocket)); - if (websocket != NULL && ulfius_init_websocket(websocket) == U_OK) { + struct _websocket * websocket = o_malloc(sizeof(struct _websocket)); + int websocket_has_error = 0; + if (websocket != NULL && ulfius_init_websocket(websocket) == U_OK) { + // if the session is a valid websocket request, + // Initiate an UPGRADE session, + // then run the websocket callback functions with initialized data + if (NULL != o_strcasestr(u_map_get_case(con_info->request->map_header, "upgrade"), U_WEBSOCKET_UPGRADE_VALUE) && + NULL != u_map_get_case(con_info->request->map_header, "Sec-WebSocket-Key") && + NULL != u_map_get_case(con_info->request->map_header, "Origin") && + NULL != o_strcasestr(u_map_get_case(con_info->request->map_header, "Connection"), "Upgrade") && + 0 == o_strcmp(con_info->request->http_protocol, "HTTP/1.1") && + 0 == o_strcmp(u_map_get_case(con_info->request->map_header, "Sec-WebSocket-Version"), "13") && + 0 == o_strcmp(con_info->request->http_verb, "GET")) { + int ret_protocol = 0, ret_extensions = 0; + // Check websocket_protocol and websocket_extensions to match ours + if ((ret_extensions = ulfius_check_list_match(u_map_get(con_info->request->map_header, "Sec-WebSocket-Extensions"), ((struct _websocket_handle *)response->websocket_handle)->websocket_extensions, ";", &extension)) == U_OK && + (ret_protocol = ulfius_check_first_match(u_map_get(con_info->request->map_header, "Sec-WebSocket-Protocol"), ((struct _websocket_handle *)response->websocket_handle)->websocket_protocol, ",", &protocol)) == U_OK) { + char websocket_accept[32] = {0}; + if (ulfius_generate_handshake_answer(u_map_get(con_info->request->map_header, "Sec-WebSocket-Key"), websocket_accept)) { websocket->request = ulfius_duplicate_request(con_info->request); if (websocket->request != NULL) { websocket->instance = (struct _u_instance *)cls; @@ -590,13 +591,13 @@ if (ulfius_set_response_header(mhd_response, response->map_header) == -1 || ulfius_set_response_cookie(mhd_response, response) == -1) { y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error setting headers or cookies"); mhd_ret = MHD_NO; + websocket_has_error = 1; } else { ulfius_instance_add_websocket_active((struct _u_instance *)cls, websocket); upgrade_protocol = 1; } } } else { - o_free(websocket); // Error building struct _websocket, sending error 500 response->status = MHD_HTTP_INTERNAL_SERVER_ERROR; response_buffer = o_strdup(ULFIUS_HTTP_ERROR_BODY); @@ -607,9 +608,10 @@ response_buffer_len = o_strlen(ULFIUS_HTTP_ERROR_BODY); mhd_response = MHD_create_response_from_buffer (response_buffer_len, response_buffer, mhd_response_flag ); } + websocket_has_error = 1; } } else { - // Error building struct _websocket, sending error 500 + // Error building ulfius_generate_handshake_answer, sending error 500 response->status = MHD_HTTP_INTERNAL_SERVER_ERROR; response_buffer = o_strdup(ULFIUS_HTTP_ERROR_BODY); if (response_buffer == NULL) { @@ -619,41 +621,51 @@ response_buffer_len = o_strlen(ULFIUS_HTTP_ERROR_BODY); mhd_response = MHD_create_response_from_buffer (response_buffer_len, response_buffer, mhd_response_flag ); } + websocket_has_error = 1; } } else { - // Error building ulfius_generate_handshake_answer, sending error 500 - response->status = MHD_HTTP_INTERNAL_SERVER_ERROR; - response_buffer = o_strdup(ULFIUS_HTTP_ERROR_BODY); - if (response_buffer == NULL) { - y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for response_buffer"); - mhd_ret = MHD_NO; - } else { - response_buffer_len = o_strlen(ULFIUS_HTTP_ERROR_BODY); - mhd_response = MHD_create_response_from_buffer (response_buffer_len, response_buffer, mhd_response_flag ); - } + response->status = MHD_HTTP_BAD_REQUEST; + response_buffer = msprintf("%s%s", (ret_protocol!=U_OK?"Error validating protocol\n":""), (ret_extensions!=U_OK?"Error validating extensions":"")); + y_log_message(Y_LOG_LEVEL_DEBUG, "Ulfius - Error websocket connection: %s", response_buffer); + mhd_response = MHD_create_response_from_buffer (o_strlen(response_buffer), response_buffer, mhd_response_flag ); + websocket_has_error = 1; } + o_free(protocol); + o_free(extension); } else { + response_buffer = msprintf("%s%s%s%s%s%s%s", + o_strcasestr(u_map_get_case(con_info->request->map_header, "upgrade"), U_WEBSOCKET_UPGRADE_VALUE)==NULL?"No Upgrade websocket header\n":"", + o_strcasestr(u_map_get_case(con_info->request->map_header, "Connection"), "Upgrade")==NULL?"No Connection Upgrade header\n":"", + u_map_get_case(con_info->request->map_header, "Sec-WebSocket-Key")==NULL?"No Sec-WebSocket-Key header\n":"", + u_map_get_case(con_info->request->map_header, "Origin")?"No Origin header\n":"", + o_strcmp(con_info->request->http_protocol, "HTTP/1.1")!=0?"Wrong HTTP Protocolv":"", + o_strcmp(u_map_get_case(con_info->request->map_header, "Sec-WebSocket-Version"), "13")!=0?"Wrong websocket version\n":"", + o_strcmp(con_info->request->http_verb, "GET")!=0?"Method is not GET":""); response->status = MHD_HTTP_BAD_REQUEST; - response_buffer = msprintf("%s%s", (ret_protocol!=U_OK?"Error validating protocol\n":""), (ret_extensions!=U_OK?"Error validating extensions":"")); y_log_message(Y_LOG_LEVEL_DEBUG, "Ulfius - Error websocket connection: %s", response_buffer); mhd_response = MHD_create_response_from_buffer (o_strlen(response_buffer), response_buffer, mhd_response_flag ); + websocket_has_error = 1; } - o_free(protocol); - o_free(extension); } else { - response_buffer = msprintf("%s%s%s%s%s%s%s", - o_strcasestr(u_map_get_case(con_info->request->map_header, "upgrade"), U_WEBSOCKET_UPGRADE_VALUE)==NULL?"No Upgrade websocket header\n":"", - o_strcasestr(u_map_get_case(con_info->request->map_header, "Connection"), "Upgrade")==NULL?"No Connection Upgrade header\n":"", - u_map_get_case(con_info->request->map_header, "Sec-WebSocket-Key")==NULL?"No Sec-WebSocket-Key header\n":"", - u_map_get_case(con_info->request->map_header, "Origin")?"No Origin header\n":"", - o_strcmp(con_info->request->http_protocol, "HTTP/1.1")!=0?"Wrong HTTP Protocolv":"", - o_strcmp(u_map_get_case(con_info->request->map_header, "Sec-WebSocket-Version"), "13")!=0?"Wrong websocket version\n":"", - o_strcmp(con_info->request->http_verb, "GET")!=0?"Method is not GET":""); - response->status = MHD_HTTP_BAD_REQUEST; - y_log_message(Y_LOG_LEVEL_DEBUG, "Ulfius - Error websocket connection: %s", response_buffer); - mhd_response = MHD_create_response_from_buffer (o_strlen(response_buffer), response_buffer, mhd_response_flag ); + // Error building struct _websocket, sending error 500 + response->status = MHD_HTTP_INTERNAL_SERVER_ERROR; + response_buffer = o_strdup(ULFIUS_HTTP_ERROR_BODY); + if (response_buffer == NULL) { + y_log_message(Y_LOG_LEVEL_ERROR, "Ulfius - Error allocating memory for response_buffer"); + mhd_ret = MHD_NO; + } else { + response_buffer_len = o_strlen(ULFIUS_HTTP_ERROR_BODY); + mhd_response = MHD_create_response_from_buffer (response_buffer_len, response_buffer, mhd_response_flag ); + } + websocket_has_error = 1; } close_loop = 1; + if (websocket_has_error) { + if (((struct _websocket_handle *)response->websocket_handle)->websocket_onclose_callback != NULL) { + ((struct _websocket_handle *)response->websocket_handle)->websocket_onclose_callback(con_info->request, websocket->websocket_manager!=NULL?websocket->websocket_manager:NULL, ((struct _websocket_handle *)response->websocket_handle)->websocket_onclose_user_data); + } + ulfius_clear_websocket(websocket); + } #endif } else { if (callback_ret == U_CALLBACK_CONTINUE && current_endpoint_list[i+1] == NULL) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ulfius-2.6.1/test/Makefile new/ulfius-2.6.2/test/Makefile --- old/ulfius-2.6.1/test/Makefile 2019-07-01 16:22:23.000000000 +0200 +++ new/ulfius-2.6.2/test/Makefile 2019-07-08 13:28:16.000000000 +0200 @@ -24,13 +24,12 @@ ULFIUS_LIBRARY=$(ULFIUS_LOCATION)/libulfius.so CC=gcc CFLAGS+=-Wall -D_REENTRANT -I$(ULFIUS_INCLUDE) -DDEBUG -g -O0 $(CPPFLAGS) -LIBS=-lc -lorcania -lulfius -lyder -ljansson -lgnutls -lcheck -lpthread -lm -lrt -lsubunit -L$(ULFIUS_LOCATION) +LIBS=-lc -lorcania -lulfius -lyder -ljansson -lgnutls $(shell pkg-config --libs check) -L$(ULFIUS_LOCATION) # Use this LIBS below if you don't have/need gnutls #LIBS=-lc -lorcania -lyder -lulfius -lcheck -lpthread -lm -lrt -lsubunit -L$(ULFIUS_LOCATION) # Use this LIBS below if you use yder logs #LIBS=-lc -lorcania -lyder -lulfius -lgnutls -lcheck -lpthread -lm -lrt -lsubunit -L$(ULFIUS_LOCATION) VALGRIND_COMMAND=valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all - all: test clean: @@ -43,25 +42,25 @@ $(CC) $(CFLAGS) u_map.c -o u_map $(LIBS) test_u_map: $(ULFIUS_LIBRARY) u_map - -LD_LIBRARY_PATH=$(ULFIUS_LOCATION):${LD_LIBRARY_PATH} ./u_map + LD_LIBRARY_PATH=$(ULFIUS_LOCATION):${LD_LIBRARY_PATH} ./u_map core: core.c $(CC) $(CFLAGS) core.c -o core $(LIBS) test_core: $(ULFIUS_LIBRARY) core - -LD_LIBRARY_PATH=$(ULFIUS_LOCATION):${LD_LIBRARY_PATH} ./core + LD_LIBRARY_PATH=$(ULFIUS_LOCATION):${LD_LIBRARY_PATH} ./core framework: framework.c $(CC) $(CFLAGS) framework.c -o framework $(LIBS) test_framework: $(ULFIUS_LIBRARY) framework - -LD_LIBRARY_PATH=$(ULFIUS_LOCATION):${LD_LIBRARY_PATH} ./framework + LD_LIBRARY_PATH=$(ULFIUS_LOCATION):${LD_LIBRARY_PATH} ./framework websocket: websocket.c $(CC) $(CFLAGS) websocket.c -o websocket $(LIBS) test_websocket: $(ULFIUS_LIBRARY) websocket - -LD_LIBRARY_PATH=$(ULFIUS_LOCATION):${LD_LIBRARY_PATH} ./websocket + LD_LIBRARY_PATH=$(ULFIUS_LOCATION):${LD_LIBRARY_PATH} ./websocket test: test_u_map test_core test_framework test_websocket diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ulfius-2.6.1/test/websocket.c new/ulfius-2.6.2/test/websocket.c --- old/ulfius-2.6.1/test/websocket.c 2019-07-01 16:22:23.000000000 +0200 +++ new/ulfius-2.6.2/test/websocket.c 2019-07-08 13:28:16.000000000 +0200 @@ -26,6 +26,10 @@ void websocket_onclose_callback_empty (const struct _u_request * request, struct _websocket_manager * websocket_manager, void * websocket_onclose_user_data) { } +void websocket_onclose_callback_client (const struct _u_request * request, struct _websocket_manager * websocket_manager, void * websocket_onclose_user_data) { + ck_assert_ptr_ne(websocket_onclose_user_data, NULL); +} + void websocket_echo_message_callback (const struct _u_request * request, struct _websocket_manager * websocket_manager, const struct _websocket_message * last_message, @@ -35,6 +39,10 @@ } } +void websocket_onclose_message_callback (const struct _u_request * request, struct _websocket_manager * websocket_manager, void * websocket_onclose_user_data) { + o_free(websocket_onclose_user_data); +} + void websocket_manager_callback_client (const struct _u_request * request, struct _websocket_manager * websocket_manager, void * websocket_manager_user_data) { int i; @@ -55,6 +63,15 @@ int callback_websocket (const struct _u_request * request, struct _u_response * response, void * user_data) { int ret; + char * websocket_allocated_data = o_strdup("grut"); + + ret = ulfius_set_websocket_response(response, NULL, NULL, NULL, NULL, &websocket_echo_message_callback, websocket_allocated_data, &websocket_onclose_message_callback, websocket_allocated_data); + ck_assert_int_eq(ret, U_OK); + return (ret == U_OK)?U_CALLBACK_CONTINUE:U_CALLBACK_ERROR; +} + +int callback_websocket_onclose (const struct _u_request * request, struct _u_response * response, void * user_data) { + int ret; ret = ulfius_set_websocket_response(response, NULL, NULL, NULL, NULL, &websocket_echo_message_callback, NULL, NULL, NULL); ck_assert_int_eq(ret, U_OK); @@ -116,26 +133,92 @@ struct _u_request request; struct _u_response response; struct _websocket_client_handler websocket_client_handler; - char url[64]; + char url[64], * allocated_data = o_strdup("plop"); ck_assert_int_eq(ulfius_init_instance(&instance, PORT, NULL, NULL), U_OK); - ck_assert_int_eq(ulfius_add_endpoint_by_val(&instance, "GET", PREFIX_WEBSOCKET, NULL, 0, &callback_websocket, NULL), U_OK); + ck_assert_int_eq(ulfius_add_endpoint_by_val(&instance, "GET", PREFIX_WEBSOCKET, NULL, 0, &callback_websocket, allocated_data), U_OK); ck_assert_int_eq(ulfius_start_framework(&instance), U_OK); ulfius_init_request(&request); ulfius_init_response(&response); sprintf(url, "ws://localhost:%d/%s", PORT, PREFIX_WEBSOCKET); + // Test correct websocket connection on correct websocket service ck_assert_int_eq(ulfius_set_websocket_request(&request, url, DEFAULT_PROTOCOL, DEFAULT_EXTENSION), U_OK); - ck_assert_int_eq(ulfius_open_websocket_client_connection(&request, &websocket_manager_callback_client, NULL, &websocket_incoming_message_callback_client, NULL, NULL, NULL, &websocket_client_handler, &response), U_OK); + ck_assert_int_eq(ulfius_open_websocket_client_connection(&request, &websocket_manager_callback_client, NULL, &websocket_incoming_message_callback_client, NULL, websocket_onclose_callback_client, allocated_data, &websocket_client_handler, &response), U_OK); ck_assert_int_eq(ulfius_websocket_client_connection_wait_close(&websocket_client_handler, 0), U_WEBSOCKET_STATUS_CLOSE); + ulfius_clean_request(&request); + ulfius_clean_response(&response); + + // Test incorrect websocket connection on correct websocket service + ulfius_init_request(&request); + ulfius_init_response(&response); + request.http_verb = o_strdup("GET"); + request.http_url = o_strdup(url); + ck_assert_int_eq(ulfius_send_http_request(&request, &response), U_ERROR_LIBCURL); // On a websocket connection attempt, libcurl return 'Unsupported protocol' + ulfius_clean_request(&request); + ulfius_clean_response(&response); + + // Test incorrect websocket connection on correct websocket service + ulfius_init_request(&request); + ulfius_init_response(&response); + ck_assert_int_eq(ulfius_set_websocket_request(&request, url, DEFAULT_PROTOCOL, DEFAULT_EXTENSION), U_OK); + ck_assert_int_eq(ulfius_open_websocket_client_connection(&request, &websocket_manager_callback_client, NULL, &websocket_incoming_message_callback_client, NULL, websocket_onclose_callback_client, allocated_data, &websocket_client_handler, &response), U_OK); + ck_assert_int_eq(ulfius_websocket_client_connection_wait_close(&websocket_client_handler, 0), U_WEBSOCKET_STATUS_CLOSE); + ulfius_clean_request(&request); + ulfius_clean_response(&response); ck_assert_int_eq(ulfius_stop_framework(&instance), U_OK); ulfius_clean_instance(&instance); + o_free(allocated_data); +} +END_TEST + +START_TEST(test_websocket_ulfius_websocket_client_no_onclose) +{ + struct _u_instance instance; + struct _u_request request; + struct _u_response response; + struct _websocket_client_handler websocket_client_handler; + char url[64]; + ck_assert_int_eq(ulfius_init_instance(&instance, PORT, NULL, NULL), U_OK); + ck_assert_int_eq(ulfius_add_endpoint_by_val(&instance, "GET", PREFIX_WEBSOCKET, NULL, 0, &callback_websocket_onclose, NULL), U_OK); + ck_assert_int_eq(ulfius_start_framework(&instance), U_OK); + + ulfius_init_request(&request); + ulfius_init_response(&response); + sprintf(url, "ws://localhost:%d/%s", PORT, PREFIX_WEBSOCKET); + + // Test correct websocket connection on correct websocket service + ck_assert_int_eq(ulfius_set_websocket_request(&request, url, DEFAULT_PROTOCOL, DEFAULT_EXTENSION), U_OK); + ck_assert_int_eq(ulfius_open_websocket_client_connection(&request, &websocket_manager_callback_client, NULL, &websocket_incoming_message_callback_client, NULL, NULL, NULL, &websocket_client_handler, &response), U_OK); + ck_assert_int_eq(ulfius_websocket_client_connection_wait_close(&websocket_client_handler, 0), U_WEBSOCKET_STATUS_CLOSE); ulfius_clean_request(&request); ulfius_clean_response(&response); + + // Test incorrect websocket connection on correct websocket service + ulfius_init_request(&request); + ulfius_init_response(&response); + request.http_verb = o_strdup("GET"); + request.http_url = o_strdup(url); + ck_assert_int_eq(ulfius_send_http_request(&request, &response), U_ERROR_LIBCURL); // On a websocket connection attempt, libcurl return 'Unsupported protocol' + ulfius_clean_request(&request); + ulfius_clean_response(&response); + + // Test incorrect websocket connection on correct websocket service + ulfius_init_request(&request); + ulfius_init_response(&response); + ck_assert_int_eq(ulfius_set_websocket_request(&request, url, DEFAULT_PROTOCOL, DEFAULT_EXTENSION), U_OK); + ck_assert_int_eq(ulfius_open_websocket_client_connection(&request, &websocket_manager_callback_client, NULL, &websocket_incoming_message_callback_client, NULL, NULL, NULL, &websocket_client_handler, &response), U_OK); + ck_assert_int_eq(ulfius_websocket_client_connection_wait_close(&websocket_client_handler, 0), U_WEBSOCKET_STATUS_CLOSE); + ulfius_clean_request(&request); + ulfius_clean_response(&response); + + ck_assert_int_eq(ulfius_stop_framework(&instance), U_OK); + ulfius_clean_instance(&instance); } END_TEST + #endif static Suite *ulfius_suite(void) @@ -150,6 +233,7 @@ tcase_add_test(tc_websocket, test_websocket_ulfius_set_websocket_request); tcase_add_test(tc_websocket, test_websocket_ulfius_open_websocket_client_connection_error); tcase_add_test(tc_websocket, test_websocket_ulfius_websocket_client); + tcase_add_test(tc_websocket, test_websocket_ulfius_websocket_client_no_onclose); #endif tcase_set_timeout(tc_websocket, 30); suite_add_tcase(s, tc_websocket);
