From 58bcaeb137f5725c6fa22aba28b129aae848fa1b Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Fri, 20 Jan 2017 10:18:24 +0100 Subject: adapted to style, using header file shims instead of HAVE_XXX by hand diff --git a/plugins/check_curl.c b/plugins/check_curl.c index 8ef48d0..8ed1aee 100644 --- a/plugins/check_curl.c +++ b/plugins/check_curl.c @@ -13,7 +13,7 @@ * normal (http) and secure (https) servers, follow redirects, search for * strings and regular expressions, check connection times, and report on * certificate expiration times. -* +* * This plugin uses functions from the curl library, see * http://curl.haxx.se * @@ -40,20 +40,6 @@ const char *email = "devel@monitoring-plugins.org"; #include "common.h" #include "utils.h" -#ifdef HAVE_SYS_TYPES_H -#include -#else -#define unsigned int size_t -#endif - -#ifdef HAVE_STRING_H -#include -#endif - -#ifdef HAVE_STDLIB_H -#include -#endif - #ifndef LIBCURL_PROTOCOL_HTTP #error libcurl compiled without HTTP support, compiling check_curl plugin makes not much sense #endif @@ -69,21 +55,21 @@ const char *email = "devel@monitoring-plugins.org"; /* for buffers for header and body */ typedef struct { - char *buf; - size_t buflen; - size_t bufsize; + char *buf; + size_t buflen; + size_t bufsize; } curlhelp_curlbuf; /* for parsing the HTTP status line */ typedef struct { - int http_major; /* major version of the protocol, always 1 (HTTP/0.9 - * never reached the big internet most likely) */ - int http_minor; /* minor version of the protocol, usually 0 or 1 */ - int http_code; /* HTTP return code as in RFC 2145 */ - int http_subcode; /* Microsoft IIS extension, HTTP subcodes, see - * http://support.microsoft.com/kb/318380/en-us */ - char *msg; /* the human readable message */ - char *first_line; /* a copy of the first line */ + int http_major; /* major version of the protocol, always 1 (HTTP/0.9 + * never reached the big internet most likely) */ + int http_minor; /* minor version of the protocol, usually 0 or 1 */ + int http_code; /* HTTP return code as in RFC 2145 */ + int http_subcode; /* Microsoft IIS extension, HTTP subcodes, see + * http://support.microsoft.com/kb/318380/en-us */ + char *msg; /* the human readable message */ + char *first_line; /* a copy of the first line */ } curlhelp_statusline; char *server_address; @@ -137,587 +123,587 @@ void test_file (char *); int main (int argc, char **argv) { - int result = STATE_OK; - - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - /* Parse extra opts if any */ - argv = np_extra_opts (&argc, argv, progname); - - /* set defaults */ - snprintf( user_agent, DEFAULT_BUFFER_SIZE, "%s/v%s (monitoring-plugins %s)", - progname, NP_VERSION, VERSION); - - /* parse arguments */ - if (process_arguments (argc, argv) == ERROR) - usage4 (_("Could not parse arguments")); - - /* initialize curl */ - if (curl_global_init (CURL_GLOBAL_DEFAULT) != CURLE_OK) - die (STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n"); - - if ((curl = curl_easy_init()) == NULL) - die (STATE_UNKNOWN, "HTTP UNKNOWN - curl_easy_init failed\n"); - - if (verbose >= 3) - curl_easy_setopt (curl, CURLOPT_VERBOSE, TRUE); - - /* initialize buffer for body of the answer */ - if (curlhelp_initbuffer(&body_buf) < 0) - die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n"); - curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, curlhelp_buffer_callback); - curl_easy_setopt (curl, CURLOPT_WRITEDATA, (void *)&body_buf); - - /* initialize buffer for header of the answer */ - if (curlhelp_initbuffer( &header_buf ) < 0) - die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n" ); - curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION, curlhelp_buffer_callback); - curl_easy_setopt (curl, CURLOPT_WRITEHEADER, (void *)&header_buf); - - /* set the error buffer */ - curl_easy_setopt (curl, CURLOPT_ERRORBUFFER, errbuf); - - /* set timeouts */ - curl_easy_setopt (curl, CURLOPT_CONNECTTIMEOUT, socket_timeout); - curl_easy_setopt (curl, CURLOPT_TIMEOUT, socket_timeout); - - /* compose URL */ - snprintf (url, DEFAULT_BUFFER_SIZE, "%s://%s%s", use_ssl ? "https" : "http", - server_address, server_url); - curl_easy_setopt (curl, CURLOPT_URL, url); - - /* set port */ - curl_easy_setopt (curl, CURLOPT_PORT, server_port); - - /* compose HTTP headers */ - snprintf (http_header, DEFAULT_BUFFER_SIZE, "Host: %s", host_name); - header_list = curl_slist_append (header_list, http_header); - curl_easy_setopt( curl, CURLOPT_HTTPHEADER, header_list ); - - /* set SSL version, warn about unsecure or unsupported versions */ - if (use_ssl) { - curl_easy_setopt (curl, CURLOPT_SSLVERSION, ssl_version); - } - - /* client certificate and key to present to server (SSL) */ - if (client_cert) - curl_easy_setopt (curl, CURLOPT_SSLCERT, client_cert); - if (client_privkey) - curl_easy_setopt (curl, CURLOPT_SSLKEY, client_privkey); - - /* per default if we have a CA verify both the peer and the - * hostname in the certificate, can be switched off later */ - curl_easy_setopt( curl, CURLOPT_SSL_VERIFYPEER, 2); - curl_easy_setopt( curl, CURLOPT_SSL_VERIFYHOST, 2); - - /* backward-compatible behaviour, be tolerant in checks */ - if (!check_cert) { - //TODO: depending on more options have aspects we want - //to be tolerant about - //curl_easy_setopt( curl, CURLOPT_SSL_VERIFYPEER, 1 ); - curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, 0); - curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, 0); - } - - /* set default or user-given user agent identification */ - curl_easy_setopt (curl, CURLOPT_USERAGENT, user_agent); - - /* authentication */ - if (strcmp(user_auth, "")) - curl_easy_setopt (curl, CURLOPT_USERPWD, user_auth); - - /* TODO: parameter auth method, bitfield of following methods: - * CURLAUTH_BASIC (default) - * CURLAUTH_DIGEST - * CURLAUTH_DIGEST_IE - * CURLAUTH_NEGOTIATE - * CURLAUTH_NTLM - * CURLAUTH_NTLM_WB - * - * convenience tokens for typical sets of methods: - * CURLAUTH_ANYSAFE: most secure, without BASIC - * or CURLAUTH_ANY: most secure, even BASIC if necessary - * - * curl_easy_setopt( curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_DIGEST ); - */ - - /* TODO: --cacert: CA certificate file to verify SSL connection against (SSL) */ - //~ if( args_info.cacert_given ) { - //~ curl_easy_setopt( curl, CURLOPT_CAINFO, args_info.cacert_arg ); - //~ } - - /* handle redirections */ - if (onredirect == STATE_DEPENDENT) { - curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1); - /* TODO: handle the following aspects of redirection - CURLOPT_POSTREDIR: method switch - CURLINFO_REDIRECT_URL: custom redirect option - CURLOPT_REDIRECT_PROTOCOLS - CURLINFO_REDIRECT_COUNT - */ - } - - /* do the request */ - res = curl_easy_perform(curl); - - /* free header list, we don't need it anymore */ - curl_slist_free_all (header_list); - - /* Curl errors, result in critical Nagios state */ - if (res != CURLE_OK) { - remove_newlines (errbuf); - snprintf (msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host on port %d: cURL returned %d - %s\n"), - server_port, res, curl_easy_strerror(res)); - die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); - } - - /* we got the data and we executed the request in a given time, so we can append - * performance data to the answer always - */ - curl_easy_getinfo (curl, CURLINFO_TOTAL_TIME, &total_time); - snprintf (perfstring, DEFAULT_BUFFER_SIZE, "time=%.6gs;%.6g;%.6g;%.6g size=%dB;;;0", - total_time, - 0.0, 0.0, - //~ args_info.warning_given ? args_info.warning_arg : 0.0, - //~ args_info.critical_given ? args_info.critical_arg : 0.0, - 0.0, - (int)body_buf.buflen); - - /* return a CRITICAL status if we couldn't read any data */ - if (strlen(header_buf.buf) == 0 && strlen(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) { - snprintf (msg, DEFAULT_BUFFER_SIZE, "Unparseable status line in %.3g seconds response time|%s\n", - code, total_time, perfstring); - die (STATE_CRITICAL, "HTTP CRITICAL HTTP/1.x %d unknown - %s", code, msg); - } - - /* get result code from cURL */ - curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &code); - if (verbose>=2) - printf ("* curl CURLINFO_RESPONSE_CODE is %d\n", code); - - /* print status line, header, body if verbose */ - if (verbose >= 2) { - puts ("--- HEADER ---"); - puts (header_buf.buf); - puts ("--- BODY ---"); - puts (body_buf.buf); - } - - /* illegal return codes result in a critical state */ - if (code >= 600 || code < 100) { - die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%d, %.40s)\n"), status_line.http_code, status_line.msg); - /* server errors result in a critical state */ - } else if (code >= 500) { - result = STATE_CRITICAL; - /* client errors result in a warning state */ - } else if (code >= 400) { - result = STATE_WARNING; - /* check redirected page if specified */ - } else if (code >= 300) { - if (onredirect == STATE_DEPENDENT) { - code = status_line.http_code; - } - result = max_state_alt (onredirect, result); - /* TODO: make sure the last status line has been - parsed into the status_line structure - */ - /* all other codes are considered ok */ - } else { - result = STATE_OK; - } - - /* check status codes, set exit status accordingly */ - if( status_line.http_code != code ) { - die (STATE_CRITICAL, _("HTTP CRITICAL HTTP/%d.%d %d %s - different HTTP codes (cUrl has %ld)\n"), - status_line.http_major, status_line.http_minor, - status_line.http_code, status_line.msg, code); - } - - /* Page and Header content checks go here */ - if (strlen (string_expect)) { - if (!strstr (body_buf.buf, string_expect)) { - strncpy(&output_string_search[0],string_expect,sizeof(output_string_search)); - if(output_string_search[sizeof(output_string_search)-1]!='\0') { - bcopy("...",&output_string_search[sizeof(output_string_search)-4],4); - } - snprintf (msg, DEFAULT_BUFFER_SIZE, _("%sstring '%s' not found on '%s://%s:%d%s', "), msg, output_string_search, use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url); - result = STATE_CRITICAL; - } - } - - /* -w, -c: check warning and critical level */ - result = max_state_alt(get_status(total_time, thlds), result); - - //~ die (result, "HTTP %s: %s\n", state_text(result), msg); - die (result, "HTTP %s HTTP/%d.%d %d %s - %s - %.3g seconds response time|%s\n", - state_text(result), status_line.http_major, status_line.http_minor, - status_line.http_code, status_line.msg, msg, - total_time, perfstring); - - /* proper cleanup after die? */ - curlhelp_free_statusline(&status_line); - curl_easy_cleanup (curl); - curl_global_cleanup (); - curlhelp_freebuffer(&body_buf); - curlhelp_freebuffer(&header_buf); - - return result; + int result = STATE_OK; + + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + /* Parse extra opts if any */ + argv = np_extra_opts (&argc, argv, progname); + + /* set defaults */ + snprintf( user_agent, DEFAULT_BUFFER_SIZE, "%s/v%s (monitoring-plugins %s)", + progname, NP_VERSION, VERSION); + + /* parse arguments */ + if (process_arguments (argc, argv) == ERROR) + usage4 (_("Could not parse arguments")); + + /* initialize curl */ + if (curl_global_init (CURL_GLOBAL_DEFAULT) != CURLE_OK) + die (STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n"); + + if ((curl = curl_easy_init()) == NULL) + die (STATE_UNKNOWN, "HTTP UNKNOWN - curl_easy_init failed\n"); + + if (verbose >= 3) + curl_easy_setopt (curl, CURLOPT_VERBOSE, TRUE); + + /* initialize buffer for body of the answer */ + if (curlhelp_initbuffer(&body_buf) < 0) + die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n"); + curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, curlhelp_buffer_callback); + curl_easy_setopt (curl, CURLOPT_WRITEDATA, (void *)&body_buf); + + /* initialize buffer for header of the answer */ + if (curlhelp_initbuffer( &header_buf ) < 0) + die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n" ); + curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION, curlhelp_buffer_callback); + curl_easy_setopt (curl, CURLOPT_WRITEHEADER, (void *)&header_buf); + + /* set the error buffer */ + curl_easy_setopt (curl, CURLOPT_ERRORBUFFER, errbuf); + + /* set timeouts */ + curl_easy_setopt (curl, CURLOPT_CONNECTTIMEOUT, socket_timeout); + curl_easy_setopt (curl, CURLOPT_TIMEOUT, socket_timeout); + + /* compose URL */ + snprintf (url, DEFAULT_BUFFER_SIZE, "%s://%s%s", use_ssl ? "https" : "http", + server_address, server_url); + curl_easy_setopt (curl, CURLOPT_URL, url); + + /* set port */ + curl_easy_setopt (curl, CURLOPT_PORT, server_port); + + /* compose HTTP headers */ + snprintf (http_header, DEFAULT_BUFFER_SIZE, "Host: %s", host_name); + header_list = curl_slist_append (header_list, http_header); + curl_easy_setopt( curl, CURLOPT_HTTPHEADER, header_list ); + + /* set SSL version, warn about unsecure or unsupported versions */ + if (use_ssl) { + curl_easy_setopt (curl, CURLOPT_SSLVERSION, ssl_version); + } + + /* client certificate and key to present to server (SSL) */ + if (client_cert) + curl_easy_setopt (curl, CURLOPT_SSLCERT, client_cert); + if (client_privkey) + curl_easy_setopt (curl, CURLOPT_SSLKEY, client_privkey); + + /* per default if we have a CA verify both the peer and the + * hostname in the certificate, can be switched off later */ + curl_easy_setopt( curl, CURLOPT_SSL_VERIFYPEER, 2); + curl_easy_setopt( curl, CURLOPT_SSL_VERIFYHOST, 2); + + /* backward-compatible behaviour, be tolerant in checks */ + if (!check_cert) { + //TODO: depending on more options have aspects we want + //to be tolerant about + //curl_easy_setopt( curl, CURLOPT_SSL_VERIFYPEER, 1 ); + curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, 0); + } + + /* set default or user-given user agent identification */ + curl_easy_setopt (curl, CURLOPT_USERAGENT, user_agent); + + /* authentication */ + if (strcmp(user_auth, "")) + curl_easy_setopt (curl, CURLOPT_USERPWD, user_auth); + + /* TODO: parameter auth method, bitfield of following methods: + * CURLAUTH_BASIC (default) + * CURLAUTH_DIGEST + * CURLAUTH_DIGEST_IE + * CURLAUTH_NEGOTIATE + * CURLAUTH_NTLM + * CURLAUTH_NTLM_WB + * + * convenience tokens for typical sets of methods: + * CURLAUTH_ANYSAFE: most secure, without BASIC + * or CURLAUTH_ANY: most secure, even BASIC if necessary + * + * curl_easy_setopt( curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_DIGEST ); + */ + + /* TODO: --cacert: CA certificate file to verify SSL connection against (SSL) */ + //~ if( args_info.cacert_given ) { + //~ curl_easy_setopt( curl, CURLOPT_CAINFO, args_info.cacert_arg ); + //~ } + + /* handle redirections */ + if (onredirect == STATE_DEPENDENT) { + curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1); + /* TODO: handle the following aspects of redirection + CURLOPT_POSTREDIR: method switch + CURLINFO_REDIRECT_URL: custom redirect option + CURLOPT_REDIRECT_PROTOCOLS + CURLINFO_REDIRECT_COUNT + */ + } + + /* do the request */ + res = curl_easy_perform(curl); + + /* free header list, we don't need it anymore */ + curl_slist_free_all (header_list); + + /* Curl errors, result in critical Nagios state */ + if (res != CURLE_OK) { + remove_newlines (errbuf); + snprintf (msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host on port %d: cURL returned %d - %s\n"), + server_port, res, curl_easy_strerror(res)); + die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); + } + + /* we got the data and we executed the request in a given time, so we can append + * performance data to the answer always + */ + curl_easy_getinfo (curl, CURLINFO_TOTAL_TIME, &total_time); + snprintf (perfstring, DEFAULT_BUFFER_SIZE, "time=%.6gs;%.6g;%.6g;%.6g size=%dB;;;0", + total_time, + 0.0, 0.0, + //~ args_info.warning_given ? args_info.warning_arg : 0.0, + //~ args_info.critical_given ? args_info.critical_arg : 0.0, + 0.0, + (int)body_buf.buflen); + + /* return a CRITICAL status if we couldn't read any data */ + if (strlen(header_buf.buf) == 0 && strlen(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) { + snprintf (msg, DEFAULT_BUFFER_SIZE, "Unparseable status line in %.3g seconds response time|%s\n", + code, total_time, perfstring); + die (STATE_CRITICAL, "HTTP CRITICAL HTTP/1.x %d unknown - %s", code, msg); + } + + /* get result code from cURL */ + curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &code); + if (verbose>=2) + printf ("* curl CURLINFO_RESPONSE_CODE is %d\n", code); + + /* print status line, header, body if verbose */ + if (verbose >= 2) { + puts ("--- HEADER ---"); + puts (header_buf.buf); + puts ("--- BODY ---"); + puts (body_buf.buf); + } + + /* illegal return codes result in a critical state */ + if (code >= 600 || code < 100) { + die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%d, %.40s)\n"), status_line.http_code, status_line.msg); + /* server errors result in a critical state */ + } else if (code >= 500) { + result = STATE_CRITICAL; + /* client errors result in a warning state */ + } else if (code >= 400) { + result = STATE_WARNING; + /* check redirected page if specified */ + } else if (code >= 300) { + if (onredirect == STATE_DEPENDENT) { + code = status_line.http_code; + } + result = max_state_alt (onredirect, result); + /* TODO: make sure the last status line has been + parsed into the status_line structure + */ + /* all other codes are considered ok */ + } else { + result = STATE_OK; + } + + /* check status codes, set exit status accordingly */ + if( status_line.http_code != code ) { + die (STATE_CRITICAL, _("HTTP CRITICAL HTTP/%d.%d %d %s - different HTTP codes (cUrl has %ld)\n"), + status_line.http_major, status_line.http_minor, + status_line.http_code, status_line.msg, code); + } + + /* Page and Header content checks go here */ + if (strlen (string_expect)) { + if (!strstr (body_buf.buf, string_expect)) { + strncpy(&output_string_search[0],string_expect,sizeof(output_string_search)); + if(output_string_search[sizeof(output_string_search)-1]!='\0') { + bcopy("...",&output_string_search[sizeof(output_string_search)-4],4); + } + snprintf (msg, DEFAULT_BUFFER_SIZE, _("%sstring '%s' not found on '%s://%s:%d%s', "), msg, output_string_search, use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url); + result = STATE_CRITICAL; + } + } + + /* -w, -c: check warning and critical level */ + result = max_state_alt(get_status(total_time, thlds), result); + + //~ die (result, "HTTP %s: %s\n", state_text(result), msg); + die (result, "HTTP %s HTTP/%d.%d %d %s - %s - %.3g seconds response time|%s\n", + state_text(result), status_line.http_major, status_line.http_minor, + status_line.http_code, status_line.msg, msg, + total_time, perfstring); + + /* proper cleanup after die? */ + curlhelp_free_statusline(&status_line); + curl_easy_cleanup (curl); + curl_global_cleanup (); + curlhelp_freebuffer(&body_buf); + curlhelp_freebuffer(&header_buf); + + return result; } /* check whether a file exists */ void test_file (char *path) { - if (access(path, R_OK) == 0) - return; - usage2 (_("file does not exist or is not readable"), path); + if (access(path, R_OK) == 0) + return; + usage2 (_("file does not exist or is not readable"), path); } int process_arguments (int argc, char **argv) { - int c; - - enum { - SNI_OPTION - }; - - int option=0; - static struct option longopts[] = { - {"ssl", optional_argument, 0, 'S'}, - {"sni", no_argument, 0, SNI_OPTION}, - {"IP-address", required_argument, 0, 'I'}, - {"url", required_argument, 0, 'u'}, - {"port", required_argument, 0, 'p'}, - {"authorization", required_argument, 0, 'a'}, - {"string", required_argument, 0, 's'}, - {"onredirect", required_argument, 0, 'f'}, - {"client-cert", required_argument, 0, 'J'}, - {"private-key", required_argument, 0, 'K'}, - {"useragent", required_argument, 0, 'A'}, - {"certificate", required_argument, 0, 'C'}, - {0, 0, 0, 0} - }; - - if (argc < 2) - usage ("\n"); - - while (1) { - c = getopt_long (argc, argv, "Vvht:c:w:A:H:I:a:p:s:u:f:C:J:K:S::", longopts, &option); - if (c == -1 || c == EOF || c == 1) - break; - - switch (c) { - case 'h': - print_help(); - exit(STATE_UNKNOWN); - break; - case 'V': - print_revision(progname, NP_VERSION); - print_curl_version(); - exit(STATE_UNKNOWN); - break; - case 'v': - verbose++; - break; - case 't': /* timeout period */ - if (!is_intnonneg (optarg)) - usage2 (_("Timeout interval must be a positive integer"), optarg); - else - socket_timeout = (int)strtol (optarg, NULL, 10); - break; - case 'c': /* critical time threshold */ - critical_thresholds = optarg; - break; - case 'w': /* warning time threshold */ - warning_thresholds = optarg; - break; - case 'H': /* virtual host */ - host_name = strdup (optarg); - break; - case 'I': /* internet address */ - server_address = strdup (optarg); - break; - case 'u': /* URL path */ - server_url = strdup (optarg); - break; - case 'p': /* Server port */ - if (!is_intnonneg (optarg)) - usage2 (_("Invalid port number, expecting a non-negative number"), optarg); - else { - if( strtol(optarg, NULL, 10) > MAX_PORT) - usage2 (_("Invalid port number, supplied port number is too big"), optarg); - server_port = (unsigned short)strtol(optarg, NULL, 10); - } - break; - case 'a': /* authorization info */ - strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1); - user_auth[MAX_INPUT_BUFFER - 1] = 0; - break; - case 'A': /* useragent */ - snprintf (user_agent, DEFAULT_BUFFER_SIZE, optarg); - break; - case 'C': /* Check SSL cert validity */ + int c; + + enum { + SNI_OPTION + }; + + int option=0; + static struct option longopts[] = { + {"ssl", optional_argument, 0, 'S'}, + {"sni", no_argument, 0, SNI_OPTION}, + {"IP-address", required_argument, 0, 'I'}, + {"url", required_argument, 0, 'u'}, + {"port", required_argument, 0, 'p'}, + {"authorization", required_argument, 0, 'a'}, + {"string", required_argument, 0, 's'}, + {"onredirect", required_argument, 0, 'f'}, + {"client-cert", required_argument, 0, 'J'}, + {"private-key", required_argument, 0, 'K'}, + {"useragent", required_argument, 0, 'A'}, + {"certificate", required_argument, 0, 'C'}, + {0, 0, 0, 0} + }; + + if (argc < 2) + usage ("\n"); + + while (1) { + c = getopt_long (argc, argv, "Vvht:c:w:A:H:I:a:p:s:u:f:C:J:K:S::", longopts, &option); + if (c == -1 || c == EOF || c == 1) + break; + + switch (c) { + case 'h': + print_help(); + exit(STATE_UNKNOWN); + break; + case 'V': + print_revision(progname, NP_VERSION); + print_curl_version(); + exit(STATE_UNKNOWN); + break; + case 'v': + verbose++; + break; + case 't': /* timeout period */ + if (!is_intnonneg (optarg)) + usage2 (_("Timeout interval must be a positive integer"), optarg); + else + socket_timeout = (int)strtol (optarg, NULL, 10); + break; + case 'c': /* critical time threshold */ + critical_thresholds = optarg; + break; + case 'w': /* warning time threshold */ + warning_thresholds = optarg; + break; + case 'H': /* virtual host */ + host_name = strdup (optarg); + break; + case 'I': /* internet address */ + server_address = strdup (optarg); + break; + case 'u': /* URL path */ + server_url = strdup (optarg); + break; + case 'p': /* Server port */ + if (!is_intnonneg (optarg)) + usage2 (_("Invalid port number, expecting a non-negative number"), optarg); + else { + if( strtol(optarg, NULL, 10) > MAX_PORT) + usage2 (_("Invalid port number, supplied port number is too big"), optarg); + server_port = (unsigned short)strtol(optarg, NULL, 10); + } + break; + case 'a': /* authorization info */ + strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1); + user_auth[MAX_INPUT_BUFFER - 1] = 0; + break; + case 'A': /* useragent */ + snprintf (user_agent, DEFAULT_BUFFER_SIZE, optarg); + break; + case 'C': /* Check SSL cert validity */ #ifdef LIBCURL_FEATURE_SSL - /* TODO: C:, check age of certificate for backward compatible - * behaviour, but we would later add more check conditions */ - check_cert = TRUE; - goto enable_ssl; + /* TODO: C:, check age of certificate for backward compatible + * behaviour, but we would later add more check conditions */ + check_cert = TRUE; + goto enable_ssl; #endif - case 'J': /* use client certificate */ + case 'J': /* use client certificate */ #ifdef LIBCURL_FEATURE_SSL - test_file(optarg); - client_cert = optarg; - goto enable_ssl; + test_file(optarg); + client_cert = optarg; + goto enable_ssl; #endif - case 'K': /* use client private key */ + case 'K': /* use client private key */ #ifdef LIBCURL_FEATURE_SSL - test_file(optarg); - client_privkey = optarg; - goto enable_ssl; + test_file(optarg); + client_privkey = optarg; + goto enable_ssl; #endif - case 'S': /* use SSL */ + case 'S': /* use SSL */ #ifdef LIBCURL_FEATURE_SSL - enable_ssl: - use_ssl = TRUE; - /* ssl_version initialized to CURL_SSLVERSION_TLSv1_0 as a default. Only set if it's non-zero. This helps when we include multiple - parameters, like -S and -C combinations */ - ssl_version = CURL_SSLVERSION_TLSv1_0; - if (c=='S' && optarg != NULL) { - int got_plus = strchr(optarg, '+') != NULL; - - if (!strncmp (optarg, "1.2", 3)) - ssl_version = CURL_SSLVERSION_TLSv1_2; - else if (!strncmp (optarg, "1.1", 3)) - ssl_version = CURL_SSLVERSION_TLSv1_1; - else if (optarg[0] == '1') - ssl_version = CURL_SSLVERSION_TLSv1_0; - else if (optarg[0] == '3') - ssl_version = CURL_SSLVERSION_SSLv3; - else if (optarg[0] == '2') - ssl_version = CURL_SSLVERSION_SSLv2; - else - usage4 (_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2 (with optional '+' suffix)")); - } - if (server_port == DEFAULT_HTTP_PORT) - server_port = DEFAULT_HTTPS_PORT; + enable_ssl: + use_ssl = TRUE; + /* ssl_version initialized to CURL_SSLVERSION_TLSv1_0 as a default. Only set if it's non-zero. This helps when we include multiple + parameters, like -S and -C combinations */ + ssl_version = CURL_SSLVERSION_TLSv1_0; + if (c=='S' && optarg != NULL) { + int got_plus = strchr(optarg, '+') != NULL; + + if (!strncmp (optarg, "1.2", 3)) + ssl_version = CURL_SSLVERSION_TLSv1_2; + else if (!strncmp (optarg, "1.1", 3)) + ssl_version = CURL_SSLVERSION_TLSv1_1; + else if (optarg[0] == '1') + ssl_version = CURL_SSLVERSION_TLSv1_0; + else if (optarg[0] == '3') + ssl_version = CURL_SSLVERSION_SSLv3; + else if (optarg[0] == '2') + ssl_version = CURL_SSLVERSION_SSLv2; + else + usage4 (_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2 (with optional '+' suffix)")); + } + if (server_port == DEFAULT_HTTP_PORT) + server_port = DEFAULT_HTTPS_PORT; #else - /* -C -J and -K fall through to here without SSL */ - usage4 (_("Invalid option - SSL is not available")); + /* -C -J and -K fall through to here without SSL */ + usage4 (_("Invalid option - SSL is not available")); #endif - break; - case SNI_OPTION: /* --sni is parsed, but ignored, the default is TRUE with libcurl */ - use_sni = TRUE; - break; - case 'f': /* onredirect */ - if (!strcmp (optarg, "ok")) - onredirect = STATE_OK; - else if (!strcmp (optarg, "warning")) - onredirect = STATE_WARNING; - else if (!strcmp (optarg, "critical")) - onredirect = STATE_CRITICAL; - else if (!strcmp (optarg, "unknown")) - onredirect = STATE_UNKNOWN; - else if (!strcmp (optarg, "follow")) - onredirect = STATE_DEPENDENT; - else usage2 (_("Invalid onredirect option"), optarg); - //~ if (!strcmp (optarg, "stickyport")) - //~ onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST|STICKY_PORT; - //~ else if (!strcmp (optarg, "sticky")) - //~ onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST; - //~ else if (!strcmp (optarg, "follow")) - //~ onredirect = STATE_DEPENDENT, followsticky = STICKY_NONE; - if (verbose >= 2) - printf(_("* Following redirects set to %s\n"), state_text(onredirect)); - break; - case 's': /* string or substring */ - strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1); - string_expect[MAX_INPUT_BUFFER - 1] = 0; - break; - case '?': - /* print short usage statement if args not parsable */ - usage5 (); - break; - } - } - - c = optind; - - if (server_address == NULL && c < argc) - server_address = strdup (argv[c++]); - - if (host_name == NULL && c < argc) - host_name = strdup (argv[c++]); - - if (server_address == NULL) { - if (host_name == NULL) - usage4 (_("You must specify a server address or host name")); - else - server_address = strdup (host_name); - } - - set_thresholds(&thlds, warning_thresholds, critical_thresholds); - - if (critical_thresholds && thlds->critical->end>(double)socket_timeout) - socket_timeout = (int)thlds->critical->end + 1; - if (verbose >= 2) - printf ("* Socket timeout set to %d seconds\n", socket_timeout); + break; + case SNI_OPTION: /* --sni is parsed, but ignored, the default is TRUE with libcurl */ + use_sni = TRUE; + break; + case 'f': /* onredirect */ + if (!strcmp (optarg, "ok")) + onredirect = STATE_OK; + else if (!strcmp (optarg, "warning")) + onredirect = STATE_WARNING; + else if (!strcmp (optarg, "critical")) + onredirect = STATE_CRITICAL; + else if (!strcmp (optarg, "unknown")) + onredirect = STATE_UNKNOWN; + else if (!strcmp (optarg, "follow")) + onredirect = STATE_DEPENDENT; + else usage2 (_("Invalid onredirect option"), optarg); + //~ if (!strcmp (optarg, "stickyport")) + //~ onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST|STICKY_PORT; + //~ else if (!strcmp (optarg, "sticky")) + //~ onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST; + //~ else if (!strcmp (optarg, "follow")) + //~ onredirect = STATE_DEPENDENT, followsticky = STICKY_NONE; + if (verbose >= 2) + printf(_("* Following redirects set to %s\n"), state_text(onredirect)); + break; + case 's': /* string or substring */ + strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1); + string_expect[MAX_INPUT_BUFFER - 1] = 0; + break; + case '?': + /* print short usage statement if args not parsable */ + usage5 (); + break; + } + } + + c = optind; + + if (server_address == NULL && c < argc) + server_address = strdup (argv[c++]); + + if (host_name == NULL && c < argc) + host_name = strdup (argv[c++]); + + if (server_address == NULL) { + if (host_name == NULL) + usage4 (_("You must specify a server address or host name")); + else + server_address = strdup (host_name); + } + + set_thresholds(&thlds, warning_thresholds, critical_thresholds); + + if (critical_thresholds && thlds->critical->end>(double)socket_timeout) + socket_timeout = (int)thlds->critical->end + 1; + if (verbose >= 2) + printf ("* Socket timeout set to %d seconds\n", socket_timeout); //~ if (http_method == NULL) //~ http_method = strdup ("GET"); - if (client_cert && !client_privkey) - usage4 (_("If you use a client certificate you must also specify a private key file")); + if (client_cert && !client_privkey) + usage4 (_("If you use a client certificate you must also specify a private key file")); //~ if (virtual_port == 0) //~ virtual_port = server_port; - return TRUE; + return TRUE; } void print_help (void) { - print_revision(progname, NP_VERSION); + print_revision(progname, NP_VERSION); + + printf ("Copyright (c) 1999 Ethan Galstad \n"); + printf ("Copyright (c) 2017 Andreas Baumann \n"); + printf (COPYRIGHT, copyright, email); - printf ("Copyright (c) 1999 Ethan Galstad \n"); - printf ("Copyright (c) 2017 Andreas Baumann \n"); - printf (COPYRIGHT, copyright, email); + printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test")); + printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for")); + printf ("%s\n", _("strings and regular expressions, check connection times, and report on")); + printf ("%s\n", _("certificate expiration times.")); + printf ("\n"); + printf ("%s\n", _("It makes use of libcurl to do so. It tries to be as compatible to check_http")); + printf ("%s\n", _("as possible.")); - printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test")); - printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for")); - printf ("%s\n", _("strings and regular expressions, check connection times, and report on")); - printf ("%s\n", _("certificate expiration times.")); - printf ("\n"); - printf ("%s\n", _("It makes use of libcurl to do so. It tries to be as compatible to check_http")); - printf ("%s\n", _("as possible.")); + printf ("\n\n"); - printf ("\n\n"); + print_usage(); - print_usage(); - - printf (_("NOTE: One or both of -H and -I must be specified")); + printf (_("NOTE: One or both of -H and -I must be specified")); - printf ("\n"); + printf ("\n"); - printf (UT_HELP_VRSN); - printf (UT_EXTRA_OPTS); + printf (UT_HELP_VRSN); + printf (UT_EXTRA_OPTS); - printf (" %s\n", "-H, --hostname=ADDRESS"); - printf (" %s\n", _("Host name argument for servers using host headers (virtual host)")); - printf (" %s\n", _("Append a port to include it in the header (eg: example.com:5000)")); - printf (" %s\n", "-I, --IP-address=ADDRESS"); - printf (" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup).")); - printf (" %s\n", "-p, --port=INTEGER"); - printf (" %s", _("Port number (default: ")); - printf ("%d)\n", DEFAULT_HTTP_PORT); + printf (" %s\n", "-H, --hostname=ADDRESS"); + printf (" %s\n", _("Host name argument for servers using host headers (virtual host)")); + printf (" %s\n", _("Append a port to include it in the header (eg: example.com:5000)")); + printf (" %s\n", "-I, --IP-address=ADDRESS"); + printf (" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup).")); + printf (" %s\n", "-p, --port=INTEGER"); + printf (" %s", _("Port number (default: ")); + printf ("%d)\n", DEFAULT_HTTP_PORT); #ifdef LIBCURL_FEATURE_SSL - printf (" %s\n", "-S, --ssl=VERSION[+]"); - printf (" %s\n", _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents")); - printf (" %s\n", _("auto-negotiation (2 = SSLv2, 3 = SSLv3, 1 = TLSv1, 1.1 = TLSv1.1,")); - printf (" %s\n", _("1.2 = TLSv1.2). With a '+' suffix, newer versions are also accepted.")); - printf (" %s\n", _("Note: SSLv2 and SSLv3 are deprecated and are usually disabled in libcurl")); - printf (" %s\n", "--sni"); - printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)")); + printf (" %s\n", "-S, --ssl=VERSION[+]"); + printf (" %s\n", _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents")); + printf (" %s\n", _("auto-negotiation (2 = SSLv2, 3 = SSLv3, 1 = TLSv1, 1.1 = TLSv1.1,")); + printf (" %s\n", _("1.2 = TLSv1.2). With a '+' suffix, newer versions are also accepted.")); + printf (" %s\n", _("Note: SSLv2 and SSLv3 are deprecated and are usually disabled in libcurl")); + printf (" %s\n", "--sni"); + printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)")); #if LIBCURL_VERSION_NUM >= 0x071801 - printf (" %s\n", _("Note: --sni is the default in libcurl as SSLv2 and SSLV3 are deprecated and")); - printf (" %s\n", _(" SNI only really works since TLSv1.0")); + printf (" %s\n", _("Note: --sni is the default in libcurl as SSLv2 and SSLV3 are deprecated and")); + printf (" %s\n", _(" SNI only really works since TLSv1.0")); #else - printf (" %s\n", _("Note: SNI is not supported in libcurl before 7.18.1")); + printf (" %s\n", _("Note: SNI is not supported in libcurl before 7.18.1")); #endif - printf (" %s\n", "-C, --certificate"); - printf (" %s\n", _("Check validity of certificate")); - printf (" %s\n", "-J, --client-cert=FILE"); - printf (" %s\n", _("Name of file that contains the client certificate (PEM format)")); - printf (" %s\n", _("to be used in establishing the SSL session")); - printf (" %s\n", "-K, --private-key=FILE"); - printf (" %s\n", _("Name of file containing the private key (PEM format)")); - printf (" %s\n", _("matching the client certificate")); + printf (" %s\n", "-C, --certificate"); + printf (" %s\n", _("Check validity of certificate")); + printf (" %s\n", "-J, --client-cert=FILE"); + printf (" %s\n", _("Name of file that contains the client certificate (PEM format)")); + printf (" %s\n", _("to be used in establishing the SSL session")); + printf (" %s\n", "-K, --private-key=FILE"); + printf (" %s\n", _("Name of file containing the private key (PEM format)")); + printf (" %s\n", _("matching the client certificate")); #endif - printf (" %s\n", "-s, --string=STRING"); - printf (" %s\n", _("String to expect in the content")); - printf (" %s\n", "-u, --url=PATH"); - printf (" %s\n", _("URL to GET or POST (default: /)")); + printf (" %s\n", "-s, --string=STRING"); + printf (" %s\n", _("String to expect in the content")); + printf (" %s\n", "-u, --url=PATH"); + printf (" %s\n", _("URL to GET or POST (default: /)")); - printf (" %s\n", "-a, --authorization=AUTH_PAIR"); - printf (" %s\n", _("Username:password on sites with basic authentication")); - printf (" %s\n", "-A, --useragent=STRING"); - printf (" %s\n", _("String to be sent in http header as \"User Agent\"")); - printf (" %s\n", "-f, --onredirect="); - printf (" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the")); - printf (" %s\n", _("specified IP address. stickyport also ensures port stays the same.")); + printf (" %s\n", "-a, --authorization=AUTH_PAIR"); + printf (" %s\n", _("Username:password on sites with basic authentication")); + printf (" %s\n", "-A, --useragent=STRING"); + printf (" %s\n", _("String to be sent in http header as \"User Agent\"")); + printf (" %s\n", "-f, --onredirect="); + printf (" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the")); + printf (" %s\n", _("specified IP address. stickyport also ensures port stays the same.")); - printf (UT_WARN_CRIT); + printf (UT_WARN_CRIT); - printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); + printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); - printf (UT_VERBOSE); + printf (UT_VERBOSE); - printf (UT_SUPPORT); + printf (UT_SUPPORT); } void print_usage (void) { - printf ("%s\n", _("Usage:")); - printf (" %s -H | -I [-u ] [-p ]\n",progname); - printf (" [-J ] [-K ]\n"); - printf (" [-w ] [-c ] [-t ] [-a auth]\n"); - printf (" [-f ]\n"); - printf (" [-A string] [-S ] [-C]\n"); - printf (" [-v verbose]\n", progname); - printf ("\n"); - printf ("%s\n", _("WARNING: check_curl is experimental. Please use")); - printf ("%s\n\n", _("check_http if you need a stable version.")); + printf ("%s\n", _("Usage:")); + printf (" %s -H | -I [-u ] [-p ]\n",progname); + printf (" [-J ] [-K ]\n"); + printf (" [-w ] [-c ] [-t ] [-a auth]\n"); + printf (" [-f ]\n"); + printf (" [-A string] [-S ] [-C]\n"); + printf (" [-v verbose]\n", progname); + printf ("\n"); + printf ("%s\n", _("WARNING: check_curl is experimental. Please use")); + printf ("%s\n\n", _("check_http if you need a stable version.")); } void print_curl_version (void) { - printf( "%s\n", curl_version()); + printf( "%s\n", curl_version()); } int curlhelp_initbuffer (curlhelp_curlbuf *buf) { - buf->bufsize = DEFAULT_BUFFER_SIZE; - buf->buflen = 0; - buf->buf = (char *)malloc ((size_t)buf->bufsize); - if (buf->buf == NULL) return -1; - return 0; + buf->bufsize = DEFAULT_BUFFER_SIZE; + buf->buflen = 0; + buf->buf = (char *)malloc ((size_t)buf->bufsize); + if (buf->buf == NULL) return -1; + return 0; } int curlhelp_buffer_callback (void *buffer, size_t size, size_t nmemb, void *stream) { - curlhelp_curlbuf *buf = (curlhelp_curlbuf *)stream; + curlhelp_curlbuf *buf = (curlhelp_curlbuf *)stream; - while (buf->bufsize < buf->buflen + size * nmemb + 1) { - buf->bufsize *= buf->bufsize * 2; - buf->buf = (char *)realloc (buf->buf, buf->bufsize); - if (buf->buf == NULL) return -1; - } + while (buf->bufsize < buf->buflen + size * nmemb + 1) { + buf->bufsize *= buf->bufsize * 2; + buf->buf = (char *)realloc (buf->buf, buf->bufsize); + if (buf->buf == NULL) return -1; + } - memcpy (buf->buf + buf->buflen, buffer, size * nmemb); - buf->buflen += size * nmemb; - buf->buf[buf->buflen] = '\0'; + memcpy (buf->buf + buf->buflen, buffer, size * nmemb); + buf->buflen += size * nmemb; + buf->buf[buf->buflen] = '\0'; - return (int)(size * nmemb); + return (int)(size * nmemb); } void curlhelp_freebuffer (curlhelp_curlbuf *buf) { - free (buf->buf); - buf->buf = NULL; + free (buf->buf); + buf->buf = NULL; } /* TODO: when redirecting we get more than one HTTP header, make sure @@ -726,76 +712,76 @@ curlhelp_freebuffer (curlhelp_curlbuf *buf) int curlhelp_parse_statusline (char *buf, curlhelp_statusline *status_line) { - char *first_line_end; - char *p; - size_t first_line_len; - char *pp; - - first_line_end = strstr(buf, "\r\n"); - if (first_line_end == NULL) return -1; - - first_line_len = (size_t)(first_line_end - buf); - status_line->first_line = (char *)malloc (first_line_len + 1); - if (status_line->first_line == NULL) return -1; - memcpy (status_line->first_line, buf, first_line_len); - status_line->first_line[first_line_len] = '\0'; - - /* protocol and version: "HTTP/x.x" SP */ - - p = strtok(status_line->first_line, "/"); - if( p == NULL ) { free( status_line->first_line ); return -1; } - if( strcmp( p, "HTTP" ) != 0 ) { free( status_line->first_line ); return -1; } - - p = strtok( NULL, "." ); - if( p == NULL ) { free( status_line->first_line ); return -1; } - status_line->http_major = (int)strtol( p, &pp, 10 ); - if( *pp != '\0' ) { free( status_line->first_line ); return -1; } - - p = strtok( NULL, " " ); - if( p == NULL ) { free( status_line->first_line ); return -1; } - status_line->http_minor = (int)strtol( p, &pp, 10 ); - if( *pp != '\0' ) { free( status_line->first_line ); return -1; } - - /* status code: "404" or "404.1", then SP */ - - p = strtok( NULL, " ." ); - if( p == NULL ) { free( status_line->first_line ); return -1; } - if( strchr( p, '.' ) != NULL ) { - char *ppp; - ppp = strtok( p, "." ); - status_line->http_code = (int)strtol( ppp, &pp, 10 ); - if( *pp != '\0' ) { free( status_line->first_line ); return -1; } - - ppp = strtok( NULL, "" ); - status_line->http_subcode = (int)strtol( ppp, &pp, 10 ); - if( *pp != '\0' ) { free( status_line->first_line ); return -1; } - } else { - status_line->http_code = (int)strtol( p, &pp, 10 ); - status_line->http_subcode = -1; - if( *pp != '\0' ) { free( status_line->first_line ); return -1; } - } - - /* Human readable message: "Not Found" CRLF */ - - p = strtok( NULL, "" ); - if( p == NULL ) { free( status_line->first_line ); return -1; } - status_line->msg = p; - - return 0; + char *first_line_end; + char *p; + size_t first_line_len; + char *pp; + + first_line_end = strstr(buf, "\r\n"); + if (first_line_end == NULL) return -1; + + first_line_len = (size_t)(first_line_end - buf); + status_line->first_line = (char *)malloc (first_line_len + 1); + if (status_line->first_line == NULL) return -1; + memcpy (status_line->first_line, buf, first_line_len); + status_line->first_line[first_line_len] = '\0'; + + /* protocol and version: "HTTP/x.x" SP */ + + p = strtok(status_line->first_line, "/"); + if( p == NULL ) { free( status_line->first_line ); return -1; } + if( strcmp( p, "HTTP" ) != 0 ) { free( status_line->first_line ); return -1; } + + p = strtok( NULL, "." ); + if( p == NULL ) { free( status_line->first_line ); return -1; } + status_line->http_major = (int)strtol( p, &pp, 10 ); + if( *pp != '\0' ) { free( status_line->first_line ); return -1; } + + p = strtok( NULL, " " ); + if( p == NULL ) { free( status_line->first_line ); return -1; } + status_line->http_minor = (int)strtol( p, &pp, 10 ); + if( *pp != '\0' ) { free( status_line->first_line ); return -1; } + + /* status code: "404" or "404.1", then SP */ + + p = strtok( NULL, " ." ); + if( p == NULL ) { free( status_line->first_line ); return -1; } + if( strchr( p, '.' ) != NULL ) { + char *ppp; + ppp = strtok( p, "." ); + status_line->http_code = (int)strtol( ppp, &pp, 10 ); + if( *pp != '\0' ) { free( status_line->first_line ); return -1; } + + ppp = strtok( NULL, "" ); + status_line->http_subcode = (int)strtol( ppp, &pp, 10 ); + if( *pp != '\0' ) { free( status_line->first_line ); return -1; } + } else { + status_line->http_code = (int)strtol( p, &pp, 10 ); + status_line->http_subcode = -1; + if( *pp != '\0' ) { free( status_line->first_line ); return -1; } + } + + /* Human readable message: "Not Found" CRLF */ + + p = strtok( NULL, "" ); + if( p == NULL ) { free( status_line->first_line ); return -1; } + status_line->msg = p; + + return 0; } void curlhelp_free_statusline (curlhelp_statusline *status_line) { - free (status_line->first_line); + free (status_line->first_line); } void remove_newlines (char *s) { - char *p; + char *p; - for (p = s; *p != '\0'; p++) - if (*p == '\r' || *p == '\n') - *p = ' '; + for (p = s; *p != '\0'; p++) + if (*p == '\r' || *p == '\n') + *p = ' '; } -- cgit v0.10-9-g596f