diff options
Diffstat (limited to 'plugins')
| -rw-r--r-- | plugins/Makefile.am | 2 | ||||
| -rw-r--r-- | plugins/check_curl.c | 41 | ||||
| -rw-r--r-- | plugins/check_curl.d/check_curl_helpers.c | 30 | ||||
| -rw-r--r-- | plugins/check_curl.d/check_curl_helpers.h | 2 | ||||
| -rw-r--r-- | plugins/check_curl.d/config.h | 6 | ||||
| -rwxr-xr-x | plugins/tests/check_curl.t | 184 |
6 files changed, 233 insertions, 32 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am index cf06c70c..252734a4 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am | |||
| @@ -164,7 +164,7 @@ check_radius_LDADD = $(NETLIBS) $(RADIUSLIBS) | |||
| 164 | check_real_LDADD = $(NETLIBS) | 164 | check_real_LDADD = $(NETLIBS) |
| 165 | check_snmp_SOURCES = check_snmp.c check_snmp.d/check_snmp_helpers.c | 165 | check_snmp_SOURCES = check_snmp.c check_snmp.d/check_snmp_helpers.c |
| 166 | check_snmp_LDADD = $(BASEOBJS) | 166 | check_snmp_LDADD = $(BASEOBJS) |
| 167 | check_snmp_LDFLAGS = $(AM_LDFLAGS) `pkg-config --libs netsnmp` | 167 | check_snmp_LDFLAGS = $(AM_LDFLAGS) -lm `pkg-config --libs netsnmp` |
| 168 | check_snmp_CFLAGS = $(AM_CFLAGS) `pkg-config --cflags netsnmp` | 168 | check_snmp_CFLAGS = $(AM_CFLAGS) `pkg-config --cflags netsnmp` |
| 169 | check_smtp_LDADD = $(SSLOBJS) | 169 | check_smtp_LDADD = $(SSLOBJS) |
| 170 | check_ssh_LDADD = $(NETLIBS) | 170 | check_ssh_LDADD = $(NETLIBS) |
diff --git a/plugins/check_curl.c b/plugins/check_curl.c index 0aff8b40..e7737c7c 100644 --- a/plugins/check_curl.c +++ b/plugins/check_curl.c | |||
| @@ -92,16 +92,16 @@ typedef struct { | |||
| 92 | static check_curl_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/); | 92 | static check_curl_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/); |
| 93 | 93 | ||
| 94 | static mp_subcheck check_http(check_curl_config /*config*/, check_curl_working_state workingState, | 94 | static mp_subcheck check_http(check_curl_config /*config*/, check_curl_working_state workingState, |
| 95 | int redir_depth); | 95 | long redir_depth); |
| 96 | 96 | ||
| 97 | typedef struct { | 97 | typedef struct { |
| 98 | int redir_depth; | 98 | long redir_depth; |
| 99 | check_curl_working_state working_state; | 99 | check_curl_working_state working_state; |
| 100 | int error_code; | 100 | int error_code; |
| 101 | check_curl_global_state curl_state; | 101 | check_curl_global_state curl_state; |
| 102 | } redir_wrapper; | 102 | } redir_wrapper; |
| 103 | static redir_wrapper redir(curlhelp_write_curlbuf * /*header_buf*/, check_curl_config /*config*/, | 103 | static redir_wrapper redir(curlhelp_write_curlbuf * /*header_buf*/, check_curl_config /*config*/, |
| 104 | int redir_depth, check_curl_working_state working_state); | 104 | long redir_depth, check_curl_working_state working_state); |
| 105 | 105 | ||
| 106 | static void print_help(void); | 106 | static void print_help(void); |
| 107 | void print_usage(void); | 107 | void print_usage(void); |
| @@ -198,7 +198,7 @@ CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm) { | |||
| 198 | #endif /* HAVE_SSL */ | 198 | #endif /* HAVE_SSL */ |
| 199 | 199 | ||
| 200 | mp_subcheck check_http(const check_curl_config config, check_curl_working_state workingState, | 200 | mp_subcheck check_http(const check_curl_config config, check_curl_working_state workingState, |
| 201 | int redir_depth) { | 201 | long redir_depth) { |
| 202 | 202 | ||
| 203 | // ======================= | 203 | // ======================= |
| 204 | // Initialisation for curl | 204 | // Initialisation for curl |
| @@ -441,19 +441,19 @@ mp_subcheck check_http(const check_curl_config config, check_curl_working_state | |||
| 441 | "CURLINFO_REDIRECT_COUNT"); | 441 | "CURLINFO_REDIRECT_COUNT"); |
| 442 | 442 | ||
| 443 | if (verbose >= 2) { | 443 | if (verbose >= 2) { |
| 444 | printf(_("* curl LIBINFO_REDIRECT_COUNT is %d\n"), redir_depth); | 444 | printf(_("* curl LIBINFO_REDIRECT_COUNT is %ld\n"), redir_depth); |
| 445 | } | 445 | } |
| 446 | 446 | ||
| 447 | mp_subcheck sc_redir_depth = mp_subcheck_init(); | 447 | mp_subcheck sc_redir_depth = mp_subcheck_init(); |
| 448 | if (redir_depth > config.max_depth) { | 448 | if (redir_depth > config.max_depth) { |
| 449 | xasprintf(&sc_redir_depth.output, | 449 | xasprintf(&sc_redir_depth.output, |
| 450 | "maximum redirection depth %d exceeded in libcurl", | 450 | "maximum redirection depth %ld exceeded in libcurl", |
| 451 | config.max_depth); | 451 | config.max_depth); |
| 452 | sc_redir_depth = mp_set_subcheck_state(sc_redir_depth, STATE_CRITICAL); | 452 | sc_redir_depth = mp_set_subcheck_state(sc_redir_depth, STATE_CRITICAL); |
| 453 | mp_add_subcheck_to_subcheck(&sc_result, sc_redir_depth); | 453 | mp_add_subcheck_to_subcheck(&sc_result, sc_redir_depth); |
| 454 | return sc_result; | 454 | return sc_result; |
| 455 | } | 455 | } |
| 456 | xasprintf(&sc_redir_depth.output, "redirection depth %d (of a maximum %d)", | 456 | xasprintf(&sc_redir_depth.output, "redirection depth %ld (of a maximum %ld)", |
| 457 | redir_depth, config.max_depth); | 457 | redir_depth, config.max_depth); |
| 458 | mp_add_subcheck_to_subcheck(&sc_result, sc_redir_depth); | 458 | mp_add_subcheck_to_subcheck(&sc_result, sc_redir_depth); |
| 459 | 459 | ||
| @@ -653,7 +653,7 @@ char *uri_string(const UriTextRangeA range, char *buf, size_t buflen) { | |||
| 653 | } | 653 | } |
| 654 | 654 | ||
| 655 | redir_wrapper redir(curlhelp_write_curlbuf *header_buf, const check_curl_config config, | 655 | redir_wrapper redir(curlhelp_write_curlbuf *header_buf, const check_curl_config config, |
| 656 | int redir_depth, check_curl_working_state working_state) { | 656 | long redir_depth, check_curl_working_state working_state) { |
| 657 | curlhelp_statusline status_line; | 657 | curlhelp_statusline status_line; |
| 658 | struct phr_header headers[255]; | 658 | struct phr_header headers[255]; |
| 659 | size_t msglen; | 659 | size_t msglen; |
| @@ -678,7 +678,7 @@ redir_wrapper redir(curlhelp_write_curlbuf *header_buf, const check_curl_config | |||
| 678 | } | 678 | } |
| 679 | 679 | ||
| 680 | if (++redir_depth > config.max_depth) { | 680 | if (++redir_depth > config.max_depth) { |
| 681 | die(STATE_WARNING, _("HTTP WARNING - maximum redirection depth %d exceeded - %s\n"), | 681 | die(STATE_WARNING, _("HTTP WARNING - maximum redirection depth %ld exceeded - %s\n"), |
| 682 | config.max_depth, location); | 682 | config.max_depth, location); |
| 683 | } | 683 | } |
| 684 | 684 | ||
| @@ -761,7 +761,7 @@ redir_wrapper redir(curlhelp_write_curlbuf *header_buf, const check_curl_config | |||
| 761 | } | 761 | } |
| 762 | 762 | ||
| 763 | /* compose new path */ | 763 | /* compose new path */ |
| 764 | /* TODO: handle fragments and query part of URL */ | 764 | /* TODO: handle fragments of URL */ |
| 765 | char *new_url = (char *)calloc(1, DEFAULT_BUFFER_SIZE); | 765 | char *new_url = (char *)calloc(1, DEFAULT_BUFFER_SIZE); |
| 766 | if (uri.pathHead) { | 766 | if (uri.pathHead) { |
| 767 | for (UriPathSegmentA *pathSegment = uri.pathHead; pathSegment; | 767 | for (UriPathSegmentA *pathSegment = uri.pathHead; pathSegment; |
| @@ -772,6 +772,25 @@ redir_wrapper redir(curlhelp_write_curlbuf *header_buf, const check_curl_config | |||
| 772 | } | 772 | } |
| 773 | } | 773 | } |
| 774 | 774 | ||
| 775 | /* missing components have null,null in their UriTextRangeA | ||
| 776 | * add query parameters if they exist. | ||
| 777 | */ | ||
| 778 | if (uri.query.first && uri.query.afterLast){ | ||
| 779 | // Ensure we have space for '?' + query_str + '\0' ahead of time, instead of calling strncat twice | ||
| 780 | size_t current_len = strlen(new_url); | ||
| 781 | size_t remaining_space = DEFAULT_BUFFER_SIZE - current_len - 1; | ||
| 782 | |||
| 783 | const char* query_str = uri_string(uri.query, buf, DEFAULT_BUFFER_SIZE); | ||
| 784 | size_t query_str_len = strlen(query_str); | ||
| 785 | |||
| 786 | if (remaining_space >= query_str_len + 1) { | ||
| 787 | strcat(new_url, "?"); | ||
| 788 | strcat(new_url, query_str); | ||
| 789 | }else{ | ||
| 790 | die(STATE_UNKNOWN, _("HTTP UNKNOWN - No space to add query part of size %d to the buffer, buffer has remaining size %d"), query_str_len , current_len ); | ||
| 791 | } | ||
| 792 | } | ||
| 793 | |||
| 775 | if (working_state.serverPort == new_port && | 794 | if (working_state.serverPort == new_port && |
| 776 | !strncmp(working_state.server_address, new_host, MAX_IPV4_HOSTLENGTH) && | 795 | !strncmp(working_state.server_address, new_host, MAX_IPV4_HOSTLENGTH) && |
| 777 | (working_state.host_name && | 796 | (working_state.host_name && |
| @@ -1400,7 +1419,7 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { | |||
| 1400 | } | 1419 | } |
| 1401 | #endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */ | 1420 | #endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */ |
| 1402 | if (verbose >= 2) { | 1421 | if (verbose >= 2) { |
| 1403 | printf(_("* Set SSL/TLS version to %d\n"), result.config.curl_config.ssl_version); | 1422 | printf(_("* Set SSL/TLS version to %ld\n"), result.config.curl_config.ssl_version); |
| 1404 | } | 1423 | } |
| 1405 | if (!specify_port) { | 1424 | if (!specify_port) { |
| 1406 | result.config.initial_config.serverPort = HTTPS_PORT; | 1425 | result.config.initial_config.serverPort = HTTPS_PORT; |
diff --git a/plugins/check_curl.d/check_curl_helpers.c b/plugins/check_curl.d/check_curl_helpers.c index e4e7bef6..7be781fc 100644 --- a/plugins/check_curl.d/check_curl_helpers.c +++ b/plugins/check_curl.d/check_curl_helpers.c | |||
| @@ -19,7 +19,7 @@ bool add_sslctx_verify_fun = false; | |||
| 19 | check_curl_configure_curl_wrapper | 19 | check_curl_configure_curl_wrapper |
| 20 | check_curl_configure_curl(const check_curl_static_curl_config config, | 20 | check_curl_configure_curl(const check_curl_static_curl_config config, |
| 21 | check_curl_working_state working_state, bool check_cert, | 21 | check_curl_working_state working_state, bool check_cert, |
| 22 | bool on_redirect_dependent, int follow_method, int max_depth) { | 22 | bool on_redirect_dependent, int follow_method, long max_depth) { |
| 23 | check_curl_configure_curl_wrapper result = { | 23 | check_curl_configure_curl_wrapper result = { |
| 24 | .errorcode = OK, | 24 | .errorcode = OK, |
| 25 | .curl_state = | 25 | .curl_state = |
| @@ -57,7 +57,7 @@ check_curl_configure_curl(const check_curl_static_curl_config config, | |||
| 57 | result.curl_state.curl_easy_initialized = true; | 57 | result.curl_state.curl_easy_initialized = true; |
| 58 | 58 | ||
| 59 | if (verbose >= 1) { | 59 | if (verbose >= 1) { |
| 60 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_VERBOSE, 1), | 60 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_VERBOSE, 1L), |
| 61 | "CURLOPT_VERBOSE"); | 61 | "CURLOPT_VERBOSE"); |
| 62 | } | 62 | } |
| 63 | 63 | ||
| @@ -214,10 +214,10 @@ check_curl_configure_curl(const check_curl_static_curl_config config, | |||
| 214 | if (working_state.http_method) { | 214 | if (working_state.http_method) { |
| 215 | if (!strcmp(working_state.http_method, "POST")) { | 215 | if (!strcmp(working_state.http_method, "POST")) { |
| 216 | handle_curl_option_return_code( | 216 | handle_curl_option_return_code( |
| 217 | curl_easy_setopt(result.curl_state.curl, CURLOPT_POST, 1), "CURLOPT_POST"); | 217 | curl_easy_setopt(result.curl_state.curl, CURLOPT_POST, 1L), "CURLOPT_POST"); |
| 218 | } else if (!strcmp(working_state.http_method, "PUT")) { | 218 | } else if (!strcmp(working_state.http_method, "PUT")) { |
| 219 | handle_curl_option_return_code( | 219 | handle_curl_option_return_code( |
| 220 | curl_easy_setopt(result.curl_state.curl, CURLOPT_UPLOAD, 1), "CURLOPT_UPLOAD"); | 220 | curl_easy_setopt(result.curl_state.curl, CURLOPT_UPLOAD, 1L), "CURLOPT_UPLOAD"); |
| 221 | } else { | 221 | } else { |
| 222 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, | 222 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, |
| 223 | CURLOPT_CUSTOMREQUEST, | 223 | CURLOPT_CUSTOMREQUEST, |
| @@ -300,10 +300,10 @@ check_curl_configure_curl(const check_curl_static_curl_config config, | |||
| 300 | /* per default if we have a CA verify both the peer and the | 300 | /* per default if we have a CA verify both the peer and the |
| 301 | * hostname in the certificate, can be switched off later */ | 301 | * hostname in the certificate, can be switched off later */ |
| 302 | handle_curl_option_return_code( | 302 | handle_curl_option_return_code( |
| 303 | curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYPEER, 1), | 303 | curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYPEER, 1L), |
| 304 | "CURLOPT_SSL_VERIFYPEER"); | 304 | "CURLOPT_SSL_VERIFYPEER"); |
| 305 | handle_curl_option_return_code( | 305 | handle_curl_option_return_code( |
| 306 | curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYHOST, 2), | 306 | curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYHOST, 2L), |
| 307 | "CURLOPT_SSL_VERIFYHOST"); | 307 | "CURLOPT_SSL_VERIFYHOST"); |
| 308 | } else { | 308 | } else { |
| 309 | /* backward-compatible behaviour, be tolerant in checks | 309 | /* backward-compatible behaviour, be tolerant in checks |
| @@ -311,10 +311,10 @@ check_curl_configure_curl(const check_curl_static_curl_config config, | |||
| 311 | * to be less tolerant about ssl verfications | 311 | * to be less tolerant about ssl verfications |
| 312 | */ | 312 | */ |
| 313 | handle_curl_option_return_code( | 313 | handle_curl_option_return_code( |
| 314 | curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYPEER, 0), | 314 | curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYPEER, 0L), |
| 315 | "CURLOPT_SSL_VERIFYPEER"); | 315 | "CURLOPT_SSL_VERIFYPEER"); |
| 316 | handle_curl_option_return_code( | 316 | handle_curl_option_return_code( |
| 317 | curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYHOST, 0), | 317 | curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYHOST, 0L), |
| 318 | "CURLOPT_SSL_VERIFYHOST"); | 318 | "CURLOPT_SSL_VERIFYHOST"); |
| 319 | } | 319 | } |
| 320 | 320 | ||
| @@ -438,7 +438,7 @@ check_curl_configure_curl(const check_curl_static_curl_config config, | |||
| 438 | if (on_redirect_dependent) { | 438 | if (on_redirect_dependent) { |
| 439 | if (follow_method == FOLLOW_LIBCURL) { | 439 | if (follow_method == FOLLOW_LIBCURL) { |
| 440 | handle_curl_option_return_code( | 440 | handle_curl_option_return_code( |
| 441 | curl_easy_setopt(result.curl_state.curl, CURLOPT_FOLLOWLOCATION, 1), | 441 | curl_easy_setopt(result.curl_state.curl, CURLOPT_FOLLOWLOCATION, 1L), |
| 442 | "CURLOPT_FOLLOWLOCATION"); | 442 | "CURLOPT_FOLLOWLOCATION"); |
| 443 | 443 | ||
| 444 | /* default -1 is infinite, not good, could lead to zombie plugins! | 444 | /* default -1 is infinite, not good, could lead to zombie plugins! |
| @@ -474,7 +474,7 @@ check_curl_configure_curl(const check_curl_static_curl_config config, | |||
| 474 | } | 474 | } |
| 475 | /* no-body */ | 475 | /* no-body */ |
| 476 | if (working_state.no_body) { | 476 | if (working_state.no_body) { |
| 477 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_NOBODY, 1), | 477 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_NOBODY, 1L), |
| 478 | "CURLOPT_NOBODY"); | 478 | "CURLOPT_NOBODY"); |
| 479 | } | 479 | } |
| 480 | 480 | ||
| @@ -796,15 +796,17 @@ mp_subcheck check_document_dates(const curlhelp_write_curlbuf *header_buf, const | |||
| 796 | ((float)last_modified) / (60 * 60 * 24)); | 796 | ((float)last_modified) / (60 * 60 * 24)); |
| 797 | sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL); | 797 | sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL); |
| 798 | } else { | 798 | } else { |
| 799 | xasprintf(&sc_document_dates.output, _("Last modified %ld:%02ld:%02ld ago"), | 799 | xasprintf(&sc_document_dates.output, _("Last modified %lld:%02d:%02d ago"), |
| 800 | last_modified / (60 * 60), (last_modified / 60) % 60, last_modified % 60); | 800 | (long long)last_modified / (60 * 60), (int)(last_modified / 60) % 60, |
| 801 | (int)last_modified % 60); | ||
| 801 | sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL); | 802 | sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL); |
| 802 | } | 803 | } |
| 803 | } else { | 804 | } else { |
| 804 | // TODO is this the OK case? | 805 | // TODO is this the OK case? |
| 805 | time_t last_modified = (srv_data - doc_data); | 806 | time_t last_modified = (srv_data - doc_data); |
| 806 | xasprintf(&sc_document_dates.output, _("Last modified %ld:%02ld:%02ld ago"), | 807 | xasprintf(&sc_document_dates.output, _("Last modified %lld:%02d:%02d ago"), |
| 807 | last_modified / (60 * 60), (last_modified / 60) % 60, last_modified % 60); | 808 | (long long)last_modified / (60 * 60), (int)(last_modified / 60) % 60, |
| 809 | (int)last_modified % 60); | ||
| 808 | sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_OK); | 810 | sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_OK); |
| 809 | } | 811 | } |
| 810 | } | 812 | } |
diff --git a/plugins/check_curl.d/check_curl_helpers.h b/plugins/check_curl.d/check_curl_helpers.h index e7b80f7e..e77b763b 100644 --- a/plugins/check_curl.d/check_curl_helpers.h +++ b/plugins/check_curl.d/check_curl_helpers.h | |||
| @@ -80,7 +80,7 @@ check_curl_configure_curl_wrapper check_curl_configure_curl(check_curl_static_cu | |||
| 80 | check_curl_working_state working_state, | 80 | check_curl_working_state working_state, |
| 81 | bool check_cert, | 81 | bool check_cert, |
| 82 | bool on_redirect_dependent, | 82 | bool on_redirect_dependent, |
| 83 | int follow_method, int max_depth); | 83 | int follow_method, long max_depth); |
| 84 | 84 | ||
| 85 | void handle_curl_option_return_code(CURLcode res, const char *option); | 85 | void handle_curl_option_return_code(CURLcode res, const char *option); |
| 86 | 86 | ||
diff --git a/plugins/check_curl.d/config.h b/plugins/check_curl.d/config.h index f51b2ee9..61067d46 100644 --- a/plugins/check_curl.d/config.h +++ b/plugins/check_curl.d/config.h | |||
| @@ -57,10 +57,10 @@ typedef struct { | |||
| 57 | bool haproxy_protocol; | 57 | bool haproxy_protocol; |
| 58 | long socket_timeout; | 58 | long socket_timeout; |
| 59 | sa_family_t sin_family; | 59 | sa_family_t sin_family; |
| 60 | int curl_http_version; | 60 | long curl_http_version; |
| 61 | char **http_opt_headers; | 61 | char **http_opt_headers; |
| 62 | size_t http_opt_headers_count; | 62 | size_t http_opt_headers_count; |
| 63 | int ssl_version; | 63 | long ssl_version; |
| 64 | char *client_cert; | 64 | char *client_cert; |
| 65 | char *client_privkey; | 65 | char *client_privkey; |
| 66 | char *ca_cert; | 66 | char *ca_cert; |
| @@ -76,7 +76,7 @@ typedef struct { | |||
| 76 | check_curl_working_state initial_config; | 76 | check_curl_working_state initial_config; |
| 77 | 77 | ||
| 78 | check_curl_static_curl_config curl_config; | 78 | check_curl_static_curl_config curl_config; |
| 79 | int max_depth; | 79 | long max_depth; |
| 80 | int followmethod; | 80 | int followmethod; |
| 81 | int followsticky; | 81 | int followsticky; |
| 82 | 82 | ||
diff --git a/plugins/tests/check_curl.t b/plugins/tests/check_curl.t index 52c5ad1c..248eb4c5 100755 --- a/plugins/tests/check_curl.t +++ b/plugins/tests/check_curl.t | |||
| @@ -20,9 +20,14 @@ use Test::More; | |||
| 20 | use NPTest; | 20 | use NPTest; |
| 21 | use FindBin qw($Bin); | 21 | use FindBin qw($Bin); |
| 22 | 22 | ||
| 23 | use URI; | ||
| 24 | use URI::QueryParam; | ||
| 25 | use HTTP::Daemon; | ||
| 26 | use HTTP::Daemon::SSL; | ||
| 27 | |||
| 23 | $ENV{'LC_TIME'} = "C"; | 28 | $ENV{'LC_TIME'} = "C"; |
| 24 | 29 | ||
| 25 | my $common_tests = 75; | 30 | my $common_tests = 95; |
| 26 | my $ssl_only_tests = 8; | 31 | my $ssl_only_tests = 8; |
| 27 | # Check that all dependent modules are available | 32 | # Check that all dependent modules are available |
| 28 | eval "use HTTP::Daemon 6.01;"; | 33 | eval "use HTTP::Daemon 6.01;"; |
| @@ -186,6 +191,123 @@ sub run_server { | |||
| 186 | $c->send_response('moved to /redirect2'); | 191 | $c->send_response('moved to /redirect2'); |
| 187 | } elsif ($r->url->path eq "/redir_timeout") { | 192 | } elsif ($r->url->path eq "/redir_timeout") { |
| 188 | $c->send_redirect( "/timeout" ); | 193 | $c->send_redirect( "/timeout" ); |
| 194 | } elsif ($r->url->path =~ m{^/redirect_with_increment}) { | ||
| 195 | # <scheme>://<username>:<password>@<host>:<port>/<path>;<parameters>?<query>#<fragment> | ||
| 196 | # Find every parameter, query , and fragment keys and increment them | ||
| 197 | |||
| 198 | my $content = ""; | ||
| 199 | |||
| 200 | # Use URI to help with query/fragment; parse path params manually. | ||
| 201 | my $original_url = $r->url->as_string; | ||
| 202 | $content .= " original_url: ${original_url}\n"; | ||
| 203 | my $uri = URI->new($original_url); | ||
| 204 | $content .= " uri: ${uri}\n"; | ||
| 205 | |||
| 206 | my $path = $uri->path // ''; | ||
| 207 | my $query = $uri->query // ''; | ||
| 208 | my $fragment = $uri->fragment // ''; | ||
| 209 | |||
| 210 | $content .= " path: ${path}\n"; | ||
| 211 | $content .= " query: ${query}\n"; | ||
| 212 | $content .= " fragment: ${fragment}\n"; | ||
| 213 | |||
| 214 | # split the URI part and parameters. URI package cannot do this | ||
| 215 | # group 1 is captured: anything without a semicolon: ([^;]*) | ||
| 216 | # group 2 is uncaptured: (?:;(.*))? | ||
| 217 | # (?: ... )? prevents capturing the parameter section | ||
| 218 | # inside group 2, ';' matches the first ever semicolon | ||
| 219 | # group3 is captured: any character string : (.*) | ||
| 220 | # \? matches an actual ? mark, which starts the query parameters | ||
| 221 | my ($before_params, $params) = $uri =~ m{^([^;]*)(?:;(.*))?\?}; | ||
| 222 | $before_params //= ''; | ||
| 223 | $params //= ''; | ||
| 224 | $content .= " before_params: ${before_params}\n"; | ||
| 225 | $content .= " params: ${params}\n"; | ||
| 226 | my @parameter_pairs; | ||
| 227 | if (defined $params && length $params) { | ||
| 228 | for my $p (split /;/, $params) { | ||
| 229 | my ($key,$value) = split /=/, $p, 2; | ||
| 230 | $value //= ''; | ||
| 231 | push @parameter_pairs, [ $key, $value ]; | ||
| 232 | $content .= " parameter: ${key} -> ${value}\n"; | ||
| 233 | } | ||
| 234 | } | ||
| 235 | |||
| 236 | # query parameters are offered directly from the library | ||
| 237 | my @query_form = $uri->query_form; | ||
| 238 | my @query_parameter_pairs; | ||
| 239 | while (@query_form) { | ||
| 240 | my $key = shift @query_form; | ||
| 241 | my $value = shift @query_form; | ||
| 242 | $value //= ''; # there can be valueless keys | ||
| 243 | push @query_parameter_pairs, [ $key, $value ]; | ||
| 244 | $content .= " query: ${key} -> ${value}\n"; | ||
| 245 | } | ||
| 246 | |||
| 247 | # helper to increment value | ||
| 248 | my $increment = sub { | ||
| 249 | my ($v) = @_; | ||
| 250 | return $v if !defined $v || $v eq ''; | ||
| 251 | # numeric integer | ||
| 252 | if ($v =~ /^-?\d+$/) { | ||
| 253 | return $v + 1; | ||
| 254 | } | ||
| 255 | # otherwise -> increment as if its an ascii character | ||
| 256 | # sed replacement syntax, but the $& holds the matched character | ||
| 257 | if (length($v)) { | ||
| 258 | (my $new_v = $v) =~ s/./chr(ord($&) + 1)/ge; | ||
| 259 | return $new_v; | ||
| 260 | } | ||
| 261 | }; | ||
| 262 | |||
| 263 | # increment values in pairs | ||
| 264 | for my $pair (@parameter_pairs) { | ||
| 265 | $pair->[1] = $increment->($pair->[1]); | ||
| 266 | $content .= " parameter new: " . $pair->[0] . " -> " . $pair->[1] . "\n"; | ||
| 267 | } | ||
| 268 | for my $pair (@query_parameter_pairs) { | ||
| 269 | $pair->[1] = $increment->($pair->[1]); | ||
| 270 | $content .= " query parameter new: " . $pair->[0] . " -> " . $pair->[1] . "\n"; | ||
| 271 | } | ||
| 272 | |||
| 273 | # rebuild strings | ||
| 274 | my $new_parameter_str = join(';', map { $_->[0] . '=' . $_->[1] } @parameter_pairs); | ||
| 275 | $content .= " new_parameter_str: ${new_parameter_str}\n"; | ||
| 276 | |||
| 277 | # library can rebuild from an array | ||
| 278 | my @new_query_form; | ||
| 279 | for my $p (@query_parameter_pairs) { push @new_query_form, $p->[0], $p->[1] } | ||
| 280 | |||
| 281 | my $new_fragment_str = ''; | ||
| 282 | for my $pair (@parameter_pairs) { | ||
| 283 | my $key = $pair->[0]; | ||
| 284 | my $value = $pair->[1]; | ||
| 285 | if ($key eq "fragment") { | ||
| 286 | $new_fragment_str = $value | ||
| 287 | } | ||
| 288 | } | ||
| 289 | $content .= " new_fragment_str: ${new_fragment_str}\n"; | ||
| 290 | |||
| 291 | # construct new URI using the library | ||
| 292 | my $new_uri = URI->new(''); | ||
| 293 | $new_uri->path( $before_params . ($new_parameter_str ? ';' . $new_parameter_str : '') ); | ||
| 294 | $new_uri->query_form( \@new_query_form ) if @new_query_form; | ||
| 295 | $new_uri->fragment( $new_fragment_str ) if $new_fragment_str ne ''; | ||
| 296 | $content .= " new_uri: ${new_uri}\n"; | ||
| 297 | |||
| 298 | # Redirect until fail_count or redirect_count reaches 3 | ||
| 299 | if ($new_uri =~ /fail_count=3/){ | ||
| 300 | $c->send_error(HTTP::Status->RC_FORBIDDEN, "fail count reached 3, url path:" . $r->url->path ); | ||
| 301 | } elsif ($new_uri =~ /redirect_count=3/){ | ||
| 302 | $c->send_response(HTTP::Response->new( 200, 'OK', undef , $content )); | ||
| 303 | } elsif ($new_uri =~ /location_redirect_count=3/){ | ||
| 304 | $c->send_basic_header(302); | ||
| 305 | $c->send_header("Location", "$new_uri" ); | ||
| 306 | $c->send_crlf; | ||
| 307 | $c->send_response("$content \n moved to $new_uri"); | ||
| 308 | } else { | ||
| 309 | $c->send_redirect( $new_uri->as_string, 301, $content ); | ||
| 310 | } | ||
| 189 | } elsif ($r->url->path eq "/timeout") { | 311 | } elsif ($r->url->path eq "/timeout") { |
| 190 | # Keep $c from being destroyed, but prevent severe leaks | 312 | # Keep $c from being destroyed, but prevent severe leaks |
| 191 | unshift @persist, $c; | 313 | unshift @persist, $c; |
| @@ -215,7 +337,7 @@ sub run_server { | |||
| 215 | return($chunk); | 337 | return($chunk); |
| 216 | })); | 338 | })); |
| 217 | } else { | 339 | } else { |
| 218 | $c->send_error(HTTP::Status->RC_FORBIDDEN); | 340 | $c->send_error(HTTP::Status->RC_FORBIDDEN, "unknown url path:" . $r->url->path ); |
| 219 | } | 341 | } |
| 220 | $c->close; | 342 | $c->close; |
| 221 | } | 343 | } |
| @@ -482,6 +604,64 @@ sub run_common_tests { | |||
| 482 | is( $result->return_code, 0, $cmd); | 604 | is( $result->return_code, 0, $cmd); |
| 483 | like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); | 605 | like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); |
| 484 | 606 | ||
| 607 | # Redirect with increment tests. These are for checking if the url parameters, query parameters and fragment are parsed. | ||
| 608 | # The server at this point has dynamic redirection. It tries to increment values that it sees in these fields, then redirects. | ||
| 609 | # It also appends some debug log and writes it into HTTP content, pass the -vvv parameter to see them. | ||
| 610 | |||
| 611 | $cmd = "$command -u '/redirect_with_increment/path1/path2/path3/path4' --onredirect=follow -vvv"; | ||
| 612 | $result = NPTest->testCmd( "$cmd" ); | ||
| 613 | is( $result->return_code, 1, $cmd); | ||
| 614 | like( $result->output, '/.*HTTP/1.1 403 Forbidden - \d+ bytes in [\d\.]+ second.*/', "Output correct, redirect_count was not present, got redirected to / : ".$result->output ); | ||
| 615 | |||
| 616 | # redirect_count=0 is parsed as a parameter and incremented. When it goes up to 3, the redirection returns HTTP OK | ||
| 617 | $cmd = "$command -u '/redirect_with_increment/path1/path2;redirect_count=0;p1=1;p2=ab?qp1=10&qp2=kl#f1=test' --onredirect=follow -vvv"; | ||
| 618 | $result = NPTest->testCmd( "$cmd" ); | ||
| 619 | is( $result->return_code, 0, $cmd); | ||
| 620 | like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct, redirect_count went up to 3, and returned OK: ".$result->output ); | ||
| 621 | |||
| 622 | # location_redirect_count=0 goes up to 3, which uses the HTTP 302 style of redirection with 'Location' header | ||
| 623 | $cmd = "$command -u '/redirect_with_increment/path1/path2;location_redirect_count=0;p1=1;p2=ab?qp1=10&qp2=kl#f1=test' --onredirect=follow -vvv"; | ||
| 624 | $result = NPTest->testCmd( "$cmd" ); | ||
| 625 | is( $result->return_code, 0, $cmd); | ||
| 626 | like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct, location_redirect_count went up to 3: ".$result->output ); | ||
| 627 | |||
| 628 | # fail_count parameter may also go up to 3, which returns a HTTP 403 | ||
| 629 | $cmd = "$command -u '/redirect_with_increment/path1/path2;redirect_count=0;fail_count=2' --onredirect=follow -vvv"; | ||
| 630 | $result = NPTest->testCmd( "$cmd" ); | ||
| 631 | is( $result->return_code, 1, $cmd); | ||
| 632 | like( $result->output, '/.*HTTP/1.1 403 Forbidden - \d+ bytes in [\d\.]+ second.*/', "Output correct, early due to fail_count reaching 3: ".$result->output ); | ||
| 633 | |||
| 634 | # redirect_count=0, p1=1 , p2=ab => redirect_count=1, p1=2 , p2=bc => redirect_count=2, p1=3 , p2=cd => redirect_count=3 , p1=4 , p2=de | ||
| 635 | # Last visited URI returns HTTP OK instead of redirect, and the one before that contains the new_uri in its content | ||
| 636 | $cmd = "$command -u '/redirect_with_increment/path1/path2;redirect_count=0;p1=1;p2=ab?qp1=10&qp2=kl#f1=test' --onredirect=follow -vvv"; | ||
| 637 | $result = NPTest->testCmd( "$cmd" ); | ||
| 638 | is( $result->return_code, 0, $cmd); | ||
| 639 | like( $result->output, '/.*redirect_count=3;p1=4;p2=de\?*/', "Output correct, parsed and incremented both parameters p1 and p2 : ".$result->output ); | ||
| 640 | like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct, location_redirect_count went up to 3: ".$result->output ); | ||
| 641 | |||
| 642 | # Same incrementation as before, uses the query parameters that come after the first '?' : qp1 and qp2 | ||
| 643 | $cmd = "$command -u '/redirect_with_increment/path1/path2;redirect_count=0;p1=1;p2=ab?qp1=10&qp2=kl#f1=test' --onredirect=follow -vvv"; | ||
| 644 | $result = NPTest->testCmd( "$cmd" ); | ||
| 645 | is( $result->return_code, 0, $cmd); | ||
| 646 | like( $result->output, '/.*\?qp1=13&qp2=no*/', "Output correct, parsed and incremented both query parameters qp1 and qp2 : ".$result->output ); | ||
| 647 | like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct, location_redirect_count went up to 3: ".$result->output ); | ||
| 648 | |||
| 649 | # Check if the query parameter order is kept intact | ||
| 650 | $cmd = "$command -u '/redirect_with_increment;redirect_count=0;?qp0=0&qp1=1&qp2=2&qp3=3&qp4=4&qp5=5' --onredirect=follow -vvv"; | ||
| 651 | $result = NPTest->testCmd( "$cmd" ); | ||
| 652 | is( $result->return_code, 0, $cmd); | ||
| 653 | like( $result->output, '/.*\?qp0=3&qp1=4&qp2=5&qp3=6&qp4=7&qp5=8*/', "Output correct, parsed and incremented query parameters qp1,qp2,qp3,qp4,qp5 in order : ".$result->output ); | ||
| 654 | like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct, location_redirect_count went up to 3: ".$result->output ); | ||
| 655 | |||
| 656 | # The fragment is passed as another parameter. | ||
| 657 | # During the server redirects the fragment will be set to its value, if such a key is present. | ||
| 658 | # 'ebiil' => 'fcjjm' => 'gdkkn' => 'hello' | ||
| 659 | $cmd = "$command -u '/redirect_with_increment/path1/path2;redirect_count=0;fragment=ebiil?qp1=0' --onredirect=follow -vvv"; | ||
| 660 | $result = NPTest->testCmd( "$cmd" ); | ||
| 661 | is( $result->return_code, 0, $cmd); | ||
| 662 | like( $result->output, '/.*redirect_count=3;fragment=hello\?qp1=3#hello*/', "Output correct, fragments are specified by server and followed by check_curl: ".$result->output ); | ||
| 663 | like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct, location_redirect_count went up to 3: ".$result->output ); | ||
| 664 | |||
| 485 | # These tests may block | 665 | # These tests may block |
| 486 | # stickyport - on full urlS port is set back to 80 otherwise | 666 | # stickyport - on full urlS port is set back to 80 otherwise |
| 487 | $cmd = "$command -f stickyport -u /redir_external -t 5 -s redirected"; | 667 | $cmd = "$command -f stickyport -u /redir_external -t 5 -s redirected"; |
