libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

commit 1a23dd25c36bdb0e0be264730e9088a49a1e8152
parent 111e08fbe3f436bd21f78ab8c6c4c3b79e728bba
Author: Christian Grothoff <christian@grothoff.org>
Date:   Thu,  5 Oct 2017 23:16:19 +0200

misc style improvements, fixing some tiny rare memory leaks in examples

Diffstat:
Mdoc/examples/largepost.c | 4+++-
Msrc/examples/chunked_example.c | 35++++++++++++++++++++++++++++-------
Msrc/examples/demo.c | 6+++---
Msrc/examples/https_fileserver_example.c | 42++++++++++++++++++++++++------------------
Msrc/examples/post_example.c | 22++++++++++++++++------
Msrc/microhttpd/connection.c | 7++++---
Msrc/microhttpd/response.c | 8++++----
Msrc/microhttpd/test_shutdown_select.c | 7++++---
Msrc/testcurl/https/test_https_session_info.c | 4+++-
Msrc/testcurl/https/test_tls_extensions.c | 4+++-
Msrc/testcurl/https/test_tls_options.c | 7+++++--
Msrc/testcurl/https/tls_test_common.c | 82+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Msrc/testcurl/https/tls_test_common.h | 27+++++++++++++++++++--------
Msrc/testcurl/test_callback.c | 14++++++++++----
Msrc/testcurl/test_get_chunked.c | 45+++++++++++++++++++++++++++++++++------------
15 files changed, 208 insertions(+), 106 deletions(-)

diff --git a/doc/examples/largepost.c b/doc/examples/largepost.c @@ -151,7 +151,9 @@ iterate_post (void *coninfo_cls, con_info->answercode = MHD_HTTP_FORBIDDEN; return MHD_YES; } - + /* NOTE: This is technically a race with the 'fopen()' above, + but there is no easy fix, short of moving to open(O_EXCL) + instead of using fopen(). For the example, we do not care. */ con_info->fp = fopen (filename, "ab"); if (!con_info->fp) { diff --git a/src/examples/chunked_example.c b/src/examples/chunked_example.c @@ -32,6 +32,7 @@ struct ResponseContentCallbackParam size_t response_size; }; + static ssize_t callback (void *cls, uint64_t pos, @@ -77,12 +78,14 @@ callback (void *cls, return size_to_copy; } -void -free_callback_param(void *cls) + +static void +free_callback_param (void *cls) { free(cls); } + static const char simple_response_text[] = "<html><head><title>Simple response</title></head>" "<body>Simple response text</body></html>"; @@ -93,10 +96,12 @@ ahc_echo (void *cls, const char *url, const char *method, const char *version, - const char *upload_data, size_t *upload_data_size, void **ptr) + const char *upload_data, + size_t *upload_data_size, + void **ptr) { static int aptr; - struct ResponseContentCallbackParam * callback_param; + struct ResponseContentCallbackParam *callback_param; struct MHD_Response *response; int ret; (void)cls; /* Unused. Silent compiler warning. */ @@ -127,31 +132,47 @@ ahc_echo (void *cls, &callback, callback_param, &free_callback_param); + if (NULL == response) + { + free (callback_param); + return MHD_NO; + } ret = MHD_queue_response (connection, MHD_HTTP_OK, response); MHD_destroy_response (response); return ret; } + int main (int argc, char *const *argv) { struct MHD_Daemon *d; + int port; if (argc != 2) { printf ("%s PORT\n", argv[0]); return 1; } + port = atoi (argv[1]); + if ( (1 > port) || + (port > UINT16_MAX) ) + { + fprintf (stderr, + "Port must be a number between 1 and 65535\n"); + return 1; + } d = MHD_start_daemon (// MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG, MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG, // MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG | MHD_USE_POLL, // MHD_USE_THREAD_PER_CONNECTION | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG | MHD_USE_POLL, // MHD_USE_THREAD_PER_CONNECTION | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG, - atoi (argv[1]), - NULL, NULL, &ahc_echo, NULL, + (uint16_t) port, + NULL, NULL, + &ahc_echo, NULL, MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 120, MHD_OPTION_END); - if (d == NULL) + if (NULL == d) return 1; (void) getc (stdin); MHD_stop_daemon (d); diff --git a/src/examples/demo.c b/src/examples/demo.c @@ -254,7 +254,7 @@ struct ResponseDataContext * * @param rdc where to store the list of files * @param dirname name of the directory to list - * @return MHD_YES on success, MHD_NO on error + * @return #MHD_YES on success, #MHD_NO on error */ static int list_directory (struct ResponseDataContext *rdc, @@ -271,7 +271,7 @@ list_directory (struct ResponseDataContext *rdc, { if ('.' == de->d_name[0]) continue; - if (sizeof (fullname) <= (size_t) + if (sizeof (fullname) <= (unsigned int) snprintf (fullname, sizeof (fullname), "%s/%s", dirname, de->d_name)) @@ -555,7 +555,7 @@ process_upload_data (void *cls, uc->category, filename); for (i=strlen (fn)-1;i>=0;i--) - if (! isprint ((int) fn[i])) + if (! isprint ((unsigned char) fn[i])) fn[i] = '_'; uc->fd = open (fn, O_CREAT | O_EXCL diff --git a/src/examples/https_fileserver_example.c b/src/examples/https_fileserver_example.c @@ -191,38 +191,44 @@ int main (int argc, char *const *argv) { struct MHD_Daemon *TLS_daemon; + int port; - if (argc == 2) + if (argc != 2) { - /* TODO check if this is truly necessary - disallow usage of the blocking /dev/random */ - /* gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0); */ - TLS_daemon = - MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG | - MHD_USE_TLS, atoi (argv[1]), NULL, NULL, &http_ahc, - NULL, MHD_OPTION_CONNECTION_TIMEOUT, 256, - MHD_OPTION_HTTPS_MEM_KEY, key_pem, - MHD_OPTION_HTTPS_MEM_CERT, cert_pem, - MHD_OPTION_END); + printf ("%s PORT\n", argv[0]); + return 1; } - else + port = atoi (argv[1]); + if ( (1 > port) || + (port > UINT16_MAX) ) { - printf ("Usage: %s HTTP-PORT\n", argv[0]); + fprintf (stderr, + "Port must be a number between 1 and 65535\n"); return 1; } - if (TLS_daemon == NULL) + /* TODO check if this is truly necessary - disallow usage of the blocking /dev/random */ + /* gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0); */ + TLS_daemon = + MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG | + MHD_USE_TLS, + (uint16_t) port, + NULL, NULL, + &http_ahc, NULL, + MHD_OPTION_CONNECTION_TIMEOUT, 256, + MHD_OPTION_HTTPS_MEM_KEY, key_pem, + MHD_OPTION_HTTPS_MEM_CERT, cert_pem, + MHD_OPTION_END); + if (NULL == TLS_daemon) { fprintf (stderr, "Error: failed to start TLS_daemon\n"); return 1; } - else - { - printf ("MHD daemon listening on port %d\n", atoi (argv[1])); - } + printf ("MHD daemon listening on port %u\n", + (unsigned int) port); (void) getc (stdin); MHD_stop_daemon (TLS_daemon); - return 0; } diff --git a/src/examples/post_example.c b/src/examples/post_example.c @@ -313,23 +313,28 @@ fill_v1_form (const void *cls, struct MHD_Connection *connection) { int ret; + size_t slen; char *reply; struct MHD_Response *response; (void)cls; /* Unused. Silent compiler warning. */ - reply = malloc (strlen (MAIN_PAGE) + strlen (session->value_1) + 1); + slen = strlen (MAIN_PAGE) + strlen (session->value_1); + reply = malloc (slen + 1); if (NULL == reply) return MHD_NO; snprintf (reply, - strlen (MAIN_PAGE) + strlen (session->value_1) + 1, + slen + 1, MAIN_PAGE, session->value_1); /* return static form */ - response = MHD_create_response_from_buffer (strlen (reply), + response = MHD_create_response_from_buffer (slen, (void *) reply, MHD_RESPMEM_MUST_FREE); if (NULL == response) + { + free (reply); return MHD_NO; + } add_session_cookie (session, response); MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_ENCODING, @@ -359,22 +364,27 @@ fill_v1_v2_form (const void *cls, int ret; char *reply; struct MHD_Response *response; + size_t slen; (void)cls; /* Unused. Silent compiler warning. */ - reply = malloc (strlen (SECOND_PAGE) + strlen (session->value_1) + strlen (session->value_2) + 1); + slen = strlen (SECOND_PAGE) + strlen (session->value_1) + strlen (session->value_2); + reply = malloc (slen + 1); if (NULL == reply) return MHD_NO; snprintf (reply, - strlen (SECOND_PAGE) + strlen (session->value_1) + strlen (session->value_2) + 1, + slen + 1, SECOND_PAGE, session->value_1, session->value_2); /* return static form */ - response = MHD_create_response_from_buffer (strlen (reply), + response = MHD_create_response_from_buffer (slen, (void *) reply, MHD_RESPMEM_MUST_FREE); if (NULL == response) + { + free (reply); return MHD_NO; + } add_session_cookie (session, response); MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_ENCODING, diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c @@ -1070,7 +1070,7 @@ try_ready_normal_body (struct MHD_Connection *connection) * Prepare the response buffer of this connection for sending. * Assumes that the response mutex is already held. If the * transmission is complete, this function may close the socket (and - * return MHD_NO). + * return #MHD_NO). * * @param connection the connection * @return #MHD_NO if readying the response failed @@ -1086,6 +1086,8 @@ try_ready_chunked_body (struct MHD_Connection *connection) int cblen; response = connection->response; + if (NULL == response->crc) + return MHD_YES; if (0 == connection->write_buffer_size) { size = MHD_MIN (connection->daemon->pool_size, @@ -3533,8 +3535,7 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) socket_start_no_buffering (connection); continue; } - if (NULL != connection->response->crc) - MHD_mutex_unlock_chk_ (&connection->response->mutex); + MHD_mutex_unlock_chk_ (&connection->response->mutex); break; case MHD_CONNECTION_BODY_SENT: if (MHD_NO == build_header_response (connection)) diff --git a/src/microhttpd/response.c b/src/microhttpd/response.c @@ -316,10 +316,10 @@ MHD_create_response_from_callback (uint64_t size, response->data = (void *) &response[1]; response->data_buffer_size = block_size; if (! MHD_mutex_init_ (&response->mutex)) - { - free (response); - return NULL; - } + { + free (response); + return NULL; + } response->crc = crc; response->crfc = crfc; response->crc_cls = crc_cls; diff --git a/src/microhttpd/test_shutdown_select.c b/src/microhttpd/test_shutdown_select.c @@ -112,10 +112,11 @@ has_in_name(const char *prog_name, const char *marker) pos++; } if (name_pos == pos) - return !0; + return true; return strstr(prog_name + name_pos, marker) != NULL; } + static MHD_socket start_socket_listen(int domain) { @@ -290,7 +291,7 @@ main (int argc, char *const *argv) test_poll = has_in_name(argv[0], "_poll"); must_ignore = has_in_name(argv[0], "_ignore"); - if (!test_poll) + if (! test_poll) test_func = &select_thread; else { @@ -324,7 +325,7 @@ main (int argc, char *const *argv) if (MHD_INVALID_SOCKET == listen_socket) return 99; - check_err = !0; + check_err = true; /* fprintf (stdout, "Starting select() thread...\n"); */ #if defined(MHD_USE_POSIX_THREADS) if (0 != pthread_create (&sel_thrd, NULL, test_func, &listen_socket)) diff --git a/src/testcurl/https/test_https_session_info.c b/src/testcurl/https/test_https_session_info.c @@ -141,7 +141,9 @@ test_query_session () aes256_sha = "rsa_aes_256_sha"; } - gen_test_file_url (url, port); + gen_test_file_url (url, + sizeof (url), + port); c = curl_easy_init (); #if DEBUG_HTTPS_TEST curl_easy_setopt (c, CURLOPT_VERBOSE, 1); diff --git a/src/testcurl/https/test_tls_extensions.c b/src/testcurl/https/test_tls_extensions.c @@ -168,7 +168,9 @@ test_hello_extension (gnutls_session_t session, int port, extensions_t exten_t, gnutls_transport_set_ptr (session, (MHD_gnutls_transport_ptr_t) (long) sd); - if (gen_test_file_url (url, port)) + if (gen_test_file_url (url, + sizeof (url), + port)) { ret = -1; goto cleanup; diff --git a/src/testcurl/https/test_tls_options.c b/src/testcurl/https/test_tls_options.c @@ -57,10 +57,13 @@ test_unmatching_ssl_version (void * cls, int port, const char *cipher_suite, cbc.pos = 0; char url[255]; - if (gen_test_file_url (url, port)) + if (gen_test_file_url (url, + sizeof (url), + port)) { free (cbc.buf); - fprintf (stderr, "Internal error in gen_test_file_url\n"); + fprintf (stderr, + "Internal error in gen_test_file_url\n"); return -1; } diff --git a/src/testcurl/https/tls_test_common.c b/src/testcurl/https/tls_test_common.c @@ -84,7 +84,9 @@ test_daemon_get (void *cls, cbc.pos = 0; /* construct url - this might use doc_path */ - gen_test_file_url (url, port); + gen_test_file_url (url, + sizeof (url), + port); c = curl_easy_init (); #if DEBUG_HTTPS_TEST @@ -108,7 +110,7 @@ test_daemon_get (void *cls, curl_easy_setopt (c, CURLOPT_CAINFO, ca_cert_file_name); curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0); curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); - + /* NOTE: use of CONNECTTIMEOUT without also setting NOSIGNAL results in really weird crashes on my system! */ @@ -258,12 +260,15 @@ send_curl_req (char *url, struct CBC * cbc, const char *cipher_suite, /** * compile test file url pointing to the current running directory path * - * @param url - char buffer into which the url is compiled + * @param[out] url - char buffer into which the url is compiled + * @param url_len number of bytes available in url * @param port port to use for the test * @return -1 on error */ int -gen_test_file_url (char *url, int port) +gen_test_file_url (char *url, + size_t url_len, + int port) { int ret = 0; char *doc_path; @@ -279,46 +284,54 @@ gen_test_file_url (char *url, int port) fprintf (stderr, MHD_E_MEM); return -1; } - if (getcwd (doc_path, doc_path_len) == NULL) + if (NULL == getcwd (doc_path, doc_path_len)) { - fprintf (stderr, "Error: failed to get working directory. %s\n", + fprintf (stderr, + "Error: failed to get working directory. %s\n", strerror (errno)); - ret = -1; + free (doc_path); + return -1; } #ifdef WINDOWS + for (int i = 0; i < doc_path_len; i++) { - int i; - for (i = 0; i < doc_path_len; i++) - { - if (doc_path[i] == 0) - break; - if (doc_path[i] == '\\') + if (doc_path[i] == 0) + break; + if (doc_path[i] == '\\') { doc_path[i] = '/'; } - if (doc_path[i] != ':') - continue; - if (i == 0) - break; - doc_path[i] = doc_path[i - 1]; - doc_path[i - 1] = '/'; - } + if (doc_path[i] != ':') + continue; + if (i == 0) + break; + doc_path[i] = doc_path[i - 1]; + doc_path[i - 1] = '/'; } #endif - /* construct url - this might use doc_path */ - if (sprintf (url, "%s:%d%s/%s", "https://127.0.0.1", port, - doc_path, "urlpath") < 0) + /* construct url */ + if (snprintf (url, + url_len, + "%s:%d%s/%s", + "https://127.0.0.1", + port, + doc_path, + "urlpath") >= url_len) ret = -1; free (doc_path); return ret; } + /** * test HTTPS file transfer */ int -test_https_transfer (void *cls, int port, const char *cipher_suite, int proto_version) +test_https_transfer (void *cls, + int port, + const char *cipher_suite, + int proto_version) { int len; int ret = 0; @@ -334,13 +347,16 @@ test_https_transfer (void *cls, int port, const char *cipher_suite, int proto_ve cbc.size = len; cbc.pos = 0; - if (gen_test_file_url (url, port)) + if (gen_test_file_url (url, + sizeof (url), + port)) { ret = -1; goto cleanup; } - if (CURLE_OK != send_curl_req (url, &cbc, cipher_suite, proto_version)) + if (CURLE_OK != + send_curl_req (url, &cbc, cipher_suite, proto_version)) { ret = -1; goto cleanup; @@ -348,8 +364,8 @@ test_https_transfer (void *cls, int port, const char *cipher_suite, int proto_ve /* compare test file & daemon responce */ if ( (len != strlen (test_data)) || - (memcmp (cbc.buf, - test_data, + (memcmp (cbc.buf, + test_data, len) != 0) ) { fprintf (stderr, "Error: local file & received file differ.\n"); @@ -404,7 +420,7 @@ teardown_testcase (struct MHD_Daemon *d) int setup_session (gnutls_session_t * session, gnutls_datum_t * key, - gnutls_datum_t * cert, + gnutls_datum_t * cert, gnutls_certificate_credentials_t * xcred) { int ret; @@ -413,7 +429,7 @@ setup_session (gnutls_session_t * session, gnutls_certificate_allocate_credentials (xcred); key->size = strlen (srv_key_pem) + 1; key->data = malloc (key->size); - if (NULL == key->data) + if (NULL == key->data) { gnutls_certificate_free_credentials (*xcred); return -1; @@ -424,7 +440,7 @@ setup_session (gnutls_session_t * session, if (NULL == cert->data) { gnutls_certificate_free_credentials (*xcred); - free (key->data); + free (key->data); return -1; } memcpy (cert->data, srv_self_signed_cert_pem, cert->size); @@ -440,8 +456,8 @@ setup_session (gnutls_session_t * session, free (key->data); return -1; } - gnutls_credentials_set (*session, - GNUTLS_CRD_CERTIFICATE, + gnutls_credentials_set (*session, + GNUTLS_CRD_CERTIFICATE, *xcred); return 0; } diff --git a/src/testcurl/https/tls_test_common.h b/src/testcurl/https/tls_test_common.h @@ -68,12 +68,15 @@ struct CipherDef }; -int curl_check_version (const char *req_version, ...); -int curl_uses_nss_ssl (); +int +curl_check_version (const char *req_version, ...); + +int +curl_uses_nss_ssl (void); FILE * -setup_ca_cert (); +setup_ca_cert (void); /** * perform cURL request for file @@ -83,9 +86,11 @@ test_daemon_get (void * cls, const char *cipher_suite, int proto_version, int port, int ver_peer); -void print_test_result (int test_outcome, char *test_name); +void +print_test_result (int test_outcome, char *test_name); -size_t copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx); +size_t +copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx); int http_ahc (void *cls, struct MHD_Connection *connection, @@ -102,11 +107,15 @@ http_dummy_ahc (void *cls, struct MHD_Connection *connection, /** * compile test file url pointing to the current running directory path * - * @param url - char buffer into which the url is compiled + * @param[out] url - char buffer into which the url is compiled + * @param url_len number of bytes available in @a url * @param port port to use for the test * @return -1 on error */ -int gen_test_file_url (char *url, int port); +int +gen_test_file_url (char *url, + size_t url_len, + int port); int send_curl_req (char *url, struct CBC *cbc, const char *cipher_suite, @@ -118,7 +127,9 @@ test_https_transfer (void *cls, int port, const char *cipher_suite, int proto_ve int setup_testcase (struct MHD_Daemon **d, int port, int daemon_flags, va_list arg_list); -void teardown_testcase (struct MHD_Daemon *d); +void +teardown_testcase (struct MHD_Daemon *d); + int setup_session (gnutls_session_t * session, diff --git a/src/testcurl/test_callback.c b/src/testcurl/test_callback.c @@ -69,15 +69,21 @@ callback(void *cls, { struct callback_closure *cbc = calloc(1, sizeof(struct callback_closure)); struct MHD_Response *r; + int ret; r = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, 1024, &called_twice, cbc, &free); - MHD_queue_response (connection, - MHD_HTTP_OK, - r); + if (NULL == r) + { + free (cbc); + return MHD_NO; + } + ret = MHD_queue_response (connection, + MHD_HTTP_OK, + r); MHD_destroy_response (r); - return MHD_YES; + return ret; } diff --git a/src/testcurl/test_get_chunked.c b/src/testcurl/test_get_chunked.c @@ -54,8 +54,12 @@ struct CBC size_t size; }; + static size_t -copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) +copyBuffer (void *ptr, + size_t size, + size_t nmemb, + void *ctx) { struct CBC *cbc = ctx; @@ -66,28 +70,34 @@ copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) return size * nmemb; } + /** - * MHD content reader callback that returns - * data in chunks. + * MHD content reader callback that returns data in chunks. */ static ssize_t -crc (void *cls, uint64_t pos, char *buf, size_t max) +crc (void *cls, + uint64_t pos, + char *buf, + size_t max) { struct MHD_Response **responseptr = cls; if (pos == 128 * 10) - { - MHD_add_response_header (*responseptr, "Footer", "working"); - return MHD_CONTENT_READER_END_OF_STREAM; - } + { + MHD_add_response_footer (*responseptr, + "Footer", + "working"); + return MHD_CONTENT_READER_END_OF_STREAM; + } if (max < 128) abort (); /* should not happen in this testcase... */ memset (buf, 'A' + (pos / 128), 128); return 128; } + /** - * Dummy function that does nothing. + * Dummy function that frees the "responseptr". */ static void crcf (void *ptr) @@ -95,6 +105,7 @@ crcf (void *ptr) free (ptr); } + static int ahc_echo (void *cls, struct MHD_Connection *connection, @@ -118,17 +129,27 @@ ahc_echo (void *cls, return MHD_YES; } responseptr = malloc (sizeof (struct MHD_Response *)); - if (responseptr == NULL) + if (NULL == responseptr) return MHD_NO; response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, 1024, - &crc, responseptr, &crcf); + &crc, + responseptr, + &crcf); + if (NULL == response) + { + free (responseptr); + return MHD_NO; + } *responseptr = response; - ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + ret = MHD_queue_response (connection, + MHD_HTTP_OK, + response); MHD_destroy_response (response); return ret; } + static int validate (struct CBC cbc, int ebase) {