Fix check_http sending HTTP/1.0 with v1.1 headers (#2638765)
[monitoring-plugins.git] / plugins / check_http.c
blob2f2460c637b53c0604ab6d31c23de961376f4d93
1 /*****************************************************************************
2 *
3 * Nagios check_http plugin
4 *
5 * License: GPL
6 * Copyright (c) 1999-2008 Nagios Plugins Development Team
7 *
8 * Description:
9 *
10 * This file contains the check_http plugin
12 * This plugin tests the HTTP service on the specified host. It can test
13 * normal (http) and secure (https) servers, follow redirects, search for
14 * strings and regular expressions, check connection times, and report on
15 * certificate expiration times.
18 * This program is free software: you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation, either version 3 of the License, or
21 * (at your option) any later version.
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with this program. If not, see <http://www.gnu.org/licenses/>.
32 *****************************************************************************/
34 /* splint -I. -I../../plugins -I../../lib/ -I/usr/kerberos/include/ ../../plugins/check_http.c */
36 const char *progname = "check_http";
37 const char *copyright = "1999-2008";
38 const char *email = "nagiosplug-devel@lists.sourceforge.net";
40 #include "common.h"
41 #include "netutils.h"
42 #include "utils.h"
43 #include "base64.h"
44 #include <ctype.h>
46 #define INPUT_DELIMITER ";"
48 #define HTTP_EXPECT "HTTP/1."
49 enum {
50 MAX_IPV4_HOSTLENGTH = 255,
51 HTTP_PORT = 80,
52 HTTPS_PORT = 443,
53 MAX_PORT = 65535
56 #ifdef HAVE_SSL
57 int check_cert = FALSE;
58 int days_till_exp;
59 char *randbuff;
60 X509 *server_cert;
61 # define my_recv(buf, len) ((use_ssl) ? np_net_ssl_read(buf, len) : read(sd, buf, len))
62 # define my_send(buf, len) ((use_ssl) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
63 #else /* ifndef HAVE_SSL */
64 # define my_recv(buf, len) read(sd, buf, len)
65 # define my_send(buf, len) send(sd, buf, len, 0)
66 #endif /* HAVE_SSL */
67 int no_body = FALSE;
68 int maximum_age = -1;
70 enum {
71 REGS = 2,
72 MAX_RE_SIZE = 256
74 #include "regex.h"
75 regex_t preg;
76 regmatch_t pmatch[REGS];
77 char regexp[MAX_RE_SIZE];
78 char errbuf[MAX_INPUT_BUFFER];
79 int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
80 int errcode;
81 int invert_regex = 0;
83 struct timeval tv;
85 #define HTTP_URL "/"
86 #define CRLF "\r\n"
88 int specify_port = FALSE;
89 int server_port = HTTP_PORT;
90 char server_port_text[6] = "";
91 char server_type[6] = "http";
92 char *server_address;
93 char *host_name;
94 char *server_url;
95 char *user_agent;
96 int server_url_length;
97 int server_expect_yn = 0;
98 char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
99 char string_expect[MAX_INPUT_BUFFER] = "";
100 double warning_time = 0;
101 int check_warning_time = FALSE;
102 double critical_time = 0;
103 int check_critical_time = FALSE;
104 char user_auth[MAX_INPUT_BUFFER] = "";
105 int display_html = FALSE;
106 char **http_opt_headers;
107 int http_opt_headers_count = 0;
108 int onredirect = STATE_OK;
109 int followsticky = 0;
110 int use_ssl = FALSE;
111 int verbose = FALSE;
112 int sd;
113 int min_page_len = 0;
114 int max_page_len = 0;
115 int redir_depth = 0;
116 int max_depth = 15;
117 char *http_method;
118 char *http_post_data;
119 char *http_content_type;
120 char buffer[MAX_INPUT_BUFFER];
122 int process_arguments (int, char **);
123 int check_http (void);
124 void redir (char *pos, char *status_line);
125 int server_type_check(const char *type);
126 int server_port_check(int ssl_flag);
127 char *perfd_time (double microsec);
128 char *perfd_size (int page_len);
129 void print_help (void);
130 void print_usage (void);
133 main (int argc, char **argv)
135 int result = STATE_UNKNOWN;
137 setlocale (LC_ALL, "");
138 bindtextdomain (PACKAGE, LOCALEDIR);
139 textdomain (PACKAGE);
141 /* Set default URL. Must be malloced for subsequent realloc if --onredirect=follow */
142 server_url = strdup(HTTP_URL);
143 server_url_length = strlen(server_url);
144 asprintf (&user_agent, "User-Agent: check_http/v%s (nagios-plugins %s)",
145 NP_VERSION, VERSION);
147 /* Parse extra opts if any */
148 argv=np_extra_opts (&argc, argv, progname);
150 if (process_arguments (argc, argv) == ERROR)
151 usage4 (_("Could not parse arguments"));
153 if (display_html == TRUE)
154 printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">",
155 use_ssl ? "https" : "http", host_name ? host_name : server_address,
156 server_port, server_url);
158 /* initialize alarm signal handling, set socket timeout, start timer */
159 (void) signal (SIGALRM, socket_timeout_alarm_handler);
160 (void) alarm (socket_timeout);
161 gettimeofday (&tv, NULL);
163 result = check_http ();
164 return result;
169 /* process command-line arguments */
171 process_arguments (int argc, char **argv)
173 int c = 1;
174 char *p;
176 enum {
177 INVERT_REGEX = CHAR_MAX + 1
180 int option = 0;
181 static struct option longopts[] = {
182 STD_LONG_OPTS,
183 {"link", no_argument, 0, 'L'},
184 {"nohtml", no_argument, 0, 'n'},
185 {"ssl", no_argument, 0, 'S'},
186 {"post", required_argument, 0, 'P'},
187 {"method", required_argument, 0, 'j'},
188 {"IP-address", required_argument, 0, 'I'},
189 {"url", required_argument, 0, 'u'},
190 {"port", required_argument, 0, 'p'},
191 {"authorization", required_argument, 0, 'a'},
192 {"string", required_argument, 0, 's'},
193 {"expect", required_argument, 0, 'e'},
194 {"regex", required_argument, 0, 'r'},
195 {"ereg", required_argument, 0, 'r'},
196 {"eregi", required_argument, 0, 'R'},
197 {"linespan", no_argument, 0, 'l'},
198 {"onredirect", required_argument, 0, 'f'},
199 {"certificate", required_argument, 0, 'C'},
200 {"useragent", required_argument, 0, 'A'},
201 {"header", required_argument, 0, 'k'},
202 {"no-body", no_argument, 0, 'N'},
203 {"max-age", required_argument, 0, 'M'},
204 {"content-type", required_argument, 0, 'T'},
205 {"pagesize", required_argument, 0, 'm'},
206 {"invert-regex", no_argument, NULL, INVERT_REGEX},
207 {"use-ipv4", no_argument, 0, '4'},
208 {"use-ipv6", no_argument, 0, '6'},
209 {0, 0, 0, 0}
212 if (argc < 2)
213 return ERROR;
215 for (c = 1; c < argc; c++) {
216 if (strcmp ("-to", argv[c]) == 0)
217 strcpy (argv[c], "-t");
218 if (strcmp ("-hn", argv[c]) == 0)
219 strcpy (argv[c], "-H");
220 if (strcmp ("-wt", argv[c]) == 0)
221 strcpy (argv[c], "-w");
222 if (strcmp ("-ct", argv[c]) == 0)
223 strcpy (argv[c], "-c");
224 if (strcmp ("-nohtml", argv[c]) == 0)
225 strcpy (argv[c], "-n");
228 while (1) {
229 c = getopt_long (argc, argv, "Vvh46t:c:w:A:k:H:P:j:T:I:a:e:p:s:R:r:u:f:C:nlLSm:M:N", longopts, &option);
230 if (c == -1 || c == EOF)
231 break;
233 switch (c) {
234 case '?': /* usage */
235 usage5 ();
236 break;
237 case 'h': /* help */
238 print_help ();
239 exit (STATE_OK);
240 break;
241 case 'V': /* version */
242 print_revision (progname, NP_VERSION);
243 exit (STATE_OK);
244 break;
245 case 't': /* timeout period */
246 if (!is_intnonneg (optarg))
247 usage2 (_("Timeout interval must be a positive integer"), optarg);
248 else
249 socket_timeout = atoi (optarg);
250 break;
251 case 'c': /* critical time threshold */
252 if (!is_nonnegative (optarg))
253 usage2 (_("Critical threshold must be integer"), optarg);
254 else {
255 critical_time = strtod (optarg, NULL);
256 check_critical_time = TRUE;
258 break;
259 case 'w': /* warning time threshold */
260 if (!is_nonnegative (optarg))
261 usage2 (_("Warning threshold must be integer"), optarg);
262 else {
263 warning_time = strtod (optarg, NULL);
264 check_warning_time = TRUE;
266 break;
267 case 'A': /* User Agent String */
268 asprintf (&user_agent, "User-Agent: %s", optarg);
269 break;
270 case 'k': /* Additional headers */
271 if (http_opt_headers_count == 0)
272 http_opt_headers = malloc (sizeof (char *) * (++http_opt_headers_count));
273 else
274 http_opt_headers = realloc (http_opt_headers, sizeof (char *) * (++http_opt_headers_count));
275 http_opt_headers[http_opt_headers_count - 1] = optarg;
276 /* asprintf (&http_opt_headers, "%s", optarg); */
277 break;
278 case 'L': /* show html link */
279 display_html = TRUE;
280 break;
281 case 'n': /* do not show html link */
282 display_html = FALSE;
283 break;
284 case 'C': /* Check SSL cert validity */
285 #ifdef HAVE_SSL
286 if (!is_intnonneg (optarg))
287 usage2 (_("Invalid certificate expiration period"), optarg);
288 else {
289 days_till_exp = atoi (optarg);
290 check_cert = TRUE;
292 /* Fall through to -S option */
293 #endif
294 case 'S': /* use SSL */
295 #ifndef HAVE_SSL
296 usage4 (_("Invalid option - SSL is not available"));
297 #endif
298 use_ssl = TRUE;
299 if (specify_port == FALSE)
300 server_port = HTTPS_PORT;
301 break;
302 case 'f': /* onredirect */
303 if (!strcmp (optarg, "sticky"))
304 onredirect = STATE_DEPENDENT, followsticky = 1;
305 if (!strcmp (optarg, "follow"))
306 onredirect = STATE_DEPENDENT, followsticky = 0;
307 if (!strcmp (optarg, "unknown"))
308 onredirect = STATE_UNKNOWN;
309 if (!strcmp (optarg, "ok"))
310 onredirect = STATE_OK;
311 if (!strcmp (optarg, "warning"))
312 onredirect = STATE_WARNING;
313 if (!strcmp (optarg, "critical"))
314 onredirect = STATE_CRITICAL;
315 if (verbose)
316 printf(_("option f:%d \n"), onredirect);
317 break;
318 /* Note: H, I, and u must be malloc'd or will fail on redirects */
319 case 'H': /* Host Name (virtual host) */
320 host_name = strdup (optarg);
321 if (host_name[0] == '[') {
322 if ((p = strstr (host_name, "]:")) != NULL) /* [IPv6]:port */
323 server_port = atoi (p + 2);
324 } else if ((p = strchr (host_name, ':')) != NULL
325 && strchr (++p, ':') == NULL) /* IPv4:port or host:port */
326 server_port = atoi (p);
327 break;
328 case 'I': /* Server IP-address */
329 server_address = strdup (optarg);
330 break;
331 case 'u': /* URL path */
332 server_url = strdup (optarg);
333 server_url_length = strlen (server_url);
334 break;
335 case 'p': /* Server port */
336 if (!is_intnonneg (optarg))
337 usage2 (_("Invalid port number"), optarg);
338 else {
339 server_port = atoi (optarg);
340 specify_port = TRUE;
342 break;
343 case 'a': /* authorization info */
344 strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1);
345 user_auth[MAX_INPUT_BUFFER - 1] = 0;
346 break;
347 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */
348 if (! http_post_data)
349 http_post_data = strdup (optarg);
350 if (! http_method)
351 http_method = strdup("POST");
352 break;
353 case 'j': /* Set HTTP method */
354 if (http_method)
355 free(http_method);
356 http_method = strdup (optarg);
357 break;
358 case 's': /* string or substring */
359 strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1);
360 string_expect[MAX_INPUT_BUFFER - 1] = 0;
361 break;
362 case 'e': /* string or substring */
363 strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1);
364 server_expect[MAX_INPUT_BUFFER - 1] = 0;
365 server_expect_yn = 1;
366 break;
367 case 'T': /* Content-type */
368 asprintf (&http_content_type, "%s", optarg);
369 break;
370 case 'l': /* linespan */
371 cflags &= ~REG_NEWLINE;
372 break;
373 case 'R': /* regex */
374 cflags |= REG_ICASE;
375 case 'r': /* regex */
376 strncpy (regexp, optarg, MAX_RE_SIZE - 1);
377 regexp[MAX_RE_SIZE - 1] = 0;
378 errcode = regcomp (&preg, regexp, cflags);
379 if (errcode != 0) {
380 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
381 printf (_("Could Not Compile Regular Expression: %s"), errbuf);
382 return ERROR;
384 break;
385 case INVERT_REGEX:
386 invert_regex = 1;
387 break;
388 case '4':
389 address_family = AF_INET;
390 break;
391 case '6':
392 #ifdef USE_IPV6
393 address_family = AF_INET6;
394 #else
395 usage4 (_("IPv6 support not available"));
396 #endif
397 break;
398 case 'v': /* verbose */
399 verbose = TRUE;
400 break;
401 case 'm': /* min_page_length */
403 char *tmp;
404 if (strchr(optarg, ':') != (char *)NULL) {
405 /* range, so get two values, min:max */
406 tmp = strtok(optarg, ":");
407 if (tmp == NULL) {
408 printf("Bad format: try \"-m min:max\"\n");
409 exit (STATE_WARNING);
410 } else
411 min_page_len = atoi(tmp);
413 tmp = strtok(NULL, ":");
414 if (tmp == NULL) {
415 printf("Bad format: try \"-m min:max\"\n");
416 exit (STATE_WARNING);
417 } else
418 max_page_len = atoi(tmp);
419 } else
420 min_page_len = atoi (optarg);
421 break;
423 case 'N': /* no-body */
424 no_body = TRUE;
425 break;
426 case 'M': /* max-age */
428 int L = strlen(optarg);
429 if (L && optarg[L-1] == 'm')
430 maximum_age = atoi (optarg) * 60;
431 else if (L && optarg[L-1] == 'h')
432 maximum_age = atoi (optarg) * 60 * 60;
433 else if (L && optarg[L-1] == 'd')
434 maximum_age = atoi (optarg) * 60 * 60 * 24;
435 else if (L && (optarg[L-1] == 's' ||
436 isdigit (optarg[L-1])))
437 maximum_age = atoi (optarg);
438 else {
439 fprintf (stderr, "unparsable max-age: %s\n", optarg);
440 exit (STATE_WARNING);
443 break;
447 c = optind;
449 if (server_address == NULL && c < argc)
450 server_address = strdup (argv[c++]);
452 if (host_name == NULL && c < argc)
453 host_name = strdup (argv[c++]);
455 if (server_address == NULL) {
456 if (host_name == NULL)
457 usage4 (_("You must specify a server address or host name"));
458 else
459 server_address = strdup (host_name);
462 if (check_critical_time && critical_time>(double)socket_timeout)
463 socket_timeout = (int)critical_time + 1;
465 if (http_method == NULL)
466 http_method = strdup ("GET");
468 return TRUE;
473 /* Returns 1 if we're done processing the document body; 0 to keep going */
474 static int
475 document_headers_done (char *full_page)
477 const char *body;
479 for (body = full_page; *body; body++) {
480 if (!strncmp (body, "\n\n", 2) || !strncmp (body, "\n\r\n", 3))
481 break;
484 if (!*body)
485 return 0; /* haven't read end of headers yet */
487 full_page[body - full_page] = 0;
488 return 1;
491 static time_t
492 parse_time_string (const char *string)
494 struct tm tm;
495 time_t t;
496 memset (&tm, 0, sizeof(tm));
498 /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */
500 if (isupper (string[0]) && /* Tue */
501 islower (string[1]) &&
502 islower (string[2]) &&
503 ',' == string[3] &&
504 ' ' == string[4] &&
505 (isdigit(string[5]) || string[5] == ' ') && /* 25 */
506 isdigit (string[6]) &&
507 ' ' == string[7] &&
508 isupper (string[8]) && /* Dec */
509 islower (string[9]) &&
510 islower (string[10]) &&
511 ' ' == string[11] &&
512 isdigit (string[12]) && /* 2001 */
513 isdigit (string[13]) &&
514 isdigit (string[14]) &&
515 isdigit (string[15]) &&
516 ' ' == string[16] &&
517 isdigit (string[17]) && /* 02: */
518 isdigit (string[18]) &&
519 ':' == string[19] &&
520 isdigit (string[20]) && /* 59: */
521 isdigit (string[21]) &&
522 ':' == string[22] &&
523 isdigit (string[23]) && /* 03 */
524 isdigit (string[24]) &&
525 ' ' == string[25] &&
526 'G' == string[26] && /* GMT */
527 'M' == string[27] && /* GMT */
528 'T' == string[28]) {
530 tm.tm_sec = 10 * (string[23]-'0') + (string[24]-'0');
531 tm.tm_min = 10 * (string[20]-'0') + (string[21]-'0');
532 tm.tm_hour = 10 * (string[17]-'0') + (string[18]-'0');
533 tm.tm_mday = 10 * (string[5] == ' ' ? 0 : string[5]-'0') + (string[6]-'0');
534 tm.tm_mon = (!strncmp (string+8, "Jan", 3) ? 0 :
535 !strncmp (string+8, "Feb", 3) ? 1 :
536 !strncmp (string+8, "Mar", 3) ? 2 :
537 !strncmp (string+8, "Apr", 3) ? 3 :
538 !strncmp (string+8, "May", 3) ? 4 :
539 !strncmp (string+8, "Jun", 3) ? 5 :
540 !strncmp (string+8, "Jul", 3) ? 6 :
541 !strncmp (string+8, "Aug", 3) ? 7 :
542 !strncmp (string+8, "Sep", 3) ? 8 :
543 !strncmp (string+8, "Oct", 3) ? 9 :
544 !strncmp (string+8, "Nov", 3) ? 10 :
545 !strncmp (string+8, "Dec", 3) ? 11 :
546 -1);
547 tm.tm_year = ((1000 * (string[12]-'0') +
548 100 * (string[13]-'0') +
549 10 * (string[14]-'0') +
550 (string[15]-'0'))
551 - 1900);
553 tm.tm_isdst = 0; /* GMT is never in DST, right? */
555 if (tm.tm_mon < 0 || tm.tm_mday < 1 || tm.tm_mday > 31)
556 return 0;
559 This is actually wrong: we need to subtract the local timezone
560 offset from GMT from this value. But, that's ok in this usage,
561 because we only comparing these two GMT dates against each other,
562 so it doesn't matter what time zone we parse them in.
565 t = mktime (&tm);
566 if (t == (time_t) -1) t = 0;
568 if (verbose) {
569 const char *s = string;
570 while (*s && *s != '\r' && *s != '\n')
571 fputc (*s++, stdout);
572 printf (" ==> %lu\n", (unsigned long) t);
575 return t;
577 } else {
578 return 0;
582 /* Checks if the server 'reply' is one of the expected 'statuscodes' */
583 static int
584 expected_statuscode (const char *reply, const char *statuscodes)
586 char *expected, *code;
587 int result = 0;
589 if ((expected = strdup (statuscodes)) == NULL)
590 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
592 for (code = strtok (expected, ","); code != NULL; code = strtok (NULL, ","))
593 if (strstr (reply, code) != NULL) {
594 result = 1;
595 break;
598 free (expected);
599 return result;
602 static int
603 check_document_dates (const char *headers, char **msg)
605 const char *s;
606 char *server_date = 0;
607 char *document_date = 0;
608 int date_result = STATE_OK;
610 s = headers;
611 while (*s) {
612 const char *field = s;
613 const char *value = 0;
615 /* Find the end of the header field */
616 while (*s && !isspace(*s) && *s != ':')
617 s++;
619 /* Remember the header value, if any. */
620 if (*s == ':')
621 value = ++s;
623 /* Skip to the end of the header, including continuation lines. */
624 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
625 s++;
627 /* Avoid stepping over end-of-string marker */
628 if (*s)
629 s++;
631 /* Process this header. */
632 if (value && value > field+2) {
633 char *ff = (char *) malloc (value-field);
634 char *ss = ff;
635 while (field < value-1)
636 *ss++ = tolower(*field++);
637 *ss++ = 0;
639 if (!strcmp (ff, "date") || !strcmp (ff, "last-modified")) {
640 const char *e;
641 while (*value && isspace (*value))
642 value++;
643 for (e = value; *e && *e != '\r' && *e != '\n'; e++)
645 ss = (char *) malloc (e - value + 1);
646 strncpy (ss, value, e - value);
647 ss[e - value] = 0;
648 if (!strcmp (ff, "date")) {
649 if (server_date) free (server_date);
650 server_date = ss;
651 } else {
652 if (document_date) free (document_date);
653 document_date = ss;
656 free (ff);
660 /* Done parsing the body. Now check the dates we (hopefully) parsed. */
661 if (!server_date || !*server_date) {
662 asprintf (msg, _("%sServer date unknown, "), *msg);
663 date_result = max_state_alt(STATE_UNKNOWN, date_result);
664 } else if (!document_date || !*document_date) {
665 asprintf (msg, _("%sDocument modification date unknown, "), *msg);
666 date_result = max_state_alt(STATE_CRITICAL, date_result);
667 } else {
668 time_t srv_data = parse_time_string (server_date);
669 time_t doc_data = parse_time_string (document_date);
671 if (srv_data <= 0) {
672 asprintf (msg, _("%sServer date \"%100s\" unparsable, "), *msg, server_date);
673 date_result = max_state_alt(STATE_CRITICAL, date_result);
674 } else if (doc_data <= 0) {
675 asprintf (msg, _("%sDocument date \"%100s\" unparsable, "), *msg, document_date);
676 date_result = max_state_alt(STATE_CRITICAL, date_result);
677 } else if (doc_data > srv_data + 30) {
678 asprintf (msg, _("%sDocument is %d seconds in the future, "), *msg, (int)doc_data - (int)srv_data);
679 date_result = max_state_alt(STATE_CRITICAL, date_result);
680 } else if (doc_data < srv_data - maximum_age) {
681 int n = (srv_data - doc_data);
682 if (n > (60 * 60 * 24 * 2)) {
683 asprintf (msg, _("%sLast modified %.1f days ago, "), *msg, ((float) n) / (60 * 60 * 24));
684 date_result = max_state_alt(STATE_CRITICAL, date_result);
685 } else {
686 asprintf (msg, _("%sLast modified %d:%02d:%02d ago, "), *msg, n / (60 * 60), (n / 60) % 60, n % 60);
687 date_result = max_state_alt(STATE_CRITICAL, date_result);
690 free (server_date);
691 free (document_date);
693 return date_result;
697 get_content_length (const char *headers)
699 const char *s;
700 int content_length = 0;
702 s = headers;
703 while (*s) {
704 const char *field = s;
705 const char *value = 0;
707 /* Find the end of the header field */
708 while (*s && !isspace(*s) && *s != ':')
709 s++;
711 /* Remember the header value, if any. */
712 if (*s == ':')
713 value = ++s;
715 /* Skip to the end of the header, including continuation lines. */
716 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
717 s++;
718 s++;
720 /* Process this header. */
721 if (value && value > field+2) {
722 char *ff = (char *) malloc (value-field);
723 char *ss = ff;
724 while (field < value-1)
725 *ss++ = tolower(*field++);
726 *ss++ = 0;
728 if (!strcmp (ff, "content-length")) {
729 const char *e;
730 while (*value && isspace (*value))
731 value++;
732 for (e = value; *e && *e != '\r' && *e != '\n'; e++)
734 ss = (char *) malloc (e - value + 1);
735 strncpy (ss, value, e - value);
736 ss[e - value] = 0;
737 content_length = atoi(ss);
738 free (ss);
740 free (ff);
743 return (content_length);
746 char *
747 prepend_slash (char *path)
749 char *newpath;
751 if (path[0] == '/')
752 return path;
754 if ((newpath = malloc (strlen(path) + 2)) == NULL)
755 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
756 newpath[0] = '/';
757 strcpy (newpath + 1, path);
758 free (path);
759 return newpath;
763 check_http (void)
765 char *msg;
766 char *status_line;
767 char *status_code;
768 char *header;
769 char *page;
770 char *auth;
771 int http_status;
772 int i = 0;
773 size_t pagesize = 0;
774 char *full_page;
775 char *buf;
776 char *pos;
777 long microsec;
778 double elapsed_time;
779 int page_len = 0;
780 int result = STATE_OK;
782 /* try to connect to the host at the given port number */
783 if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
784 die (STATE_CRITICAL, _("HTTP CRITICAL - Unable to open TCP socket\n"));
785 #ifdef HAVE_SSL
786 if (use_ssl == TRUE) {
787 np_net_ssl_init(sd);
788 if (check_cert == TRUE) {
789 result = np_net_ssl_check_cert(days_till_exp);
790 np_net_ssl_cleanup();
791 if (sd) close(sd);
792 return result;
795 #endif /* HAVE_SSL */
797 asprintf (&buf, "%s %s %s\r\n%s\r\n", http_method, server_url, host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent);
799 /* tell HTTP/1.1 servers not to keep the connection alive */
800 asprintf (&buf, "%sConnection: close\r\n", buf);
802 /* optionally send the host header info */
803 if (host_name) {
805 * Specify the port only if we're using a non-default port (see RFC 2616,
806 * 14.23). Some server applications/configurations cause trouble if the
807 * (default) port is explicitly specified in the "Host:" header line.
809 if ((use_ssl == FALSE && server_port == HTTP_PORT) ||
810 (use_ssl == TRUE && server_port == HTTPS_PORT))
811 asprintf (&buf, "%sHost: %s\r\n", buf, host_name);
812 else
813 asprintf (&buf, "%sHost: %s:%d\r\n", buf, host_name, server_port);
816 /* optionally send any other header tag */
817 if (http_opt_headers_count) {
818 for (i = 0; i < http_opt_headers_count ; i++) {
819 for ((pos = strtok(http_opt_headers[i], INPUT_DELIMITER)); pos; (pos = strtok(NULL, INPUT_DELIMITER)))
820 asprintf (&buf, "%s%s\r\n", buf, pos);
822 /* This cannot be free'd here because a redirection will then try to access this and segfault */
823 /* Covered in a testcase in tests/check_http.t */
824 /* free(http_opt_headers); */
827 /* optionally send the authentication info */
828 if (strlen(user_auth)) {
829 base64_encode_alloc (user_auth, strlen (user_auth), &auth);
830 asprintf (&buf, "%sAuthorization: Basic %s\r\n", buf, auth);
833 /* either send http POST data (any data, not only POST)*/
834 if (http_post_data) {
835 if (http_content_type) {
836 asprintf (&buf, "%sContent-Type: %s\r\n", buf, http_content_type);
837 } else {
838 asprintf (&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf);
841 asprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data));
842 asprintf (&buf, "%s%s%s", buf, http_post_data, CRLF);
844 else {
845 /* or just a newline so the server knows we're done with the request */
846 asprintf (&buf, "%s%s", buf, CRLF);
849 if (verbose) printf ("%s\n", buf);
850 my_send (buf, strlen (buf));
852 /* fetch the page */
853 full_page = strdup("");
854 while ((i = my_recv (buffer, MAX_INPUT_BUFFER-1)) > 0) {
855 buffer[i] = '\0';
856 asprintf (&full_page, "%s%s", full_page, buffer);
857 pagesize += i;
859 if (no_body && document_headers_done (full_page)) {
860 i = 0;
861 break;
865 if (i < 0 && errno != ECONNRESET) {
866 #ifdef HAVE_SSL
868 if (use_ssl) {
869 sslerr=SSL_get_error(ssl, i);
870 if ( sslerr == SSL_ERROR_SSL ) {
871 die (STATE_WARNING, _("HTTP WARNING - Client Certificate Required\n"));
872 } else {
873 die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
876 else {
878 #endif
879 die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
880 #ifdef HAVE_SSL
881 /* XXX
884 #endif
887 /* return a CRITICAL status if we couldn't read any data */
888 if (pagesize == (size_t) 0)
889 die (STATE_CRITICAL, _("HTTP CRITICAL - No data received from host\n"));
891 /* close the connection */
892 #ifdef HAVE_SSL
893 np_net_ssl_cleanup();
894 #endif
895 if (sd) close(sd);
897 /* reset the alarm */
898 alarm (0);
900 /* Save check time */
901 microsec = deltime (tv);
902 elapsed_time = (double)microsec / 1.0e6;
904 /* leave full_page untouched so we can free it later */
905 page = full_page;
907 if (verbose)
908 printf ("%s://%s:%d%s is %d characters\n",
909 use_ssl ? "https" : "http", server_address,
910 server_port, server_url, (int)pagesize);
912 /* find status line and null-terminate it */
913 status_line = page;
914 page += (size_t) strcspn (page, "\r\n");
915 pos = page;
916 page += (size_t) strspn (page, "\r\n");
917 status_line[strcspn(status_line, "\r\n")] = 0;
918 strip (status_line);
919 if (verbose)
920 printf ("STATUS: %s\n", status_line);
922 /* find header info and null-terminate it */
923 header = page;
924 while (strcspn (page, "\r\n") > 0) {
925 page += (size_t) strcspn (page, "\r\n");
926 pos = page;
927 if ((strspn (page, "\r") == 1 && strspn (page, "\r\n") >= 2) ||
928 (strspn (page, "\n") == 1 && strspn (page, "\r\n") >= 2))
929 page += (size_t) 2;
930 else
931 page += (size_t) 1;
933 page += (size_t) strspn (page, "\r\n");
934 header[pos - header] = 0;
935 if (verbose)
936 printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header,
937 (no_body ? " [[ skipped ]]" : page));
939 /* make sure the status line matches the response we are looking for */
940 if (!expected_statuscode (status_line, server_expect)) {
941 if (server_port == HTTP_PORT)
942 asprintf (&msg,
943 _("Invalid HTTP response received from host: %s\n"),
944 status_line);
945 else
946 asprintf (&msg,
947 _("Invalid HTTP response received from host on port %d: %s\n"),
948 server_port, status_line);
949 die (STATE_CRITICAL, "HTTP CRITICAL - %s", msg);
952 /* Bypass normal status line check if server_expect was set by user and not default */
953 /* NOTE: After this if/else block msg *MUST* be an asprintf-allocated string */
954 if ( server_expect_yn ) {
955 asprintf (&msg,
956 _("Status line output matched \"%s\" - "), server_expect);
957 if (verbose)
958 printf ("%s\n",msg);
960 else {
961 /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
962 /* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
963 /* Status-Code = 3 DIGITS */
965 status_code = strchr (status_line, ' ') + sizeof (char);
966 if (strspn (status_code, "1234567890") != 3)
967 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line);
969 http_status = atoi (status_code);
971 /* check the return code */
973 if (http_status >= 600 || http_status < 100) {
974 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line);
976 /* server errors result in a critical state */
977 else if (http_status >= 500) {
978 asprintf (&msg, _("%s - "), status_line);
979 result = STATE_CRITICAL;
981 /* client errors result in a warning state */
982 else if (http_status >= 400) {
983 asprintf (&msg, _("%s - "), status_line);
984 result = max_state_alt(STATE_WARNING, result);
986 /* check redirected page if specified */
987 else if (http_status >= 300) {
989 if (onredirect == STATE_DEPENDENT)
990 redir (header, status_line);
991 else
992 result = max_state_alt(onredirect, result);
993 asprintf (&msg, _("%s - "), status_line);
994 } /* end if (http_status >= 300) */
995 else {
996 /* Print OK status anyway */
997 asprintf (&msg, _("%s - "), status_line);
1000 } /* end else (server_expect_yn) */
1002 if (maximum_age >= 0) {
1003 result = max_state_alt(check_document_dates(header, &msg), result);
1006 /* Page and Header content checks go here */
1008 if (strlen (string_expect)) {
1009 if (!strstr (page, string_expect)) {
1010 asprintf (&msg, _("%sstring not found, "), msg);
1011 result = STATE_CRITICAL;
1015 if (strlen (regexp)) {
1016 errcode = regexec (&preg, page, REGS, pmatch, 0);
1017 if ((errcode == 0 && invert_regex == 0) || (errcode == REG_NOMATCH && invert_regex == 1)) {
1018 /* OK - No-op to avoid changing the logic around it */
1019 result = max_state_alt(STATE_OK, result);
1021 else if ((errcode == REG_NOMATCH && invert_regex == 0) || (errcode == 0 && invert_regex == 1)) {
1022 if (invert_regex == 0)
1023 asprintf (&msg, _("%spattern not found, "), msg);
1024 else
1025 asprintf (&msg, _("%spattern found, "), msg);
1026 result = STATE_CRITICAL;
1028 else {
1029 /* FIXME: Shouldn't that be UNKNOWN? */
1030 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1031 asprintf (&msg, _("%sExecute Error: %s, "), msg, errbuf);
1032 result = STATE_CRITICAL;
1036 /* make sure the page is of an appropriate size */
1037 /* page_len = get_content_length(header); */
1038 /* FIXME: Will this work with -N ? IMHO we should use
1039 * get_content_length(header) and always check if it's different than the
1040 * returned pagesize
1042 /* FIXME: IIRC pagesize returns headers - shouldn't we make
1043 * it == get_content_length(header) ??
1045 page_len = pagesize;
1046 if ((max_page_len > 0) && (page_len > max_page_len)) {
1047 asprintf (&msg, _("%spage size %d too large, "), msg, page_len);
1048 result = max_state_alt(STATE_WARNING, result);
1049 } else if ((min_page_len > 0) && (page_len < min_page_len)) {
1050 asprintf (&msg, _("%spage size %d too small, "), msg, page_len);
1051 result = max_state_alt(STATE_WARNING, result);
1054 /* Cut-off trailing characters */
1055 if(msg[strlen(msg)-2] == ',')
1056 msg[strlen(msg)-2] = '\0';
1057 else
1058 msg[strlen(msg)-3] = '\0';
1060 /* check elapsed time */
1061 asprintf (&msg,
1062 _("%s - %d bytes in %.3f second response time %s|%s %s"),
1063 msg, page_len, elapsed_time,
1064 (display_html ? "</A>" : ""),
1065 perfd_time (elapsed_time), perfd_size (page_len));
1067 if (check_critical_time == TRUE && elapsed_time > critical_time)
1068 result = STATE_CRITICAL;
1069 if (check_warning_time == TRUE && elapsed_time > warning_time)
1070 result = max_state_alt(STATE_WARNING, result);
1072 die (result, "HTTP %s: %s\n", state_text(result), msg);
1073 /* die failed? */
1074 return STATE_UNKNOWN;
1079 /* per RFC 2396 */
1080 #define URI_HTTP "%5[HTPShtps]"
1081 #define URI_HOST "%255[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1082 #define URI_PORT "%6d" /* MAX_PORT's width is 5 chars, 6 to detect overflow */
1083 #define URI_PATH "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1084 #define HD1 URI_HTTP "://" URI_HOST ":" URI_PORT "/" URI_PATH
1085 #define HD2 URI_HTTP "://" URI_HOST "/" URI_PATH
1086 #define HD3 URI_HTTP "://" URI_HOST ":" URI_PORT
1087 #define HD4 URI_HTTP "://" URI_HOST
1088 #define HD5 URI_PATH
1090 void
1091 redir (char *pos, char *status_line)
1093 int i = 0;
1094 char *x;
1095 char xx[2];
1096 char type[6];
1097 char *addr;
1098 char *url;
1100 addr = malloc (MAX_IPV4_HOSTLENGTH + 1);
1101 if (addr == NULL)
1102 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate addr\n"));
1104 url = malloc (strcspn (pos, "\r\n"));
1105 if (url == NULL)
1106 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
1108 while (pos) {
1109 sscanf (pos, "%1[Ll]%*1[Oo]%*1[Cc]%*1[Aa]%*1[Tt]%*1[Ii]%*1[Oo]%*1[Nn]:%n", xx, &i);
1110 if (i == 0) {
1111 pos += (size_t) strcspn (pos, "\r\n");
1112 pos += (size_t) strspn (pos, "\r\n");
1113 if (strlen(pos) == 0)
1114 die (STATE_UNKNOWN,
1115 _("HTTP UNKNOWN - Could not find redirect location - %s%s\n"),
1116 status_line, (display_html ? "</A>" : ""));
1117 continue;
1120 pos += i;
1121 pos += strspn (pos, " \t");
1124 * RFC 2616 (4.2): ``Header fields can be extended over multiple lines by
1125 * preceding each extra line with at least one SP or HT.''
1127 for (; (i = strspn (pos, "\r\n")); pos += i) {
1128 pos += i;
1129 if (!(i = strspn (pos, " \t"))) {
1130 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Empty redirect location%s\n"),
1131 display_html ? "</A>" : "");
1135 url = realloc (url, strcspn (pos, "\r\n") + 1);
1136 if (url == NULL)
1137 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
1139 /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
1140 if (sscanf (pos, HD1, type, addr, &i, url) == 4) {
1141 url = prepend_slash (url);
1142 use_ssl = server_type_check (type);
1145 /* URI_HTTP URI_HOST URI_PATH */
1146 else if (sscanf (pos, HD2, type, addr, url) == 3 ) {
1147 url = prepend_slash (url);
1148 use_ssl = server_type_check (type);
1149 i = server_port_check (use_ssl);
1152 /* URI_HTTP URI_HOST URI_PORT */
1153 else if (sscanf (pos, HD3, type, addr, &i) == 3) {
1154 strcpy (url, HTTP_URL);
1155 use_ssl = server_type_check (type);
1158 /* URI_HTTP URI_HOST */
1159 else if (sscanf (pos, HD4, type, addr) == 2) {
1160 strcpy (url, HTTP_URL);
1161 use_ssl = server_type_check (type);
1162 i = server_port_check (use_ssl);
1165 /* URI_PATH */
1166 else if (sscanf (pos, HD5, url) == 1) {
1167 /* relative url */
1168 if ((url[0] != '/')) {
1169 if ((x = strrchr(server_url, '/')))
1170 *x = '\0';
1171 asprintf (&url, "%s/%s", server_url, url);
1173 i = server_port;
1174 strcpy (type, server_type);
1175 strcpy (addr, host_name ? host_name : server_address);
1178 else {
1179 die (STATE_UNKNOWN,
1180 _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"),
1181 pos, (display_html ? "</A>" : ""));
1184 break;
1186 } /* end while (pos) */
1188 if (++redir_depth > max_depth)
1189 die (STATE_WARNING,
1190 _("HTTP WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"),
1191 max_depth, type, addr, i, url, (display_html ? "</A>" : ""));
1193 if (server_port==i &&
1194 !strcmp(server_address, addr) &&
1195 (host_name && !strcmp(host_name, addr)) &&
1196 !strcmp(server_url, url))
1197 die (STATE_WARNING,
1198 _("HTTP WARNING - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
1199 type, addr, i, url, (display_html ? "</A>" : ""));
1201 strcpy (server_type, type);
1203 free (host_name);
1204 host_name = strdup (addr);
1206 if (followsticky == 0) {
1207 free (server_address);
1208 server_address = strdup (addr);
1211 free (server_url);
1212 server_url = url;
1214 if ((server_port = i) > MAX_PORT)
1215 die (STATE_UNKNOWN,
1216 _("HTTP UNKNOWN - Redirection to port above %d - %s://%s:%d%s%s\n"),
1217 MAX_PORT, server_type, server_address, server_port, server_url,
1218 display_html ? "</A>" : "");
1220 if (verbose)
1221 printf (_("Redirection to %s://%s:%d%s\n"), server_type,
1222 host_name ? host_name : server_address, server_port, server_url);
1224 check_http ();
1229 server_type_check (const char *type)
1231 if (strcmp (type, "https"))
1232 return FALSE;
1233 else
1234 return TRUE;
1238 server_port_check (int ssl_flag)
1240 if (ssl_flag)
1241 return HTTPS_PORT;
1242 else
1243 return HTTP_PORT;
1246 char *perfd_time (double elapsed_time)
1248 return fperfdata ("time", elapsed_time, "s",
1249 check_warning_time, warning_time,
1250 check_critical_time, critical_time,
1251 TRUE, 0, FALSE, 0);
1256 char *perfd_size (int page_len)
1258 return perfdata ("size", page_len, "B",
1259 (min_page_len>0?TRUE:FALSE), min_page_len,
1260 (min_page_len>0?TRUE:FALSE), 0,
1261 TRUE, 0, FALSE, 0);
1264 void
1265 print_help (void)
1267 print_revision (progname, NP_VERSION);
1269 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1270 printf (COPYRIGHT, copyright, email);
1272 printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test"));
1273 printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for"));
1274 printf ("%s\n", _("strings and regular expressions, check connection times, and report on"));
1275 printf ("%s\n", _("certificate expiration times."));
1277 printf ("\n\n");
1279 print_usage ();
1281 printf (_("NOTE: One or both of -H and -I must be specified"));
1283 printf ("\n");
1285 printf (_(UT_HELP_VRSN));
1286 printf (_(UT_EXTRA_OPTS));
1288 printf (" %s\n", "-H, --hostname=ADDRESS");
1289 printf (" %s\n", _("Host name argument for servers using host headers (virtual host)"));
1290 printf (" %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
1291 printf (" %s\n", "-I, --IP-address=ADDRESS");
1292 printf (" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
1293 printf (" %s\n", "-p, --port=INTEGER");
1294 printf (" %s", _("Port number (default: "));
1295 printf ("%d)\n", HTTP_PORT);
1297 printf (_(UT_IPv46));
1299 #ifdef HAVE_SSL
1300 printf (" %s\n", "-S, --ssl");
1301 printf (" %s\n", _("Connect via SSL. Port defaults to 443"));
1302 printf (" %s\n", "-C, --certificate=INTEGER");
1303 printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443"));
1304 printf (" %s\n", _("(when this option is used the URL is not checked.)\n"));
1305 #endif
1307 printf (" %s\n", "-e, --expect=STRING");
1308 printf (" %s\n", _("Comma-delimited list of strings, at least one of them is expected in"));
1309 printf (" %s", _("the first (status) line of the server response (default: "));
1310 printf ("%s)\n", HTTP_EXPECT);
1311 printf (" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
1312 printf (" %s\n", "-s, --string=STRING");
1313 printf (" %s\n", _("String to expect in the content"));
1314 printf (" %s\n", "-u, --url=PATH");
1315 printf (" %s\n", _("URL to GET or POST (default: /)"));
1316 printf (" %s\n", "-P, --post=STRING");
1317 printf (" %s\n", _("URL encoded http POST data"));
1318 printf (" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE)");
1319 printf (" %s\n", _("Set HTTP method."));
1320 printf (" %s\n", "-N, --no-body");
1321 printf (" %s\n", _("Don't wait for document body: stop reading after headers."));
1322 printf (" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)"));
1323 printf (" %s\n", "-M, --max-age=SECONDS");
1324 printf (" %s\n", _("Warn if document is more than SECONDS old. the number can also be of"));
1325 printf (" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
1326 printf (" %s\n", "-T, --content-type=STRING");
1327 printf (" %s\n", _("specify Content-Type header media type when POSTing\n"));
1329 printf (" %s\n", "-l, --linespan");
1330 printf (" %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
1331 printf (" %s\n", "-r, --regex, --ereg=STRING");
1332 printf (" %s\n", _("Search page for regex STRING"));
1333 printf (" %s\n", "-R, --eregi=STRING");
1334 printf (" %s\n", _("Search page for case-insensitive regex STRING"));
1335 printf (" %s\n", "--invert-regex");
1336 printf (" %s\n", _("Return CRITICAL if found, OK if not\n"));
1338 printf (" %s\n", "-a, --authorization=AUTH_PAIR");
1339 printf (" %s\n", _("Username:password on sites with basic authentication"));
1340 printf (" %s\n", "-A, --useragent=STRING");
1341 printf (" %s\n", _("String to be sent in http header as \"User Agent\""));
1342 printf (" %s\n", "-k, --header=STRING");
1343 printf (" %s\n", _(" Any other tags to be sent in http header. Use multiple times for additional headers"));
1344 printf (" %s\n", "-L, --link");
1345 printf (" %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
1346 printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky>");
1347 printf (" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the"));
1348 printf (" %s\n", _("specified IP address"));
1349 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
1350 printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
1352 printf (_(UT_WARN_CRIT));
1354 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
1356 printf (_(UT_VERBOSE));
1358 printf ("\n");
1359 printf ("%s\n", _("Notes:"));
1360 printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
1361 printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
1362 printf (" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect reponse"));
1363 printf (" %s\n", _("messages from the host result in STATE_WARNING return values. If you are"));
1364 printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
1365 printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
1366 printf ("\n");
1367 printf (_(UT_EXTRA_OPTS_NOTES));
1369 #ifdef HAVE_SSL
1370 printf ("\n");
1371 printf (" %s\n", _("This plugin can also check whether an SSL enabled web server is able to"));
1372 printf (" %s\n", _("serve content (optionally within a specified time) or whether the X509 "));
1373 printf (" %s\n", _("certificate is still valid for the specified number of days."));
1374 printf ("\n");
1375 printf ("%s\n", _("Examples:"));
1376 printf (" %s\n\n", "CHECK CONTENT: check_http -w 5 -c 10 --ssl -H www.verisign.com");
1377 printf (" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
1378 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
1379 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
1380 printf (" %s\n\n", _("a STATE_CRITICAL will be returned."));
1382 printf (" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 14");
1383 printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
1384 printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
1385 printf (" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
1386 printf (" %s\n", _("the certificate is expired."));
1387 #endif
1389 printf (_(UT_SUPPORT));
1395 void
1396 print_usage (void)
1398 printf (_("Usage:"));
1399 printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname);
1400 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L]\n");
1401 printf (" [-a auth] [-f <ok | warn | critcal | follow>] [-e <expect>]\n");
1402 printf (" [-s string] [-l] [-r <regex> | -R <case-insensitive regex>] [-P string]\n");
1403 printf (" [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>] [-A string]\n");
1404 printf (" [-k string] [-S] [-C <age>] [-T <content-type>] [-j method]\n");