From 40b062f1bd77d60279555a2f40f853d829b15db6 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Tue, 9 Sep 2025 15:12:03 +0200 Subject: check_curl: more refactoring --- plugins/check_curl.c | 787 ++++++++++++++++++++++++++++----------------------- 1 file changed, 437 insertions(+), 350 deletions(-) (limited to 'plugins/check_curl.c') diff --git a/plugins/check_curl.c b/plugins/check_curl.c index 94b726d0..76dcbfd8 100644 --- a/plugins/check_curl.c +++ b/plugins/check_curl.c @@ -115,21 +115,37 @@ enum { #include "regex.h" // Globals -static bool curl_global_initialized = false; -static bool curl_easy_initialized = false; static int verbose = 0; -static bool body_buf_initialized = false; -static curlhelp_write_curlbuf body_buf; -static bool header_buf_initialized = false; -static curlhelp_write_curlbuf header_buf; -static bool status_line_initialized = false; -static curlhelp_statusline status_line; -static bool put_buf_initialized = false; -static curlhelp_read_curlbuf put_buf; - -static CURL *curl; -static struct curl_slist *header_list = NULL; -static long code; + +typedef struct { + bool curl_global_initialized; + bool curl_easy_initialized; + bool body_buf_initialized; + curlhelp_write_curlbuf body_buf; + bool header_buf_initialized; + curlhelp_write_curlbuf header_buf; + bool status_line_initialized; + curlhelp_statusline status_line; + bool put_buf_initialized; + curlhelp_read_curlbuf put_buf; + CURL *curl; +} check_curl_global_state; + +check_curl_global_state global_state = { + .curl_global_initialized = false, + .curl_easy_initialized = false, + .body_buf_initialized = false, + .body_buf = {}, + .header_buf_initialized = false, + .header_buf = {}, + .status_line_initialized = false, + .status_line = {}, + .put_buf_initialized = false, + .put_buf = {}, + .curl = NULL, +}; + +static long httpReturnCode; static char errbuf[MAX_INPUT_BUFFER]; static char msg[DEFAULT_BUFFER_SIZE]; typedef union { @@ -143,8 +159,6 @@ static bool add_sslctx_verify_fun = false; static X509 *cert = NULL; #endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */ -static curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN; - typedef struct { int errorcode; check_curl_config config; @@ -152,10 +166,16 @@ typedef struct { static check_curl_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/); static void handle_curl_option_return_code(CURLcode res, const char *option); -static mp_state_enum check_http(check_curl_config /*config*/, int redir_depth); +static mp_state_enum check_http(check_curl_config /*config*/, check_curl_working_state workingState, + int redir_depth, struct curl_slist *header_list); -static void redir(curlhelp_write_curlbuf * /*header_buf*/, check_curl_config /*config*/, - int redir_depth); +typedef struct { + int redir_depth; + check_curl_working_state working_state; + int error_code; +} redir_wrapper; +static redir_wrapper redir(curlhelp_write_curlbuf * /*header_buf*/, check_curl_config /*config*/, + int redir_depth, check_curl_working_state working_state); static char *perfd_time(double elapsed_time, thresholds * /*thlds*/, long /*socket_timeout*/); static char *perfd_time_connect(double elapsed_time_connect, long /*socket_timeout*/); @@ -218,14 +238,21 @@ int main(int argc, char **argv) { } if (config.display_html) { - printf("", config.use_ssl ? "https" : "http", - config.host_name ? config.host_name : config.server_address, - config.virtual_port ? config.virtual_port : config.server_port, config.server_url); + printf("", + config.initial_config.use_ssl ? "https" : "http", + config.initial_config.host_name ? config.initial_config.host_name + : config.initial_config.server_address, + config.initial_config.virtualPort ? config.initial_config.virtualPort + : config.initial_config.serverPort, + config.initial_config.server_url); } int redir_depth = 0; - exit((int)check_http(config, redir_depth)); + check_curl_working_state working_state = config.initial_config; + struct curl_slist *header_list = NULL; + + exit((int)check_http(config, working_state, redir_depth, header_list)); } #ifdef HAVE_SSL @@ -243,13 +270,11 @@ int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) { # endif if (verbose >= 2) { puts("* SSL verify callback with certificate:"); - X509_NAME *subject; - X509_NAME *issuer; printf("* issuer:\n"); - issuer = X509_get_issuer_name(cert); + X509_NAME *issuer = X509_get_issuer_name(cert); X509_NAME_print_ex_fp(stdout, issuer, 5, XN_FLAG_MULTILINE); printf("* curl verify_callback:\n* subject:\n"); - subject = X509_get_subject_name(cert); + X509_NAME *subject = X509_get_subject_name(cert); X509_NAME_print_ex_fp(stdout, subject, 5, XN_FLAG_MULTILINE); puts(""); } @@ -305,9 +330,8 @@ static bool expected_statuscode(const char *reply, const char *statuscodes) { die(STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n")); } - char *code; bool result = false; - for (code = strtok(expected, ","); code != NULL; code = strtok(NULL, ",")) { + for (char *code = strtok(expected, ","); code != NULL; code = strtok(NULL, ",")) { if (strstr(reply, code) != NULL) { result = true; break; @@ -328,11 +352,11 @@ void handle_curl_option_return_code(CURLcode res, const char *option) { } int lookup_host(const char *host, char *buf, size_t buflen, sa_family_t addr_family) { - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = addr_family; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags |= AI_CANONNAME; + struct addrinfo hints = { + .ai_family = addr_family, + .ai_socktype = SOCK_STREAM, + .ai_flags = AI_CANONNAME, + }; struct addrinfo *result; int errcode = getaddrinfo(host, NULL, &hints, &result); @@ -383,103 +407,115 @@ int lookup_host(const char *host, char *buf, size_t buflen, sa_family_t addr_fam } static void cleanup(void) { - if (status_line_initialized) { - curlhelp_free_statusline(&status_line); + if (global_state.status_line_initialized) { + curlhelp_free_statusline(&global_state.status_line); } - status_line_initialized = false; - if (curl_easy_initialized) { - curl_easy_cleanup(curl); + global_state.status_line_initialized = false; + + if (global_state.curl_easy_initialized) { + curl_easy_cleanup(global_state.curl); } - curl_easy_initialized = false; - if (curl_global_initialized) { + global_state.curl_easy_initialized = false; + + if (global_state.curl_global_initialized) { curl_global_cleanup(); } - curl_global_initialized = false; - if (body_buf_initialized) { - curlhelp_freewritebuffer(&body_buf); + global_state.curl_global_initialized = false; + + if (global_state.body_buf_initialized) { + curlhelp_freewritebuffer(&global_state.body_buf); } - body_buf_initialized = false; - if (header_buf_initialized) { - curlhelp_freewritebuffer(&header_buf); + global_state.body_buf_initialized = false; + + if (global_state.header_buf_initialized) { + curlhelp_freewritebuffer(&global_state.header_buf); } - header_buf_initialized = false; - if (put_buf_initialized) { - curlhelp_freereadbuffer(&put_buf); + global_state.header_buf_initialized = false; + + if (global_state.put_buf_initialized) { + curlhelp_freereadbuffer(&global_state.put_buf); } - put_buf_initialized = false; + global_state.put_buf_initialized = false; } -mp_state_enum check_http(check_curl_config config, int redir_depth) { +mp_state_enum check_http(const check_curl_config config, check_curl_working_state workingState, + int redir_depth, struct curl_slist *header_list) { /* initialize curl */ if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK) { die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n"); } - curl_global_initialized = true; + global_state.curl_global_initialized = true; - if ((curl = curl_easy_init()) == NULL) { + if ((global_state.curl = curl_easy_init()) == NULL) { die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_easy_init failed\n"); } - curl_easy_initialized = true; + global_state.curl_easy_initialized = true; /* register cleanup function to shut down libcurl properly */ atexit(cleanup); if (verbose >= 1) { - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_VERBOSE, 1), + handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_VERBOSE, 1), "CURLOPT_VERBOSE"); } /* print everything on stdout like check_http would do */ - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_STDERR, stdout), + handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_STDERR, stdout), "CURLOPT_STDERR"); if (config.automatic_decompression) { #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""), - "CURLOPT_ACCEPT_ENCODING"); + handle_curl_option_return_code( + curl_easy_setopt(global_state.curl, CURLOPT_ACCEPT_ENCODING, ""), + "CURLOPT_ACCEPT_ENCODING"); #else - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_ENCODING, ""), + handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_ENCODING, ""), "CURLOPT_ENCODING"); #endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) */ } /* initialize buffer for body of the answer */ - if (curlhelp_initwritebuffer(&body_buf) < 0) { + if (curlhelp_initwritebuffer(&global_state.body_buf) < 0) { die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n"); } - body_buf_initialized = true; + global_state.body_buf_initialized = true; handle_curl_option_return_code( - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlhelp_buffer_write_callback), + curl_easy_setopt(global_state.curl, CURLOPT_WRITEFUNCTION, curlhelp_buffer_write_callback), "CURLOPT_WRITEFUNCTION"); - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&body_buf), - "CURLOPT_WRITEDATA"); + handle_curl_option_return_code( + curl_easy_setopt(global_state.curl, CURLOPT_WRITEDATA, (void *)&global_state.body_buf), + "CURLOPT_WRITEDATA"); /* initialize buffer for header of the answer */ - if (curlhelp_initwritebuffer(&header_buf) < 0) { + if (curlhelp_initwritebuffer(&global_state.header_buf) < 0) { die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n"); } - header_buf_initialized = true; + global_state.header_buf_initialized = true; + handle_curl_option_return_code( - curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curlhelp_buffer_write_callback), + curl_easy_setopt(global_state.curl, CURLOPT_HEADERFUNCTION, curlhelp_buffer_write_callback), "CURLOPT_HEADERFUNCTION"); - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_WRITEHEADER, (void *)&header_buf), - "CURLOPT_WRITEHEADER"); + handle_curl_option_return_code( + curl_easy_setopt(global_state.curl, CURLOPT_WRITEHEADER, (void *)&global_state.header_buf), + "CURLOPT_WRITEHEADER"); /* set the error buffer */ - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf), + handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_ERRORBUFFER, errbuf), "CURLOPT_ERRORBUFFER"); /* set timeouts */ handle_curl_option_return_code( - curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, config.socket_timeout), + curl_easy_setopt(global_state.curl, CURLOPT_CONNECTTIMEOUT, config.socket_timeout), "CURLOPT_CONNECTTIMEOUT"); - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_TIMEOUT, config.socket_timeout), - "CURLOPT_TIMEOUT"); + handle_curl_option_return_code( + curl_easy_setopt(global_state.curl, CURLOPT_TIMEOUT, config.socket_timeout), + "CURLOPT_TIMEOUT"); /* enable haproxy protocol */ if (config.haproxy_protocol) { - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HAPROXYPROTOCOL, 1L), - "CURLOPT_HAPROXYPROTOCOL"); + handle_curl_option_return_code( + curl_easy_setopt(global_state.curl, CURLOPT_HAPROXYPROTOCOL, 1L), + "CURLOPT_HAPROXYPROTOCOL"); } // fill dns resolve cache to make curl connect to the given server_address instead of the @@ -487,19 +523,19 @@ mp_state_enum check_http(check_curl_config config, int redir_depth) { struct curl_slist *host = NULL; char dnscache[DEFAULT_BUFFER_SIZE]; char addrstr[DEFAULT_BUFFER_SIZE / 2]; - if (config.use_ssl && config.host_name != NULL) { + if (workingState.use_ssl && workingState.host_name != NULL) { int res; - if ((res = lookup_host(config.server_address, addrstr, DEFAULT_BUFFER_SIZE / 2, + if ((res = lookup_host(workingState.server_address, addrstr, DEFAULT_BUFFER_SIZE / 2, config.sin_family)) != 0) { snprintf(msg, DEFAULT_BUFFER_SIZE, _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"), - config.server_address, res, gai_strerror(res)); + workingState.server_address, res, gai_strerror(res)); die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); } - snprintf(dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", config.host_name, config.server_port, - addrstr); + snprintf(dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", workingState.host_name, + workingState.serverPort, addrstr); host = curl_slist_append(NULL, dnscache); - curl_easy_setopt(curl, CURLOPT_RESOLVE, host); + curl_easy_setopt(global_state.curl, CURLOPT_RESOLVE, host); if (verbose >= 1) { printf("* curl CURLOPT_RESOLVE: %s\n", dnscache); } @@ -507,66 +543,73 @@ mp_state_enum check_http(check_curl_config config, int redir_depth) { // If server_address is an IPv6 address it must be surround by square brackets struct in6_addr tmp_in_addr; - if (inet_pton(AF_INET6, config.server_address, &tmp_in_addr) == 1) { - char *new_server_address = malloc(strlen(config.server_address) + 3); + if (inet_pton(AF_INET6, workingState.server_address, &tmp_in_addr) == 1) { + char *new_server_address = malloc(strlen(workingState.server_address) + 3); if (new_server_address == NULL) { die(STATE_UNKNOWN, "HTTP UNKNOWN - Unable to allocate memory\n"); } - snprintf(new_server_address, strlen(config.server_address) + 3, "[%s]", - config.server_address); - free(config.server_address); - config.server_address = new_server_address; + snprintf(new_server_address, strlen(workingState.server_address) + 3, "[%s]", + workingState.server_address); + free(workingState.server_address); + workingState.server_address = new_server_address; } /* compose URL: use the address we want to connect to, set Host: header later */ char url[DEFAULT_BUFFER_SIZE]; - snprintf(url, DEFAULT_BUFFER_SIZE, "%s://%s:%d%s", config.use_ssl ? "https" : "http", - (config.use_ssl & (config.host_name != NULL)) ? config.host_name - : config.server_address, - config.server_port, config.server_url); + snprintf(url, DEFAULT_BUFFER_SIZE, "%s://%s:%d%s", workingState.use_ssl ? "https" : "http", + (workingState.use_ssl & (workingState.host_name != NULL)) + ? workingState.host_name + : workingState.server_address, + workingState.serverPort, workingState.server_url); if (verbose >= 1) { printf("* curl CURLOPT_URL: %s\n", url); } - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_URL, url), "CURLOPT_URL"); + handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_URL, url), + "CURLOPT_URL"); /* extract proxy information for legacy proxy https requests */ - if (!strcmp(config.http_method, "CONNECT") || - strstr(config.server_url, "http") == config.server_url) { - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_PROXY, config.server_address), - "CURLOPT_PROXY"); + if (!strcmp(workingState.http_method, "CONNECT") || + strstr(workingState.server_url, "http") == workingState.server_url) { + handle_curl_option_return_code( + curl_easy_setopt(global_state.curl, CURLOPT_PROXY, workingState.server_address), + "CURLOPT_PROXY"); handle_curl_option_return_code( - curl_easy_setopt(curl, CURLOPT_PROXYPORT, (long)config.server_port), + curl_easy_setopt(global_state.curl, CURLOPT_PROXYPORT, (long)workingState.serverPort), "CURLOPT_PROXYPORT"); if (verbose >= 2) { - printf("* curl CURLOPT_PROXY: %s:%d\n", config.server_address, config.server_port); + printf("* curl CURLOPT_PROXY: %s:%d\n", workingState.server_address, + workingState.serverPort); } - config.http_method = "GET"; - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_URL, config.server_url), - "CURLOPT_URL"); + workingState.http_method = "GET"; + handle_curl_option_return_code( + curl_easy_setopt(global_state.curl, CURLOPT_URL, workingState.server_url), + "CURLOPT_URL"); } /* disable body for HEAD request */ - if (config.http_method && !strcmp(config.http_method, "HEAD")) { - config.no_body = true; + if (workingState.http_method && !strcmp(workingState.http_method, "HEAD")) { + workingState.no_body = true; } /* set HTTP protocol version */ handle_curl_option_return_code( - curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, config.curl_http_version), + curl_easy_setopt(global_state.curl, CURLOPT_HTTP_VERSION, config.curl_http_version), "CURLOPT_HTTP_VERSION"); /* set HTTP method */ - if (config.http_method) { - if (!strcmp(config.http_method, "POST")) { - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_POST, 1), "CURLOPT_POST"); - } else if (!strcmp(config.http_method, "PUT")) { - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_UPLOAD, 1), + if (workingState.http_method) { + if (!strcmp(workingState.http_method, "POST")) { + handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_POST, 1), + "CURLOPT_POST"); + } else if (!strcmp(workingState.http_method, "PUT")) { + handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_UPLOAD, 1), "CURLOPT_UPLOAD"); } else { - handle_curl_option_return_code( - curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, config.http_method), - "CURLOPT_CUSTOMREQUEST"); + handle_curl_option_return_code(curl_easy_setopt(global_state.curl, + CURLOPT_CUSTOMREQUEST, + workingState.http_method), + "CURLOPT_CUSTOMREQUEST"); } } @@ -583,13 +626,13 @@ mp_state_enum check_http(check_curl_config config, int redir_depth) { /* set hostname (virtual hosts), not needed if CURLOPT_CONNECT_TO is used, but left in * anyway */ char http_header[DEFAULT_BUFFER_SIZE]; - if (config.host_name != NULL && force_host_header == NULL) { - if ((config.virtual_port != HTTP_PORT && !config.use_ssl) || - (config.virtual_port != HTTPS_PORT && config.use_ssl)) { - snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s:%d", config.host_name, - config.virtual_port); + if (workingState.host_name != NULL && force_host_header == NULL) { + if ((workingState.virtualPort != HTTP_PORT && !workingState.use_ssl) || + (workingState.virtualPort != HTTPS_PORT && workingState.use_ssl)) { + snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s:%d", workingState.host_name, + workingState.virtualPort); } else { - snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s", config.host_name); + snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s", workingState.host_name); } header_list = curl_slist_append(header_list, http_header); } @@ -604,57 +647,63 @@ mp_state_enum check_http(check_curl_config config, int redir_depth) { for (size_t i = 0; i < config.http_opt_headers_count; i++) { header_list = curl_slist_append(header_list, config.http_opt_headers[i]); } - /* This cannot be free'd here because a redirection will then try to access this and - * segfault */ - /* Covered in a testcase in tests/check_http.t */ - /* free(http_opt_headers); */ } /* set HTTP headers */ - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list), - "CURLOPT_HTTPHEADER"); + handle_curl_option_return_code( + curl_easy_setopt(global_state.curl, CURLOPT_HTTPHEADER, header_list), "CURLOPT_HTTPHEADER"); #ifdef LIBCURL_FEATURE_SSL /* set SSL version, warn about insecure or unsupported versions */ - if (config.use_ssl) { + if (workingState.use_ssl) { handle_curl_option_return_code( - curl_easy_setopt(curl, CURLOPT_SSLVERSION, config.ssl_version), "CURLOPT_SSLVERSION"); + curl_easy_setopt(global_state.curl, CURLOPT_SSLVERSION, config.ssl_version), + "CURLOPT_SSLVERSION"); } /* client certificate and key to present to server (SSL) */ if (config.client_cert) { - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSLCERT, config.client_cert), - "CURLOPT_SSLCERT"); + handle_curl_option_return_code( + curl_easy_setopt(global_state.curl, CURLOPT_SSLCERT, config.client_cert), + "CURLOPT_SSLCERT"); } + if (config.client_privkey) { handle_curl_option_return_code( - curl_easy_setopt(curl, CURLOPT_SSLKEY, config.client_privkey), "CURLOPT_SSLKEY"); + curl_easy_setopt(global_state.curl, CURLOPT_SSLKEY, config.client_privkey), + "CURLOPT_SSLKEY"); } + if (config.ca_cert) { - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CAINFO, config.ca_cert), - "CURLOPT_CAINFO"); + handle_curl_option_return_code( + curl_easy_setopt(global_state.curl, CURLOPT_CAINFO, config.ca_cert), "CURLOPT_CAINFO"); } + if (config.ca_cert || config.verify_peer_and_host) { /* per default if we have a CA verify both the peer and the * hostname in the certificate, can be switched off later */ - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1), - "CURLOPT_SSL_VERIFYPEER"); - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2), - "CURLOPT_SSL_VERIFYHOST"); + handle_curl_option_return_code( + curl_easy_setopt(global_state.curl, CURLOPT_SSL_VERIFYPEER, 1), + "CURLOPT_SSL_VERIFYPEER"); + handle_curl_option_return_code( + curl_easy_setopt(global_state.curl, CURLOPT_SSL_VERIFYHOST, 2), + "CURLOPT_SSL_VERIFYHOST"); } else { /* backward-compatible behaviour, be tolerant in checks * TODO: depending on more options have aspects we want * to be less tolerant about ssl verfications */ - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0), - "CURLOPT_SSL_VERIFYPEER"); - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0), - "CURLOPT_SSL_VERIFYHOST"); + handle_curl_option_return_code( + curl_easy_setopt(global_state.curl, CURLOPT_SSL_VERIFYPEER, 0), + "CURLOPT_SSL_VERIFYPEER"); + handle_curl_option_return_code( + curl_easy_setopt(global_state.curl, CURLOPT_SSL_VERIFYHOST, 0), + "CURLOPT_SSL_VERIFYHOST"); } /* detect SSL library used by libcurl */ - ssl_library = curlhelp_get_ssl_library(); + curlhelp_ssl_library ssl_library = curlhelp_get_ssl_library(); /* try hard to get a stack of certificates to verify against */ if (config.check_cert) { @@ -672,15 +721,15 @@ mp_state_enum check_http(check_curl_config config, int redir_depth) { # endif /* USE_OPENSSL */ /* libcurl is built with OpenSSL, monitoring plugins, so falling * back to manually extracting certificate information */ - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L), - "CURLOPT_CERTINFO"); + handle_curl_option_return_code( + curl_easy_setopt(global_state.curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO"); break; case CURLHELP_SSL_LIBRARY_NSS: # if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) /* NSS: support for CERTINFO is implemented since 7.34.0 */ - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L), - "CURLOPT_CERTINFO"); + handle_curl_option_return_code( + curl_easy_setopt(global_state.curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO"); # else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library " @@ -692,8 +741,8 @@ mp_state_enum check_http(check_curl_config config, int redir_depth) { case CURLHELP_SSL_LIBRARY_GNUTLS: # if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) /* GnuTLS: support for CERTINFO is implemented since 7.42.0 */ - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L), - "CURLOPT_CERTINFO"); + handle_curl_option_return_code( + curl_easy_setopt(global_state.curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO"); # else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */ die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library " @@ -726,29 +775,33 @@ mp_state_enum check_http(check_curl_config config, int redir_depth) { # if LIBCURL_VERSION_NUM >= \ MAKE_LIBCURL_VERSION(7, 10, 6) /* required for CURLOPT_SSL_CTX_FUNCTION */ // ssl ctx function is not available with all ssl backends - if (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, NULL) != CURLE_UNKNOWN_OPTION) { - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), - "CURLOPT_SSL_CTX_FUNCTION"); + if (curl_easy_setopt(global_state.curl, CURLOPT_SSL_CTX_FUNCTION, NULL) != + CURLE_UNKNOWN_OPTION) { + handle_curl_option_return_code( + curl_easy_setopt(global_state.curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), + "CURLOPT_SSL_CTX_FUNCTION"); } # endif #endif /* LIBCURL_FEATURE_SSL */ /* set default or user-given user agent identification */ - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_USERAGENT, config.user_agent), - "CURLOPT_USERAGENT"); + handle_curl_option_return_code( + curl_easy_setopt(global_state.curl, CURLOPT_USERAGENT, config.user_agent), + "CURLOPT_USERAGENT"); /* proxy-authentication */ if (strcmp(config.proxy_auth, "")) { handle_curl_option_return_code( - curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, config.proxy_auth), + curl_easy_setopt(global_state.curl, CURLOPT_PROXYUSERPWD, config.proxy_auth), "CURLOPT_PROXYUSERPWD"); } /* authentication */ if (strcmp(config.user_auth, "")) { - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_USERPWD, config.user_auth), - "CURLOPT_USERPWD"); + handle_curl_option_return_code( + curl_easy_setopt(global_state.curl, CURLOPT_USERPWD, config.user_auth), + "CURLOPT_USERPWD"); } /* TODO: parameter auth method, bitfield of following methods: @@ -770,25 +823,27 @@ mp_state_enum check_http(check_curl_config config, int redir_depth) { /* handle redirections */ if (config.onredirect == STATE_DEPENDENT) { if (config.followmethod == FOLLOW_LIBCURL) { - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1), - "CURLOPT_FOLLOWLOCATION"); + handle_curl_option_return_code( + curl_easy_setopt(global_state.curl, CURLOPT_FOLLOWLOCATION, 1), + "CURLOPT_FOLLOWLOCATION"); /* default -1 is infinite, not good, could lead to zombie plugins! Setting it to one bigger than maximal limit to handle errors nicely below */ handle_curl_option_return_code( - curl_easy_setopt(curl, CURLOPT_MAXREDIRS, config.max_depth + 1), + curl_easy_setopt(global_state.curl, CURLOPT_MAXREDIRS, config.max_depth + 1), "CURLOPT_MAXREDIRS"); /* for now allow only http and https (we are a http(s) check plugin in the end) */ #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 85, 0) handle_curl_option_return_code( - curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https"), + curl_easy_setopt(global_state.curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https"), "CURLOPT_REDIR_PROTOCOLS_STR"); #elif LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 4) - handle_curl_option_return_code( - curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS), - "CURLOPT_REDIRECT_PROTOCOLS"); + handle_curl_option_return_code(curl_easy_setopt(global_state.curl, + CURLOPT_REDIR_PROTOCOLS, + CURLPROTO_HTTP | CURLPROTO_HTTPS), + "CURLOPT_REDIRECT_PROTOCOLS"); #endif /* TODO: handle the following aspects of redirection, make them @@ -805,28 +860,31 @@ mp_state_enum check_http(check_curl_config config, int redir_depth) { } /* no-body */ - if (config.no_body) { - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_NOBODY, 1), "CURLOPT_NOBODY"); + if (workingState.no_body) { + handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_NOBODY, 1), + "CURLOPT_NOBODY"); } /* IPv4 or IPv6 forced DNS resolution */ if (config.sin_family == AF_UNSPEC) { handle_curl_option_return_code( - curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER), + curl_easy_setopt(global_state.curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_WHATEVER)"); } else if (config.sin_family == AF_INET) { - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4), - "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V4)"); + handle_curl_option_return_code( + curl_easy_setopt(global_state.curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4), + "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V4)"); } #if defined(USE_IPV6) && defined(LIBCURL_FEATURE_IPV6) else if (config.sin_family == AF_INET6) { - handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6), - "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V6)"); + handle_curl_option_return_code( + curl_easy_setopt(global_state.curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6), + "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V6)"); } #endif /* either send http POST data (any data, not only POST)*/ - if (!strcmp(config.http_method, "POST") || !strcmp(config.http_method, "PUT")) { + if (!strcmp(workingState.http_method, "POST") || !strcmp(workingState.http_method, "PUT")) { /* set content of payload for POST and PUT */ if (config.http_content_type) { snprintf(http_header, DEFAULT_BUFFER_SIZE, "Content-Type: %s", @@ -835,30 +893,32 @@ mp_state_enum check_http(check_curl_config config, int redir_depth) { } /* NULL indicates "HTTP Continue" in libcurl, provide an empty string * in case of no POST/PUT data */ - if (!config.http_post_data) { - config.http_post_data = ""; + if (!workingState.http_post_data) { + workingState.http_post_data = ""; } - if (!strcmp(config.http_method, "POST")) { + if (!strcmp(workingState.http_method, "POST")) { /* POST method, set payload with CURLOPT_POSTFIELDS */ + handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_POSTFIELDS, + workingState.http_post_data), + "CURLOPT_POSTFIELDS"); + } else if (!strcmp(workingState.http_method, "PUT")) { handle_curl_option_return_code( - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, config.http_post_data), - "CURLOPT_POSTFIELDS"); - } else if (!strcmp(config.http_method, "PUT")) { - handle_curl_option_return_code( - curl_easy_setopt(curl, CURLOPT_READFUNCTION, + curl_easy_setopt(global_state.curl, CURLOPT_READFUNCTION, (curl_read_callback)curlhelp_buffer_read_callback), "CURLOPT_READFUNCTION"); - if (curlhelp_initreadbuffer(&put_buf, config.http_post_data, - strlen(config.http_post_data)) < 0) { + if (curlhelp_initreadbuffer(&global_state.put_buf, workingState.http_post_data, + strlen(workingState.http_post_data)) < 0) { die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating read buffer for PUT\n"); } - put_buf_initialized = true; - handle_curl_option_return_code( - curl_easy_setopt(curl, CURLOPT_READDATA, (void *)&put_buf), "CURLOPT_READDATA"); + global_state.put_buf_initialized = true; + + handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_READDATA, + (void *)&global_state.put_buf), + "CURLOPT_READDATA"); handle_curl_option_return_code( - curl_easy_setopt(curl, CURLOPT_INFILESIZE, - (curl_off_t)strlen(config.http_post_data)), + curl_easy_setopt(global_state.curl, CURLOPT_INFILESIZE, + (curl_off_t)strlen(workingState.http_post_data)), "CURLOPT_INFILESIZE"); } } @@ -868,22 +928,22 @@ mp_state_enum check_http(check_curl_config config, int redir_depth) { /* enable reading cookies from a file, and if the filename is an empty string, only * enable the curl cookie engine */ handle_curl_option_return_code( - curl_easy_setopt(curl, CURLOPT_COOKIEFILE, config.cookie_jar_file), + curl_easy_setopt(global_state.curl, CURLOPT_COOKIEFILE, config.cookie_jar_file), "CURLOPT_COOKIEFILE"); /* now enable saving cookies to a file, but only if the filename is not an empty string, * since writing it would fail */ if (*config.cookie_jar_file) { handle_curl_option_return_code( - curl_easy_setopt(curl, CURLOPT_COOKIEJAR, config.cookie_jar_file), + curl_easy_setopt(global_state.curl, CURLOPT_COOKIEJAR, config.cookie_jar_file), "CURLOPT_COOKIEJAR"); } } /* do the request */ - CURLcode res = curl_easy_perform(curl); + CURLcode res = curl_easy_perform(global_state.curl); - if (verbose >= 2 && config.http_post_data) { - printf("**** REQUEST CONTENT ****\n%s\n", config.http_post_data); + if (verbose >= 2 && workingState.http_post_data) { + printf("**** REQUEST CONTENT ****\n%s\n", workingState.http_post_data); } /* free header and server IP resolve lists, we don't need it anymore */ @@ -899,14 +959,14 @@ mp_state_enum check_http(check_curl_config config, int redir_depth) { if (res != CURLE_OK) { snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host on port %d: cURL returned %d - %s"), - config.server_port, res, errbuf[0] ? errbuf : curl_easy_strerror(res)); + workingState.serverPort, res, errbuf[0] ? errbuf : curl_easy_strerror(res)); die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); } mp_state_enum result_ssl = STATE_OK; /* certificate checks */ #ifdef LIBCURL_FEATURE_SSL - if (config.use_ssl) { + if (workingState.use_ssl) { if (config.check_cert) { if (is_openssl_callback) { # ifdef USE_OPENSSL @@ -927,7 +987,7 @@ mp_state_enum check_http(check_curl_config config, int redir_depth) { cert_ptr_union cert_ptr = {0}; cert_ptr.to_info = NULL; - res = curl_easy_getinfo(curl, CURLINFO_CERTINFO, &cert_ptr.to_info); + res = curl_easy_getinfo(global_state.curl, CURLINFO_CERTINFO, &cert_ptr.to_info); if (!res && cert_ptr.to_info) { # ifdef USE_OPENSSL /* We have no OpenSSL in libcurl, but we can use OpenSSL for X509 cert @@ -994,32 +1054,37 @@ mp_state_enum check_http(check_curl_config config, int redir_depth) { * performance data to the answer always */ double total_time; - handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time), - "CURLINFO_TOTAL_TIME"); - size_t page_len = get_content_length(&header_buf, &body_buf); + handle_curl_option_return_code( + curl_easy_getinfo(global_state.curl, CURLINFO_TOTAL_TIME, &total_time), + "CURLINFO_TOTAL_TIME"); + size_t page_len = get_content_length(&global_state.header_buf, &global_state.body_buf); char perfstring[DEFAULT_BUFFER_SIZE]; if (config.show_extended_perfdata) { double time_connect; handle_curl_option_return_code( - curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &time_connect), "CURLINFO_CONNECT_TIME"); + curl_easy_getinfo(global_state.curl, CURLINFO_CONNECT_TIME, &time_connect), + "CURLINFO_CONNECT_TIME"); + double time_appconnect; handle_curl_option_return_code( - curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME, &time_appconnect), + curl_easy_getinfo(global_state.curl, CURLINFO_APPCONNECT_TIME, &time_appconnect), "CURLINFO_APPCONNECT_TIME"); + double time_headers; handle_curl_option_return_code( - curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME, &time_headers), + curl_easy_getinfo(global_state.curl, CURLINFO_PRETRANSFER_TIME, &time_headers), "CURLINFO_PRETRANSFER_TIME"); + double time_firstbyte; handle_curl_option_return_code( - curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME, &time_firstbyte), + curl_easy_getinfo(global_state.curl, CURLINFO_STARTTRANSFER_TIME, &time_firstbyte), "CURLINFO_STARTTRANSFER_TIME"); snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s %s %s %s %s %s", perfd_time(total_time, config.thlds, config.socket_timeout), perfd_size(page_len, config.min_page_len), perfd_time_connect(time_connect, config.socket_timeout), - config.use_ssl + workingState.use_ssl ? perfd_time_ssl(time_appconnect - time_connect, config.socket_timeout) : "", perfd_time_headers(time_headers - time_appconnect, config.socket_timeout), @@ -1032,46 +1097,47 @@ mp_state_enum check_http(check_curl_config config, int redir_depth) { } /* return a CRITICAL status if we couldn't read any data */ - if (strlen(header_buf.buf) == 0 && strlen(body_buf.buf) == 0) { + if (strlen(global_state.header_buf.buf) == 0 && strlen(global_state.body_buf.buf) == 0) { die(STATE_CRITICAL, _("HTTP CRITICAL - No header received from host\n")); } /* get status line of answer, check sanity of HTTP code */ - if (curlhelp_parse_statusline(header_buf.buf, &status_line) < 0) { + if (curlhelp_parse_statusline(global_state.header_buf.buf, &global_state.status_line) < 0) { snprintf(msg, DEFAULT_BUFFER_SIZE, "Unparsable status line in %.3g seconds response time|%s\n", total_time, perfstring); /* we cannot know the major/minor version here for sure as we cannot parse the first * line */ - die(STATE_CRITICAL, "HTTP CRITICAL HTTP/x.x %ld unknown - %s", code, msg); + die(STATE_CRITICAL, "HTTP CRITICAL HTTP/x.x %ld unknown - %s", httpReturnCode, msg); } - status_line_initialized = true; + global_state.status_line_initialized = true; /* get result code from cURL */ - handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code), - "CURLINFO_RESPONSE_CODE"); + handle_curl_option_return_code( + curl_easy_getinfo(global_state.curl, CURLINFO_RESPONSE_CODE, &httpReturnCode), + "CURLINFO_RESPONSE_CODE"); if (verbose >= 2) { - printf("* curl CURLINFO_RESPONSE_CODE is %ld\n", code); + printf("* curl CURLINFO_RESPONSE_CODE is %ld\n", httpReturnCode); } /* print status line, header, body if verbose */ if (verbose >= 2) { - printf("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header_buf.buf, - (config.no_body ? " [[ skipped ]]" : body_buf.buf)); + printf("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", global_state.header_buf.buf, + (workingState.no_body ? " [[ skipped ]]" : global_state.body_buf.buf)); } /* make sure the status line matches the response we are looking for */ - if (!expected_statuscode(status_line.first_line, config.server_expect)) { - if (config.server_port == HTTP_PORT) { + if (!expected_statuscode(global_state.status_line.first_line, config.server_expect)) { + if (workingState.serverPort == HTTP_PORT) { snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host: %s\n"), - status_line.first_line); + global_state.status_line.first_line); } else { snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host on port %d: %s\n"), - config.server_port, status_line.first_line); + workingState.serverPort, global_state.status_line.first_line); } die(STATE_CRITICAL, "HTTP CRITICAL - %s%s%s", msg, config.show_body ? "\n" : "", - config.show_body ? body_buf.buf : ""); + config.show_body ? global_state.body_buf.buf : ""); } mp_state_enum result = STATE_OK; @@ -1084,26 +1150,29 @@ mp_state_enum check_http(check_curl_config config, int redir_depth) { result = STATE_OK; } else { /* illegal return codes result in a critical state */ - if (code >= 600 || code < 100) { + if (httpReturnCode >= 600 || httpReturnCode < 100) { die(STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%d, %.40s)\n"), - status_line.http_code, status_line.msg); + global_state.status_line.http_code, global_state.status_line.msg); /* server errors result in a critical state */ - } else if (code >= 500) { + } else if (httpReturnCode >= 500) { result = STATE_CRITICAL; /* client errors result in a warning state */ - } else if (code >= 400) { + } else if (httpReturnCode >= 400) { result = STATE_WARNING; /* check redirected page if specified */ - } else if (code >= 300) { + } else if (httpReturnCode >= 300) { if (config.onredirect == STATE_DEPENDENT) { if (config.followmethod == FOLLOW_LIBCURL) { - code = status_line.http_code; + httpReturnCode = global_state.status_line.http_code; } else { /* old check_http style redirection, if we come * back here, we are in the same status as with * the libcurl method */ - redir(&header_buf, config, redir_depth); + redir_wrapper redir_result = + redir(&global_state.header_buf, config, redir_depth, workingState); + check_http(config, redir_result.working_state, redir_result.redir_depth, + header_list); } } else { /* this is a specific code in the command line to @@ -1120,7 +1189,7 @@ mp_state_enum check_http(check_curl_config config, int redir_depth) { /* libcurl redirection internally, handle error states here */ if (config.followmethod == FOLLOW_LIBCURL) { handle_curl_option_return_code( - curl_easy_getinfo(curl, CURLINFO_REDIRECT_COUNT, &redir_depth), + curl_easy_getinfo(global_state.curl, CURLINFO_REDIRECT_COUNT, &redir_depth), "CURLINFO_REDIRECT_COUNT"); if (verbose >= 2) { printf(_("* curl LIBINFO_REDIRECT_COUNT is %d\n"), redir_depth); @@ -1133,20 +1202,22 @@ mp_state_enum check_http(check_curl_config config, int redir_depth) { } /* check status codes, set exit status accordingly */ - if (status_line.http_code != code) { + if (global_state.status_line.http_code != httpReturnCode) { die(STATE_CRITICAL, _("HTTP CRITICAL %s %d %s - different HTTP codes (cUrl has %ld)\n"), - string_statuscode(status_line.http_major, status_line.http_minor), - status_line.http_code, status_line.msg, code); + string_statuscode(global_state.status_line.http_major, + global_state.status_line.http_minor), + global_state.status_line.http_code, global_state.status_line.msg, httpReturnCode); } if (config.maximum_age >= 0) { - result = max_state_alt(check_document_dates(&header_buf, &msg, config.maximum_age), result); + result = max_state_alt( + check_document_dates(&global_state.header_buf, &msg, config.maximum_age), result); } /* Page and Header content checks go here */ if (strlen(config.header_expect)) { - if (!strstr(header_buf.buf, config.header_expect)) { + if (!strstr(global_state.header_buf.buf, config.header_expect)) { char output_header_search[30] = ""; strncpy(&output_header_search[0], config.header_expect, sizeof(output_header_search)); @@ -1158,9 +1229,9 @@ mp_state_enum check_http(check_curl_config config, int redir_depth) { char tmp[DEFAULT_BUFFER_SIZE]; snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sheader '%s' not found on '%s://%s:%d%s', "), - msg, output_header_search, config.use_ssl ? "https" : "http", - config.host_name ? config.host_name : config.server_address, - config.server_port, config.server_url); + msg, output_header_search, workingState.use_ssl ? "https" : "http", + workingState.host_name ? workingState.host_name : workingState.server_address, + workingState.serverPort, workingState.server_url); strcpy(msg, tmp); @@ -1169,7 +1240,7 @@ mp_state_enum check_http(check_curl_config config, int redir_depth) { } if (strlen(config.string_expect)) { - if (!strstr(body_buf.buf, config.string_expect)) { + if (!strstr(global_state.body_buf.buf, config.string_expect)) { char output_string_search[30] = ""; strncpy(&output_string_search[0], config.string_expect, sizeof(output_string_search)); @@ -1181,9 +1252,9 @@ mp_state_enum check_http(check_curl_config config, int redir_depth) { char tmp[DEFAULT_BUFFER_SIZE]; snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sstring '%s' not found on '%s://%s:%d%s', "), - msg, output_string_search, config.use_ssl ? "https" : "http", - config.host_name ? config.host_name : config.server_address, - config.server_port, config.server_url); + msg, output_string_search, workingState.use_ssl ? "https" : "http", + workingState.host_name ? workingState.host_name : workingState.server_address, + workingState.serverPort, workingState.server_url); strcpy(msg, tmp); @@ -1194,7 +1265,7 @@ mp_state_enum check_http(check_curl_config config, int redir_depth) { if (strlen(config.regexp)) { regex_t preg; regmatch_t pmatch[REGS]; - int errcode = regexec(&preg, body_buf.buf, REGS, pmatch, 0); + int errcode = regexec(&preg, global_state.body_buf.buf, REGS, pmatch, 0); if ((errcode == 0 && !config.invert_regex) || (errcode == REG_NOMATCH && config.invert_regex)) { /* OK - No-op to avoid changing the logic around it */ @@ -1259,22 +1330,25 @@ mp_state_enum check_http(check_curl_config config, int redir_depth) { * msg); */ die((int)max_state_alt(result, result_ssl), "HTTP %s: %s %d %s%s%s - %zu bytes in %.3f second response time %s|%s\n%s%s", - state_text(result), string_statuscode(status_line.http_major, status_line.http_minor), - status_line.http_code, status_line.msg, strlen(msg) > 0 ? " - " : "", msg, page_len, - total_time, (config.display_html ? "" : ""), perfstring, - (config.show_body ? body_buf.buf : ""), (config.show_body ? "\n" : "")); + state_text(result), + string_statuscode(global_state.status_line.http_major, global_state.status_line.http_minor), + global_state.status_line.http_code, global_state.status_line.msg, + strlen(msg) > 0 ? " - " : "", msg, page_len, total_time, + (config.display_html ? "" : ""), perfstring, + (config.show_body ? global_state.body_buf.buf : ""), (config.show_body ? "\n" : "")); return max_state_alt(result, result_ssl); } -int uri_strcmp(const UriTextRangeA range, const char *s) { +int uri_strcmp(const UriTextRangeA range, const char *stringToCompare) { if (!range.first) { return -1; } - if ((size_t)(range.afterLast - range.first) < strlen(s)) { + if ((size_t)(range.afterLast - range.first) < strlen(stringToCompare)) { return -1; } - return strncmp(s, range.first, min((size_t)(range.afterLast - range.first), strlen(s))); + return strncmp(stringToCompare, range.first, + min((size_t)(range.afterLast - range.first), strlen(stringToCompare))); } char *uri_string(const UriTextRangeA range, char *buf, size_t buflen) { @@ -1287,8 +1361,8 @@ char *uri_string(const UriTextRangeA range, char *buf, size_t buflen) { return buf; } -void redir(curlhelp_write_curlbuf *header_buf, check_curl_config config, int redir_depth) { - +redir_wrapper redir(curlhelp_write_curlbuf *header_buf, const check_curl_config config, + int redir_depth, check_curl_working_state working_state) { curlhelp_statusline status_line; struct phr_header headers[255]; size_t msglen; @@ -1340,9 +1414,9 @@ void redir(curlhelp_write_curlbuf *header_buf, check_curl_config config, int red } if (uri.pathHead) { printf(_("** path: ")); - const UriPathSegmentA *p = uri.pathHead; - for (; p; p = p->next) { - printf("/%s", uri_string(p->text, buf, DEFAULT_BUFFER_SIZE)); + for (UriPathSegmentA *path_segment = uri.pathHead; path_segment; + path_segment = path_segment->next) { + printf("/%s", uri_string(path_segment->text, buf, DEFAULT_BUFFER_SIZE)); } puts(""); } @@ -1355,7 +1429,7 @@ void redir(curlhelp_write_curlbuf *header_buf, check_curl_config config, int red } if (uri.scheme.first) { - config.use_ssl = (bool)(!uri_strcmp(uri.scheme, "https")); + working_state.use_ssl = (bool)(!uri_strcmp(uri.scheme, "https")); } /* we do a sloppy test here only, because uriparser would have failed @@ -1366,7 +1440,7 @@ void redir(curlhelp_write_curlbuf *header_buf, check_curl_config config, int red new_port = atoi(uri_string(uri.portText, buf, DEFAULT_BUFFER_SIZE)); } else { new_port = HTTP_PORT; - if (config.use_ssl) { + if (working_state.use_ssl) { new_port = HTTPS_PORT; } } @@ -1380,9 +1454,10 @@ void redir(curlhelp_write_curlbuf *header_buf, check_curl_config config, int red */ char *new_host; if (!uri.scheme.first && !uri.hostText.first) { - new_host = strdup(config.host_name ? config.host_name : config.server_address); - new_port = config.server_port; - if (config.use_ssl) { + new_host = strdup(working_state.host_name ? working_state.host_name + : working_state.server_address); + new_port = working_state.serverPort; + if (working_state.use_ssl) { uri_string(uri.scheme, "https", DEFAULT_BUFFER_SIZE); } } else { @@ -1393,50 +1468,51 @@ void redir(curlhelp_write_curlbuf *header_buf, check_curl_config config, int red /* TODO: handle fragments and query part of URL */ char *new_url = (char *)calloc(1, DEFAULT_BUFFER_SIZE); if (uri.pathHead) { - const UriPathSegmentA *p = uri.pathHead; - for (; p; p = p->next) { + for (UriPathSegmentA *pathSegment = uri.pathHead; pathSegment; + pathSegment = pathSegment->next) { strncat(new_url, "/", DEFAULT_BUFFER_SIZE); - strncat(new_url, uri_string(p->text, buf, DEFAULT_BUFFER_SIZE), + strncat(new_url, uri_string(pathSegment->text, buf, DEFAULT_BUFFER_SIZE), DEFAULT_BUFFER_SIZE - 1); } } - if (config.server_port == new_port && - !strncmp(config.server_address, new_host, MAX_IPV4_HOSTLENGTH) && - (config.host_name && !strncmp(config.host_name, new_host, MAX_IPV4_HOSTLENGTH)) && - !strcmp(config.server_url, new_url)) { + if (working_state.serverPort == new_port && + !strncmp(working_state.server_address, new_host, MAX_IPV4_HOSTLENGTH) && + (working_state.host_name && + !strncmp(working_state.host_name, new_host, MAX_IPV4_HOSTLENGTH)) && + !strcmp(working_state.server_url, new_url)) { die(STATE_CRITICAL, _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"), - config.use_ssl ? "https" : "http", new_host, new_port, new_url, + working_state.use_ssl ? "https" : "http", new_host, new_port, new_url, (config.display_html ? "" : "")); } /* set new values for redirected request */ if (!(config.followsticky & STICKY_HOST)) { - free(config.server_address); - config.server_address = strndup(new_host, MAX_IPV4_HOSTLENGTH); + free(working_state.server_address); + working_state.server_address = strndup(new_host, MAX_IPV4_HOSTLENGTH); } if (!(config.followsticky & STICKY_PORT)) { - config.server_port = (unsigned short)new_port; + working_state.serverPort = (unsigned short)new_port; } - free(config.host_name); - config.host_name = strndup(new_host, MAX_IPV4_HOSTLENGTH); + free(working_state.host_name); + working_state.host_name = strndup(new_host, MAX_IPV4_HOSTLENGTH); /* reset virtual port */ - config.virtual_port = config.server_port; + working_state.virtualPort = working_state.serverPort; free(new_host); - free(config.server_url); - config.server_url = new_url; + free(working_state.server_url); + working_state.server_url = new_url; uriFreeUriMembersA(&uri); if (verbose) { - printf(_("Redirection to %s://%s:%d%s\n"), config.use_ssl ? "https" : "http", - config.host_name ? config.host_name : config.server_address, config.server_port, - config.server_url); + printf(_("Redirection to %s://%s:%d%s\n"), working_state.use_ssl ? "https" : "http", + working_state.host_name ? working_state.host_name : working_state.server_address, + working_state.serverPort, working_state.server_url); } /* TODO: the hash component MUST be taken from the original URL and @@ -1444,7 +1520,13 @@ void redir(curlhelp_write_curlbuf *header_buf, check_curl_config config, int red */ cleanup(); - check_http(config, redir_depth); + + redir_wrapper result = { + .redir_depth = redir_depth, + .working_state = working_state, + .error_code = OK, + }; + return result; } /* check whether a file exists */ @@ -1585,31 +1667,34 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { warning_thresholds = optarg; break; case 'H': /* virtual host */ - result.config.host_name = strdup(optarg); - char *p; + result.config.initial_config.host_name = strdup(optarg); + char *tmp_string; size_t host_name_length; - if (result.config.host_name[0] == '[') { - if ((p = strstr(result.config.host_name, "]:")) != NULL) { /* [IPv6]:port */ - result.config.virtual_port = atoi(p + 2); + if (result.config.initial_config.host_name[0] == '[') { + if ((tmp_string = strstr(result.config.initial_config.host_name, "]:")) != + NULL) { /* [IPv6]:port */ + result.config.initial_config.virtualPort = atoi(tmp_string + 2); /* cut off the port */ - host_name_length = strlen(result.config.host_name) - strlen(p) - 1; - free(result.config.host_name); - result.config.host_name = strndup(optarg, host_name_length); + host_name_length = + strlen(result.config.initial_config.host_name) - strlen(tmp_string) - 1; + free(result.config.initial_config.host_name); + result.config.initial_config.host_name = strndup(optarg, host_name_length); } - } else if ((p = strchr(result.config.host_name, ':')) != NULL && - strchr(++p, ':') == NULL) { /* IPv4:port or host:port */ - result.config.virtual_port = atoi(p); + } else if ((tmp_string = strchr(result.config.initial_config.host_name, ':')) != NULL && + strchr(++tmp_string, ':') == NULL) { /* IPv4:port or host:port */ + result.config.initial_config.virtualPort = atoi(tmp_string); /* cut off the port */ - host_name_length = strlen(result.config.host_name) - strlen(p) - 1; - free(result.config.host_name); - result.config.host_name = strndup(optarg, host_name_length); + host_name_length = + strlen(result.config.initial_config.host_name) - strlen(tmp_string) - 1; + free(result.config.initial_config.host_name); + result.config.initial_config.host_name = strndup(optarg, host_name_length); } break; case 'I': /* internet address */ - result.config.server_address = strdup(optarg); + result.config.initial_config.server_address = strdup(optarg); break; case 'u': /* URL path */ - result.config.server_url = strdup(optarg); + result.config.initial_config.server_url = strdup(optarg); break; case 'p': /* Server port */ if (!is_intnonneg(optarg)) { @@ -1618,7 +1703,7 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { if (strtol(optarg, NULL, 10) > MAX_PORT) { usage2(_("Invalid port number, supplied port number is too big"), optarg); } - result.config.server_port = (unsigned short)strtol(optarg, NULL, 10); + result.config.initial_config.serverPort = (unsigned short)strtol(optarg, NULL, 10); specify_port = true; } break; @@ -1631,18 +1716,18 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { result.config.proxy_auth[MAX_INPUT_BUFFER - 1] = 0; break; case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */ - if (!result.config.http_post_data) { - result.config.http_post_data = strdup(optarg); + if (!result.config.initial_config.http_post_data) { + result.config.initial_config.http_post_data = strdup(optarg); } - if (!result.config.http_method) { - result.config.http_method = strdup("POST"); + if (!result.config.initial_config.http_method) { + result.config.initial_config.http_method = strdup("POST"); } break; case 'j': /* Set HTTP method */ - if (result.config.http_method) { - free(result.config.http_method); + if (result.config.initial_config.http_method) { + free(result.config.initial_config.http_method); } - result.config.http_method = strdup(optarg); + result.config.initial_config.http_method = strdup(optarg); break; case 'A': /* useragent */ strncpy(result.config.user_agent, optarg, DEFAULT_BUFFER_SIZE); @@ -1723,7 +1808,7 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { { enable_ssl: bool got_plus = false; - result.config.use_ssl = true; + result.config.initial_config.use_ssl = true; /* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default. * Only set if it's non-zero. This helps when we include multiple * parameters, like -S and -C combinations */ @@ -1801,7 +1886,7 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { printf(_("* Set SSL/TLS version to %d\n"), result.config.ssl_version); } if (!specify_port) { - result.config.server_port = HTTPS_PORT; + result.config.initial_config.serverPort = HTTPS_PORT; } } break; #else /* LIBCURL_FEATURE_SSL */ @@ -1935,7 +2020,7 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { break; } case 'N': /* no-body */ - result.config.no_body = true; + result.config.initial_config.no_body = true; break; case 'M': /* max-age */ { @@ -1996,21 +2081,22 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { } } - int c = optind; + int option_counter = optind; - if (result.config.server_address == NULL && c < argc) { - result.config.server_address = strdup(argv[c++]); + if (result.config.initial_config.server_address == NULL && option_counter < argc) { + result.config.initial_config.server_address = strdup(argv[option_counter++]); } - if (result.config.host_name == NULL && c < argc) { - result.config.host_name = strdup(argv[c++]); + if (result.config.initial_config.host_name == NULL && option_counter < argc) { + result.config.initial_config.host_name = strdup(argv[option_counter++]); } - if (result.config.server_address == NULL) { - if (result.config.host_name == NULL) { + if (result.config.initial_config.server_address == NULL) { + if (result.config.initial_config.host_name == NULL) { usage4(_("You must specify a server address or host name")); } else { - result.config.server_address = strdup(result.config.host_name); + result.config.initial_config.server_address = + strdup(result.config.initial_config.host_name); } } @@ -2024,21 +2110,23 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { printf("* Socket timeout set to %ld seconds\n", result.config.socket_timeout); } - if (result.config.http_method == NULL) { - result.config.http_method = strdup("GET"); + if (result.config.initial_config.http_method == NULL) { + result.config.initial_config.http_method = strdup("GET"); } if (result.config.client_cert && !result.config.client_privkey) { usage4(_("If you use a client certificate you must also specify a private key file")); } - if (result.config.virtual_port == 0) { - result.config.virtual_port = result.config.server_port; + if (result.config.initial_config.virtualPort == 0) { + result.config.initial_config.virtualPort = result.config.initial_config.serverPort; } else { - if ((result.config.use_ssl && result.config.server_port == HTTPS_PORT) || - (!result.config.use_ssl && result.config.server_port == HTTP_PORT)) { + if ((result.config.initial_config.use_ssl && + result.config.initial_config.serverPort == HTTPS_PORT) || + (!result.config.initial_config.use_ssl && + result.config.initial_config.serverPort == HTTP_PORT)) { if (!specify_port) { - result.config.server_port = result.config.virtual_port; + result.config.initial_config.serverPort = result.config.initial_config.virtualPort; } } } @@ -2389,12 +2477,12 @@ size_t curlhelp_buffer_write_callback(void *buffer, size_t size, size_t nmemb, v size_t curlhelp_buffer_read_callback(void *buffer, size_t size, size_t nmemb, void *stream) { curlhelp_read_curlbuf *buf = (curlhelp_read_curlbuf *)stream; - size_t n = min(nmemb * size, buf->buflen - buf->pos); + size_t minimalSize = min(nmemb * size, buf->buflen - buf->pos); - memcpy(buffer, buf->buf + buf->pos, n); - buf->pos += n; + memcpy(buffer, buf->buf + buf->pos, minimalSize); + buf->pos += minimalSize; - return n; + return minimalSize; } void curlhelp_freewritebuffer(curlhelp_write_curlbuf *buf) { @@ -2473,86 +2561,85 @@ int curlhelp_parse_statusline(const char *buf, curlhelp_statusline *status_line) char *first_line_buf = strdup(status_line->first_line); /* protocol and version: "HTTP/x.x" SP or "HTTP/2" SP */ - char *p = strtok(first_line_buf, "/"); - if (p == NULL) { + char *temp_string = strtok(first_line_buf, "/"); + if (temp_string == NULL) { free(first_line_buf); return -1; } - if (strcmp(p, "HTTP") != 0) { + if (strcmp(temp_string, "HTTP") != 0) { free(first_line_buf); return -1; } - p = strtok(NULL, " "); - if (p == NULL) { + temp_string = strtok(NULL, " "); + if (temp_string == NULL) { free(first_line_buf); return -1; } - char *pp; - if (strchr(p, '.') != NULL) { + char *temp_string_2; + if (strchr(temp_string, '.') != NULL) { /* HTTP 1.x case */ - strtok(p, "."); - status_line->http_major = (int)strtol(p, &pp, 10); - if (*pp != '\0') { + strtok(temp_string, "."); + status_line->http_major = (int)strtol(temp_string, &temp_string_2, 10); + if (*temp_string_2 != '\0') { free(first_line_buf); return -1; } strtok(NULL, " "); - status_line->http_minor = (int)strtol(p, &pp, 10); - if (*pp != '\0') { + status_line->http_minor = (int)strtol(temp_string, &temp_string_2, 10); + if (*temp_string_2 != '\0') { free(first_line_buf); return -1; } - p += 4; /* 1.x SP */ + temp_string += 4; /* 1.x SP */ } else { /* HTTP 2 case */ - status_line->http_major = (int)strtol(p, &pp, 10); + status_line->http_major = (int)strtol(temp_string, &temp_string_2, 10); status_line->http_minor = 0; - p += 2; /* 2 SP */ + temp_string += 2; /* 2 SP */ } /* status code: "404" or "404.1", then SP */ - - p = strtok(p, " "); - if (p == NULL) { + temp_string = strtok(temp_string, " "); + if (temp_string == NULL) { free(first_line_buf); return -1; } - if (strchr(p, '.') != NULL) { + if (strchr(temp_string, '.') != NULL) { char *ppp; - ppp = strtok(p, "."); - status_line->http_code = (int)strtol(ppp, &pp, 10); - if (*pp != '\0') { + ppp = strtok(temp_string, "."); + status_line->http_code = (int)strtol(ppp, &temp_string_2, 10); + if (*temp_string_2 != '\0') { free(first_line_buf); return -1; } ppp = strtok(NULL, ""); - status_line->http_subcode = (int)strtol(ppp, &pp, 10); - if (*pp != '\0') { + status_line->http_subcode = (int)strtol(ppp, &temp_string_2, 10); + if (*temp_string_2 != '\0') { free(first_line_buf); return -1; } - p += 6; /* 400.1 SP */ + temp_string += 6; /* 400.1 SP */ } else { - status_line->http_code = (int)strtol(p, &pp, 10); + status_line->http_code = (int)strtol(temp_string, &temp_string_2, 10); status_line->http_subcode = -1; - if (*pp != '\0') { + if (*temp_string_2 != '\0') { free(first_line_buf); return -1; } - p += 4; /* 400 SP */ + temp_string += 4; /* 400 SP */ } /* Human readable message: "Not Found" CRLF */ - p = strtok(p, ""); - if (p == NULL) { + temp_string = strtok(temp_string, ""); + if (temp_string == NULL) { status_line->msg = ""; return 0; } - status_line->msg = status_line->first_line + (p - first_line_buf); + status_line->msg = status_line->first_line + (temp_string - first_line_buf); free(first_line_buf); return 0; -- cgit v1.2.3-74-g34f1