Fixed typo in check_disk
[monitoring-plugins.git] / plugins / check_http.c
blob03102033a0f9a3b85036be76d1551b953daf86d8
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 ";"
47 #define STICKY_NONE 0
48 #define STICKY_HOST 1
49 #define STICKY_PORT 2
51 #define HTTP_EXPECT "HTTP/1."
52 enum {
53 MAX_IPV4_HOSTLENGTH = 255,
54 HTTP_PORT = 80,
55 HTTPS_PORT = 443,
56 MAX_PORT = 65535
59 #ifdef HAVE_SSL
60 int check_cert = FALSE;
61 int days_till_exp;
62 char *randbuff;
63 X509 *server_cert;
64 # define my_recv(buf, len) ((use_ssl) ? np_net_ssl_read(buf, len) : read(sd, buf, len))
65 # define my_send(buf, len) ((use_ssl) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
66 #else /* ifndef HAVE_SSL */
67 # define my_recv(buf, len) read(sd, buf, len)
68 # define my_send(buf, len) send(sd, buf, len, 0)
69 #endif /* HAVE_SSL */
70 int no_body = FALSE;
71 int maximum_age = -1;
73 enum {
74 REGS = 2,
75 MAX_RE_SIZE = 256
77 #include "regex.h"
78 regex_t preg;
79 regmatch_t pmatch[REGS];
80 char regexp[MAX_RE_SIZE];
81 char errbuf[MAX_INPUT_BUFFER];
82 int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
83 int errcode;
84 int invert_regex = 0;
86 struct timeval tv;
88 #define HTTP_URL "/"
89 #define CRLF "\r\n"
91 int specify_port = FALSE;
92 int server_port = HTTP_PORT;
93 char server_port_text[6] = "";
94 char server_type[6] = "http";
95 char *server_address;
96 char *host_name;
97 char *server_url;
98 char *user_agent;
99 int server_url_length;
100 int server_expect_yn = 0;
101 char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
102 char string_expect[MAX_INPUT_BUFFER] = "";
103 double warning_time = 0;
104 int check_warning_time = FALSE;
105 double critical_time = 0;
106 int check_critical_time = FALSE;
107 char user_auth[MAX_INPUT_BUFFER] = "";
108 int display_html = FALSE;
109 char **http_opt_headers;
110 int http_opt_headers_count = 0;
111 int onredirect = STATE_OK;
112 int followsticky = STICKY_NONE;
113 int use_ssl = FALSE;
114 int verbose = FALSE;
115 int sd;
116 int min_page_len = 0;
117 int max_page_len = 0;
118 int redir_depth = 0;
119 int max_depth = 15;
120 char *http_method;
121 char *http_post_data;
122 char *http_content_type;
123 char buffer[MAX_INPUT_BUFFER];
125 int process_arguments (int, char **);
126 int check_http (void);
127 void redir (char *pos, char *status_line);
128 int server_type_check(const char *type);
129 int server_port_check(int ssl_flag);
130 char *perfd_time (double microsec);
131 char *perfd_size (int page_len);
132 void print_help (void);
133 void print_usage (void);
136 main (int argc, char **argv)
138 int result = STATE_UNKNOWN;
140 setlocale (LC_ALL, "");
141 bindtextdomain (PACKAGE, LOCALEDIR);
142 textdomain (PACKAGE);
144 /* Set default URL. Must be malloced for subsequent realloc if --onredirect=follow */
145 server_url = strdup(HTTP_URL);
146 server_url_length = strlen(server_url);
147 asprintf (&user_agent, "User-Agent: check_http/v%s (nagios-plugins %s)",
148 NP_VERSION, VERSION);
150 /* Parse extra opts if any */
151 argv=np_extra_opts (&argc, argv, progname);
153 if (process_arguments (argc, argv) == ERROR)
154 usage4 (_("Could not parse arguments"));
156 if (display_html == TRUE)
157 printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">",
158 use_ssl ? "https" : "http", host_name ? host_name : server_address,
159 server_port, server_url);
161 /* initialize alarm signal handling, set socket timeout, start timer */
162 (void) signal (SIGALRM, socket_timeout_alarm_handler);
163 (void) alarm (socket_timeout);
164 gettimeofday (&tv, NULL);
166 result = check_http ();
167 return result;
172 /* process command-line arguments */
174 process_arguments (int argc, char **argv)
176 int c = 1;
177 char *p;
179 enum {
180 INVERT_REGEX = CHAR_MAX + 1
183 int option = 0;
184 static struct option longopts[] = {
185 STD_LONG_OPTS,
186 {"link", no_argument, 0, 'L'},
187 {"nohtml", no_argument, 0, 'n'},
188 {"ssl", no_argument, 0, 'S'},
189 {"post", required_argument, 0, 'P'},
190 {"method", required_argument, 0, 'j'},
191 {"IP-address", required_argument, 0, 'I'},
192 {"url", required_argument, 0, 'u'},
193 {"port", required_argument, 0, 'p'},
194 {"authorization", required_argument, 0, 'a'},
195 {"string", required_argument, 0, 's'},
196 {"expect", required_argument, 0, 'e'},
197 {"regex", required_argument, 0, 'r'},
198 {"ereg", required_argument, 0, 'r'},
199 {"eregi", required_argument, 0, 'R'},
200 {"linespan", no_argument, 0, 'l'},
201 {"onredirect", required_argument, 0, 'f'},
202 {"certificate", required_argument, 0, 'C'},
203 {"useragent", required_argument, 0, 'A'},
204 {"header", required_argument, 0, 'k'},
205 {"no-body", no_argument, 0, 'N'},
206 {"max-age", required_argument, 0, 'M'},
207 {"content-type", required_argument, 0, 'T'},
208 {"pagesize", required_argument, 0, 'm'},
209 {"invert-regex", no_argument, NULL, INVERT_REGEX},
210 {"use-ipv4", no_argument, 0, '4'},
211 {"use-ipv6", no_argument, 0, '6'},
212 {0, 0, 0, 0}
215 if (argc < 2)
216 return ERROR;
218 for (c = 1; c < argc; c++) {
219 if (strcmp ("-to", argv[c]) == 0)
220 strcpy (argv[c], "-t");
221 if (strcmp ("-hn", argv[c]) == 0)
222 strcpy (argv[c], "-H");
223 if (strcmp ("-wt", argv[c]) == 0)
224 strcpy (argv[c], "-w");
225 if (strcmp ("-ct", argv[c]) == 0)
226 strcpy (argv[c], "-c");
227 if (strcmp ("-nohtml", argv[c]) == 0)
228 strcpy (argv[c], "-n");
231 while (1) {
232 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);
233 if (c == -1 || c == EOF)
234 break;
236 switch (c) {
237 case '?': /* usage */
238 usage5 ();
239 break;
240 case 'h': /* help */
241 print_help ();
242 exit (STATE_OK);
243 break;
244 case 'V': /* version */
245 print_revision (progname, NP_VERSION);
246 exit (STATE_OK);
247 break;
248 case 't': /* timeout period */
249 if (!is_intnonneg (optarg))
250 usage2 (_("Timeout interval must be a positive integer"), optarg);
251 else
252 socket_timeout = atoi (optarg);
253 break;
254 case 'c': /* critical time threshold */
255 if (!is_nonnegative (optarg))
256 usage2 (_("Critical threshold must be integer"), optarg);
257 else {
258 critical_time = strtod (optarg, NULL);
259 check_critical_time = TRUE;
261 break;
262 case 'w': /* warning time threshold */
263 if (!is_nonnegative (optarg))
264 usage2 (_("Warning threshold must be integer"), optarg);
265 else {
266 warning_time = strtod (optarg, NULL);
267 check_warning_time = TRUE;
269 break;
270 case 'A': /* User Agent String */
271 asprintf (&user_agent, "User-Agent: %s", optarg);
272 break;
273 case 'k': /* Additional headers */
274 if (http_opt_headers_count == 0)
275 http_opt_headers = malloc (sizeof (char *) * (++http_opt_headers_count));
276 else
277 http_opt_headers = realloc (http_opt_headers, sizeof (char *) * (++http_opt_headers_count));
278 http_opt_headers[http_opt_headers_count - 1] = optarg;
279 /* asprintf (&http_opt_headers, "%s", optarg); */
280 break;
281 case 'L': /* show html link */
282 display_html = TRUE;
283 break;
284 case 'n': /* do not show html link */
285 display_html = FALSE;
286 break;
287 case 'C': /* Check SSL cert validity */
288 #ifdef HAVE_SSL
289 if (!is_intnonneg (optarg))
290 usage2 (_("Invalid certificate expiration period"), optarg);
291 else {
292 days_till_exp = atoi (optarg);
293 check_cert = TRUE;
295 /* Fall through to -S option */
296 #endif
297 case 'S': /* use SSL */
298 #ifndef HAVE_SSL
299 usage4 (_("Invalid option - SSL is not available"));
300 #endif
301 use_ssl = TRUE;
302 if (specify_port == FALSE)
303 server_port = HTTPS_PORT;
304 break;
305 case 'f': /* onredirect */
306 if (!strcmp (optarg, "stickyport"))
307 onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST|STICKY_PORT;
308 else if (!strcmp (optarg, "sticky"))
309 onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST;
310 else if (!strcmp (optarg, "follow"))
311 onredirect = STATE_DEPENDENT, followsticky = STICKY_NONE;
312 else if (!strcmp (optarg, "unknown"))
313 onredirect = STATE_UNKNOWN;
314 else if (!strcmp (optarg, "ok"))
315 onredirect = STATE_OK;
316 else if (!strcmp (optarg, "warning"))
317 onredirect = STATE_WARNING;
318 else if (!strcmp (optarg, "critical"))
319 onredirect = STATE_CRITICAL;
320 else usage2 (_("Invalid onredirect option"), optarg);
321 if (verbose)
322 printf(_("option f:%d \n"), onredirect);
323 break;
324 /* Note: H, I, and u must be malloc'd or will fail on redirects */
325 case 'H': /* Host Name (virtual host) */
326 host_name = strdup (optarg);
327 if (host_name[0] == '[') {
328 if ((p = strstr (host_name, "]:")) != NULL) /* [IPv6]:port */
329 server_port = atoi (p + 2);
330 } else if ((p = strchr (host_name, ':')) != NULL
331 && strchr (++p, ':') == NULL) /* IPv4:port or host:port */
332 server_port = atoi (p);
333 break;
334 case 'I': /* Server IP-address */
335 server_address = strdup (optarg);
336 break;
337 case 'u': /* URL path */
338 server_url = strdup (optarg);
339 server_url_length = strlen (server_url);
340 break;
341 case 'p': /* Server port */
342 if (!is_intnonneg (optarg))
343 usage2 (_("Invalid port number"), optarg);
344 else {
345 server_port = atoi (optarg);
346 specify_port = TRUE;
348 break;
349 case 'a': /* authorization info */
350 strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1);
351 user_auth[MAX_INPUT_BUFFER - 1] = 0;
352 break;
353 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */
354 if (! http_post_data)
355 http_post_data = strdup (optarg);
356 if (! http_method)
357 http_method = strdup("POST");
358 break;
359 case 'j': /* Set HTTP method */
360 if (http_method)
361 free(http_method);
362 http_method = strdup (optarg);
363 break;
364 case 's': /* string or substring */
365 strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1);
366 string_expect[MAX_INPUT_BUFFER - 1] = 0;
367 break;
368 case 'e': /* string or substring */
369 strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1);
370 server_expect[MAX_INPUT_BUFFER - 1] = 0;
371 server_expect_yn = 1;
372 break;
373 case 'T': /* Content-type */
374 asprintf (&http_content_type, "%s", optarg);
375 break;
376 case 'l': /* linespan */
377 cflags &= ~REG_NEWLINE;
378 break;
379 case 'R': /* regex */
380 cflags |= REG_ICASE;
381 case 'r': /* regex */
382 strncpy (regexp, optarg, MAX_RE_SIZE - 1);
383 regexp[MAX_RE_SIZE - 1] = 0;
384 errcode = regcomp (&preg, regexp, cflags);
385 if (errcode != 0) {
386 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
387 printf (_("Could Not Compile Regular Expression: %s"), errbuf);
388 return ERROR;
390 break;
391 case INVERT_REGEX:
392 invert_regex = 1;
393 break;
394 case '4':
395 address_family = AF_INET;
396 break;
397 case '6':
398 #ifdef USE_IPV6
399 address_family = AF_INET6;
400 #else
401 usage4 (_("IPv6 support not available"));
402 #endif
403 break;
404 case 'v': /* verbose */
405 verbose = TRUE;
406 break;
407 case 'm': /* min_page_length */
409 char *tmp;
410 if (strchr(optarg, ':') != (char *)NULL) {
411 /* range, so get two values, min:max */
412 tmp = strtok(optarg, ":");
413 if (tmp == NULL) {
414 printf("Bad format: try \"-m min:max\"\n");
415 exit (STATE_WARNING);
416 } else
417 min_page_len = atoi(tmp);
419 tmp = strtok(NULL, ":");
420 if (tmp == NULL) {
421 printf("Bad format: try \"-m min:max\"\n");
422 exit (STATE_WARNING);
423 } else
424 max_page_len = atoi(tmp);
425 } else
426 min_page_len = atoi (optarg);
427 break;
429 case 'N': /* no-body */
430 no_body = TRUE;
431 break;
432 case 'M': /* max-age */
434 int L = strlen(optarg);
435 if (L && optarg[L-1] == 'm')
436 maximum_age = atoi (optarg) * 60;
437 else if (L && optarg[L-1] == 'h')
438 maximum_age = atoi (optarg) * 60 * 60;
439 else if (L && optarg[L-1] == 'd')
440 maximum_age = atoi (optarg) * 60 * 60 * 24;
441 else if (L && (optarg[L-1] == 's' ||
442 isdigit (optarg[L-1])))
443 maximum_age = atoi (optarg);
444 else {
445 fprintf (stderr, "unparsable max-age: %s\n", optarg);
446 exit (STATE_WARNING);
449 break;
453 c = optind;
455 if (server_address == NULL && c < argc)
456 server_address = strdup (argv[c++]);
458 if (host_name == NULL && c < argc)
459 host_name = strdup (argv[c++]);
461 if (server_address == NULL) {
462 if (host_name == NULL)
463 usage4 (_("You must specify a server address or host name"));
464 else
465 server_address = strdup (host_name);
468 if (check_critical_time && critical_time>(double)socket_timeout)
469 socket_timeout = (int)critical_time + 1;
471 if (http_method == NULL)
472 http_method = strdup ("GET");
474 return TRUE;
479 /* Returns 1 if we're done processing the document body; 0 to keep going */
480 static int
481 document_headers_done (char *full_page)
483 const char *body;
485 for (body = full_page; *body; body++) {
486 if (!strncmp (body, "\n\n", 2) || !strncmp (body, "\n\r\n", 3))
487 break;
490 if (!*body)
491 return 0; /* haven't read end of headers yet */
493 full_page[body - full_page] = 0;
494 return 1;
497 static time_t
498 parse_time_string (const char *string)
500 struct tm tm;
501 time_t t;
502 memset (&tm, 0, sizeof(tm));
504 /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */
506 if (isupper (string[0]) && /* Tue */
507 islower (string[1]) &&
508 islower (string[2]) &&
509 ',' == string[3] &&
510 ' ' == string[4] &&
511 (isdigit(string[5]) || string[5] == ' ') && /* 25 */
512 isdigit (string[6]) &&
513 ' ' == string[7] &&
514 isupper (string[8]) && /* Dec */
515 islower (string[9]) &&
516 islower (string[10]) &&
517 ' ' == string[11] &&
518 isdigit (string[12]) && /* 2001 */
519 isdigit (string[13]) &&
520 isdigit (string[14]) &&
521 isdigit (string[15]) &&
522 ' ' == string[16] &&
523 isdigit (string[17]) && /* 02: */
524 isdigit (string[18]) &&
525 ':' == string[19] &&
526 isdigit (string[20]) && /* 59: */
527 isdigit (string[21]) &&
528 ':' == string[22] &&
529 isdigit (string[23]) && /* 03 */
530 isdigit (string[24]) &&
531 ' ' == string[25] &&
532 'G' == string[26] && /* GMT */
533 'M' == string[27] && /* GMT */
534 'T' == string[28]) {
536 tm.tm_sec = 10 * (string[23]-'0') + (string[24]-'0');
537 tm.tm_min = 10 * (string[20]-'0') + (string[21]-'0');
538 tm.tm_hour = 10 * (string[17]-'0') + (string[18]-'0');
539 tm.tm_mday = 10 * (string[5] == ' ' ? 0 : string[5]-'0') + (string[6]-'0');
540 tm.tm_mon = (!strncmp (string+8, "Jan", 3) ? 0 :
541 !strncmp (string+8, "Feb", 3) ? 1 :
542 !strncmp (string+8, "Mar", 3) ? 2 :
543 !strncmp (string+8, "Apr", 3) ? 3 :
544 !strncmp (string+8, "May", 3) ? 4 :
545 !strncmp (string+8, "Jun", 3) ? 5 :
546 !strncmp (string+8, "Jul", 3) ? 6 :
547 !strncmp (string+8, "Aug", 3) ? 7 :
548 !strncmp (string+8, "Sep", 3) ? 8 :
549 !strncmp (string+8, "Oct", 3) ? 9 :
550 !strncmp (string+8, "Nov", 3) ? 10 :
551 !strncmp (string+8, "Dec", 3) ? 11 :
552 -1);
553 tm.tm_year = ((1000 * (string[12]-'0') +
554 100 * (string[13]-'0') +
555 10 * (string[14]-'0') +
556 (string[15]-'0'))
557 - 1900);
559 tm.tm_isdst = 0; /* GMT is never in DST, right? */
561 if (tm.tm_mon < 0 || tm.tm_mday < 1 || tm.tm_mday > 31)
562 return 0;
565 This is actually wrong: we need to subtract the local timezone
566 offset from GMT from this value. But, that's ok in this usage,
567 because we only comparing these two GMT dates against each other,
568 so it doesn't matter what time zone we parse them in.
571 t = mktime (&tm);
572 if (t == (time_t) -1) t = 0;
574 if (verbose) {
575 const char *s = string;
576 while (*s && *s != '\r' && *s != '\n')
577 fputc (*s++, stdout);
578 printf (" ==> %lu\n", (unsigned long) t);
581 return t;
583 } else {
584 return 0;
588 /* Checks if the server 'reply' is one of the expected 'statuscodes' */
589 static int
590 expected_statuscode (const char *reply, const char *statuscodes)
592 char *expected, *code;
593 int result = 0;
595 if ((expected = strdup (statuscodes)) == NULL)
596 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
598 for (code = strtok (expected, ","); code != NULL; code = strtok (NULL, ","))
599 if (strstr (reply, code) != NULL) {
600 result = 1;
601 break;
604 free (expected);
605 return result;
608 static int
609 check_document_dates (const char *headers, char **msg)
611 const char *s;
612 char *server_date = 0;
613 char *document_date = 0;
614 int date_result = STATE_OK;
616 s = headers;
617 while (*s) {
618 const char *field = s;
619 const char *value = 0;
621 /* Find the end of the header field */
622 while (*s && !isspace(*s) && *s != ':')
623 s++;
625 /* Remember the header value, if any. */
626 if (*s == ':')
627 value = ++s;
629 /* Skip to the end of the header, including continuation lines. */
630 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
631 s++;
633 /* Avoid stepping over end-of-string marker */
634 if (*s)
635 s++;
637 /* Process this header. */
638 if (value && value > field+2) {
639 char *ff = (char *) malloc (value-field);
640 char *ss = ff;
641 while (field < value-1)
642 *ss++ = tolower(*field++);
643 *ss++ = 0;
645 if (!strcmp (ff, "date") || !strcmp (ff, "last-modified")) {
646 const char *e;
647 while (*value && isspace (*value))
648 value++;
649 for (e = value; *e && *e != '\r' && *e != '\n'; e++)
651 ss = (char *) malloc (e - value + 1);
652 strncpy (ss, value, e - value);
653 ss[e - value] = 0;
654 if (!strcmp (ff, "date")) {
655 if (server_date) free (server_date);
656 server_date = ss;
657 } else {
658 if (document_date) free (document_date);
659 document_date = ss;
662 free (ff);
666 /* Done parsing the body. Now check the dates we (hopefully) parsed. */
667 if (!server_date || !*server_date) {
668 asprintf (msg, _("%sServer date unknown, "), *msg);
669 date_result = max_state_alt(STATE_UNKNOWN, date_result);
670 } else if (!document_date || !*document_date) {
671 asprintf (msg, _("%sDocument modification date unknown, "), *msg);
672 date_result = max_state_alt(STATE_CRITICAL, date_result);
673 } else {
674 time_t srv_data = parse_time_string (server_date);
675 time_t doc_data = parse_time_string (document_date);
677 if (srv_data <= 0) {
678 asprintf (msg, _("%sServer date \"%100s\" unparsable, "), *msg, server_date);
679 date_result = max_state_alt(STATE_CRITICAL, date_result);
680 } else if (doc_data <= 0) {
681 asprintf (msg, _("%sDocument date \"%100s\" unparsable, "), *msg, document_date);
682 date_result = max_state_alt(STATE_CRITICAL, date_result);
683 } else if (doc_data > srv_data + 30) {
684 asprintf (msg, _("%sDocument is %d seconds in the future, "), *msg, (int)doc_data - (int)srv_data);
685 date_result = max_state_alt(STATE_CRITICAL, date_result);
686 } else if (doc_data < srv_data - maximum_age) {
687 int n = (srv_data - doc_data);
688 if (n > (60 * 60 * 24 * 2)) {
689 asprintf (msg, _("%sLast modified %.1f days ago, "), *msg, ((float) n) / (60 * 60 * 24));
690 date_result = max_state_alt(STATE_CRITICAL, date_result);
691 } else {
692 asprintf (msg, _("%sLast modified %d:%02d:%02d ago, "), *msg, n / (60 * 60), (n / 60) % 60, n % 60);
693 date_result = max_state_alt(STATE_CRITICAL, date_result);
696 free (server_date);
697 free (document_date);
699 return date_result;
703 get_content_length (const char *headers)
705 const char *s;
706 int content_length = 0;
708 s = headers;
709 while (*s) {
710 const char *field = s;
711 const char *value = 0;
713 /* Find the end of the header field */
714 while (*s && !isspace(*s) && *s != ':')
715 s++;
717 /* Remember the header value, if any. */
718 if (*s == ':')
719 value = ++s;
721 /* Skip to the end of the header, including continuation lines. */
722 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
723 s++;
724 s++;
726 /* Process this header. */
727 if (value && value > field+2) {
728 char *ff = (char *) malloc (value-field);
729 char *ss = ff;
730 while (field < value-1)
731 *ss++ = tolower(*field++);
732 *ss++ = 0;
734 if (!strcmp (ff, "content-length")) {
735 const char *e;
736 while (*value && isspace (*value))
737 value++;
738 for (e = value; *e && *e != '\r' && *e != '\n'; e++)
740 ss = (char *) malloc (e - value + 1);
741 strncpy (ss, value, e - value);
742 ss[e - value] = 0;
743 content_length = atoi(ss);
744 free (ss);
746 free (ff);
749 return (content_length);
752 char *
753 prepend_slash (char *path)
755 char *newpath;
757 if (path[0] == '/')
758 return path;
760 if ((newpath = malloc (strlen(path) + 2)) == NULL)
761 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
762 newpath[0] = '/';
763 strcpy (newpath + 1, path);
764 free (path);
765 return newpath;
769 check_http (void)
771 char *msg;
772 char *status_line;
773 char *status_code;
774 char *header;
775 char *page;
776 char *auth;
777 int http_status;
778 int i = 0;
779 size_t pagesize = 0;
780 char *full_page;
781 char *buf;
782 char *pos;
783 long microsec;
784 double elapsed_time;
785 int page_len = 0;
786 int result = STATE_OK;
788 /* try to connect to the host at the given port number */
789 if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
790 die (STATE_CRITICAL, _("HTTP CRITICAL - Unable to open TCP socket\n"));
791 #ifdef HAVE_SSL
792 if (use_ssl == TRUE) {
793 np_net_ssl_init(sd);
794 if (check_cert == TRUE) {
795 result = np_net_ssl_check_cert(days_till_exp);
796 np_net_ssl_cleanup();
797 if (sd) close(sd);
798 return result;
801 #endif /* HAVE_SSL */
803 asprintf (&buf, "%s %s %s\r\n%s\r\n", http_method, server_url, host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent);
805 /* tell HTTP/1.1 servers not to keep the connection alive */
806 asprintf (&buf, "%sConnection: close\r\n", buf);
808 /* optionally send the host header info */
809 if (host_name) {
811 * Specify the port only if we're using a non-default port (see RFC 2616,
812 * 14.23). Some server applications/configurations cause trouble if the
813 * (default) port is explicitly specified in the "Host:" header line.
815 if ((use_ssl == FALSE && server_port == HTTP_PORT) ||
816 (use_ssl == TRUE && server_port == HTTPS_PORT))
817 asprintf (&buf, "%sHost: %s\r\n", buf, host_name);
818 else
819 asprintf (&buf, "%sHost: %s:%d\r\n", buf, host_name, server_port);
822 /* optionally send any other header tag */
823 if (http_opt_headers_count) {
824 for (i = 0; i < http_opt_headers_count ; i++) {
825 for ((pos = strtok(http_opt_headers[i], INPUT_DELIMITER)); pos; (pos = strtok(NULL, INPUT_DELIMITER)))
826 asprintf (&buf, "%s%s\r\n", buf, pos);
828 /* This cannot be free'd here because a redirection will then try to access this and segfault */
829 /* Covered in a testcase in tests/check_http.t */
830 /* free(http_opt_headers); */
833 /* optionally send the authentication info */
834 if (strlen(user_auth)) {
835 base64_encode_alloc (user_auth, strlen (user_auth), &auth);
836 asprintf (&buf, "%sAuthorization: Basic %s\r\n", buf, auth);
839 /* either send http POST data (any data, not only POST)*/
840 if (http_post_data) {
841 if (http_content_type) {
842 asprintf (&buf, "%sContent-Type: %s\r\n", buf, http_content_type);
843 } else {
844 asprintf (&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf);
847 asprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data));
848 asprintf (&buf, "%s%s%s", buf, http_post_data, CRLF);
850 else {
851 /* or just a newline so the server knows we're done with the request */
852 asprintf (&buf, "%s%s", buf, CRLF);
855 if (verbose) printf ("%s\n", buf);
856 my_send (buf, strlen (buf));
858 /* fetch the page */
859 full_page = strdup("");
860 while ((i = my_recv (buffer, MAX_INPUT_BUFFER-1)) > 0) {
861 buffer[i] = '\0';
862 asprintf (&full_page, "%s%s", full_page, buffer);
863 pagesize += i;
865 if (no_body && document_headers_done (full_page)) {
866 i = 0;
867 break;
871 if (i < 0 && errno != ECONNRESET) {
872 #ifdef HAVE_SSL
874 if (use_ssl) {
875 sslerr=SSL_get_error(ssl, i);
876 if ( sslerr == SSL_ERROR_SSL ) {
877 die (STATE_WARNING, _("HTTP WARNING - Client Certificate Required\n"));
878 } else {
879 die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
882 else {
884 #endif
885 die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
886 #ifdef HAVE_SSL
887 /* XXX
890 #endif
893 /* return a CRITICAL status if we couldn't read any data */
894 if (pagesize == (size_t) 0)
895 die (STATE_CRITICAL, _("HTTP CRITICAL - No data received from host\n"));
897 /* close the connection */
898 #ifdef HAVE_SSL
899 np_net_ssl_cleanup();
900 #endif
901 if (sd) close(sd);
903 /* Save check time */
904 microsec = deltime (tv);
905 elapsed_time = (double)microsec / 1.0e6;
907 /* leave full_page untouched so we can free it later */
908 page = full_page;
910 if (verbose)
911 printf ("%s://%s:%d%s is %d characters\n",
912 use_ssl ? "https" : "http", server_address,
913 server_port, server_url, (int)pagesize);
915 /* find status line and null-terminate it */
916 status_line = page;
917 page += (size_t) strcspn (page, "\r\n");
918 pos = page;
919 page += (size_t) strspn (page, "\r\n");
920 status_line[strcspn(status_line, "\r\n")] = 0;
921 strip (status_line);
922 if (verbose)
923 printf ("STATUS: %s\n", status_line);
925 /* find header info and null-terminate it */
926 header = page;
927 while (strcspn (page, "\r\n") > 0) {
928 page += (size_t) strcspn (page, "\r\n");
929 pos = page;
930 if ((strspn (page, "\r") == 1 && strspn (page, "\r\n") >= 2) ||
931 (strspn (page, "\n") == 1 && strspn (page, "\r\n") >= 2))
932 page += (size_t) 2;
933 else
934 page += (size_t) 1;
936 page += (size_t) strspn (page, "\r\n");
937 header[pos - header] = 0;
938 if (verbose)
939 printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header,
940 (no_body ? " [[ skipped ]]" : page));
942 /* make sure the status line matches the response we are looking for */
943 if (!expected_statuscode (status_line, server_expect)) {
944 if (server_port == HTTP_PORT)
945 asprintf (&msg,
946 _("Invalid HTTP response received from host: %s\n"),
947 status_line);
948 else
949 asprintf (&msg,
950 _("Invalid HTTP response received from host on port %d: %s\n"),
951 server_port, status_line);
952 die (STATE_CRITICAL, "HTTP CRITICAL - %s", msg);
955 /* Bypass normal status line check if server_expect was set by user and not default */
956 /* NOTE: After this if/else block msg *MUST* be an asprintf-allocated string */
957 if ( server_expect_yn ) {
958 asprintf (&msg,
959 _("Status line output matched \"%s\" - "), server_expect);
960 if (verbose)
961 printf ("%s\n",msg);
963 else {
964 /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
965 /* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
966 /* Status-Code = 3 DIGITS */
968 status_code = strchr (status_line, ' ') + sizeof (char);
969 if (strspn (status_code, "1234567890") != 3)
970 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line);
972 http_status = atoi (status_code);
974 /* check the return code */
976 if (http_status >= 600 || http_status < 100) {
977 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line);
979 /* server errors result in a critical state */
980 else if (http_status >= 500) {
981 asprintf (&msg, _("%s - "), status_line);
982 result = STATE_CRITICAL;
984 /* client errors result in a warning state */
985 else if (http_status >= 400) {
986 asprintf (&msg, _("%s - "), status_line);
987 result = max_state_alt(STATE_WARNING, result);
989 /* check redirected page if specified */
990 else if (http_status >= 300) {
992 if (onredirect == STATE_DEPENDENT)
993 redir (header, status_line);
994 else
995 result = max_state_alt(onredirect, result);
996 asprintf (&msg, _("%s - "), status_line);
997 } /* end if (http_status >= 300) */
998 else {
999 /* Print OK status anyway */
1000 asprintf (&msg, _("%s - "), status_line);
1003 } /* end else (server_expect_yn) */
1005 /* reset the alarm - must be called *after* redir or we'll never die on redirects! */
1006 alarm (0);
1008 if (maximum_age >= 0) {
1009 result = max_state_alt(check_document_dates(header, &msg), result);
1012 /* Page and Header content checks go here */
1014 if (strlen (string_expect)) {
1015 if (!strstr (page, string_expect)) {
1016 asprintf (&msg, _("%sstring not found, "), msg);
1017 result = STATE_CRITICAL;
1021 if (strlen (regexp)) {
1022 errcode = regexec (&preg, page, REGS, pmatch, 0);
1023 if ((errcode == 0 && invert_regex == 0) || (errcode == REG_NOMATCH && invert_regex == 1)) {
1024 /* OK - No-op to avoid changing the logic around it */
1025 result = max_state_alt(STATE_OK, result);
1027 else if ((errcode == REG_NOMATCH && invert_regex == 0) || (errcode == 0 && invert_regex == 1)) {
1028 if (invert_regex == 0)
1029 asprintf (&msg, _("%spattern not found, "), msg);
1030 else
1031 asprintf (&msg, _("%spattern found, "), msg);
1032 result = STATE_CRITICAL;
1034 else {
1035 /* FIXME: Shouldn't that be UNKNOWN? */
1036 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1037 asprintf (&msg, _("%sExecute Error: %s, "), msg, errbuf);
1038 result = STATE_CRITICAL;
1042 /* make sure the page is of an appropriate size */
1043 /* page_len = get_content_length(header); */
1044 /* FIXME: Will this work with -N ? IMHO we should use
1045 * get_content_length(header) and always check if it's different than the
1046 * returned pagesize
1048 /* FIXME: IIRC pagesize returns headers - shouldn't we make
1049 * it == get_content_length(header) ??
1051 page_len = pagesize;
1052 if ((max_page_len > 0) && (page_len > max_page_len)) {
1053 asprintf (&msg, _("%spage size %d too large, "), msg, page_len);
1054 result = max_state_alt(STATE_WARNING, result);
1055 } else if ((min_page_len > 0) && (page_len < min_page_len)) {
1056 asprintf (&msg, _("%spage size %d too small, "), msg, page_len);
1057 result = max_state_alt(STATE_WARNING, result);
1060 /* Cut-off trailing characters */
1061 if(msg[strlen(msg)-2] == ',')
1062 msg[strlen(msg)-2] = '\0';
1063 else
1064 msg[strlen(msg)-3] = '\0';
1066 /* check elapsed time */
1067 asprintf (&msg,
1068 _("%s - %d bytes in %.3f second response time %s|%s %s"),
1069 msg, page_len, elapsed_time,
1070 (display_html ? "</A>" : ""),
1071 perfd_time (elapsed_time), perfd_size (page_len));
1073 if (check_critical_time == TRUE && elapsed_time > critical_time)
1074 result = STATE_CRITICAL;
1075 if (check_warning_time == TRUE && elapsed_time > warning_time)
1076 result = max_state_alt(STATE_WARNING, result);
1078 die (result, "HTTP %s: %s\n", state_text(result), msg);
1079 /* die failed? */
1080 return STATE_UNKNOWN;
1085 /* per RFC 2396 */
1086 #define URI_HTTP "%5[HTPShtps]"
1087 #define URI_HOST "%255[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1088 #define URI_PORT "%6d" /* MAX_PORT's width is 5 chars, 6 to detect overflow */
1089 #define URI_PATH "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1090 #define HD1 URI_HTTP "://" URI_HOST ":" URI_PORT "/" URI_PATH
1091 #define HD2 URI_HTTP "://" URI_HOST "/" URI_PATH
1092 #define HD3 URI_HTTP "://" URI_HOST ":" URI_PORT
1093 #define HD4 URI_HTTP "://" URI_HOST
1094 #define HD5 URI_PATH
1096 void
1097 redir (char *pos, char *status_line)
1099 int i = 0;
1100 char *x;
1101 char xx[2];
1102 char type[6];
1103 char *addr;
1104 char *url;
1106 addr = malloc (MAX_IPV4_HOSTLENGTH + 1);
1107 if (addr == NULL)
1108 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate addr\n"));
1110 url = malloc (strcspn (pos, "\r\n"));
1111 if (url == NULL)
1112 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
1114 while (pos) {
1115 sscanf (pos, "%1[Ll]%*1[Oo]%*1[Cc]%*1[Aa]%*1[Tt]%*1[Ii]%*1[Oo]%*1[Nn]:%n", xx, &i);
1116 if (i == 0) {
1117 pos += (size_t) strcspn (pos, "\r\n");
1118 pos += (size_t) strspn (pos, "\r\n");
1119 if (strlen(pos) == 0)
1120 die (STATE_UNKNOWN,
1121 _("HTTP UNKNOWN - Could not find redirect location - %s%s\n"),
1122 status_line, (display_html ? "</A>" : ""));
1123 continue;
1126 pos += i;
1127 pos += strspn (pos, " \t");
1130 * RFC 2616 (4.2): ``Header fields can be extended over multiple lines by
1131 * preceding each extra line with at least one SP or HT.''
1133 for (; (i = strspn (pos, "\r\n")); pos += i) {
1134 pos += i;
1135 if (!(i = strspn (pos, " \t"))) {
1136 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Empty redirect location%s\n"),
1137 display_html ? "</A>" : "");
1141 url = realloc (url, strcspn (pos, "\r\n") + 1);
1142 if (url == NULL)
1143 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
1145 /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
1146 if (sscanf (pos, HD1, type, addr, &i, url) == 4) {
1147 url = prepend_slash (url);
1148 use_ssl = server_type_check (type);
1151 /* URI_HTTP URI_HOST URI_PATH */
1152 else if (sscanf (pos, HD2, type, addr, url) == 3 ) {
1153 url = prepend_slash (url);
1154 use_ssl = server_type_check (type);
1155 i = server_port_check (use_ssl);
1158 /* URI_HTTP URI_HOST URI_PORT */
1159 else if (sscanf (pos, HD3, type, addr, &i) == 3) {
1160 strcpy (url, HTTP_URL);
1161 use_ssl = server_type_check (type);
1164 /* URI_HTTP URI_HOST */
1165 else if (sscanf (pos, HD4, type, addr) == 2) {
1166 strcpy (url, HTTP_URL);
1167 use_ssl = server_type_check (type);
1168 i = server_port_check (use_ssl);
1171 /* URI_PATH */
1172 else if (sscanf (pos, HD5, url) == 1) {
1173 /* relative url */
1174 if ((url[0] != '/')) {
1175 if ((x = strrchr(server_url, '/')))
1176 *x = '\0';
1177 asprintf (&url, "%s/%s", server_url, url);
1179 i = server_port;
1180 strcpy (type, server_type);
1181 strcpy (addr, host_name ? host_name : server_address);
1184 else {
1185 die (STATE_UNKNOWN,
1186 _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"),
1187 pos, (display_html ? "</A>" : ""));
1190 break;
1192 } /* end while (pos) */
1194 if (++redir_depth > max_depth)
1195 die (STATE_WARNING,
1196 _("HTTP WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"),
1197 max_depth, type, addr, i, url, (display_html ? "</A>" : ""));
1199 if (server_port==i &&
1200 !strcmp(server_address, addr) &&
1201 (host_name && !strcmp(host_name, addr)) &&
1202 !strcmp(server_url, url))
1203 die (STATE_WARNING,
1204 _("HTTP WARNING - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
1205 type, addr, i, url, (display_html ? "</A>" : ""));
1207 strcpy (server_type, type);
1209 free (host_name);
1210 host_name = strdup (addr);
1212 if (!(followsticky & STICKY_HOST)) {
1213 free (server_address);
1214 server_address = strdup (addr);
1216 if (!(followsticky & STICKY_PORT)) {
1217 server_port = i;
1220 free (server_url);
1221 server_url = url;
1223 if (server_port > MAX_PORT)
1224 die (STATE_UNKNOWN,
1225 _("HTTP UNKNOWN - Redirection to port above %d - %s://%s:%d%s%s\n"),
1226 MAX_PORT, server_type, server_address, server_port, server_url,
1227 display_html ? "</A>" : "");
1229 if (verbose)
1230 printf (_("Redirection to %s://%s:%d%s\n"), server_type,
1231 host_name ? host_name : server_address, server_port, server_url);
1233 check_http ();
1238 server_type_check (const char *type)
1240 if (strcmp (type, "https"))
1241 return FALSE;
1242 else
1243 return TRUE;
1247 server_port_check (int ssl_flag)
1249 if (ssl_flag)
1250 return HTTPS_PORT;
1251 else
1252 return HTTP_PORT;
1255 char *perfd_time (double elapsed_time)
1257 return fperfdata ("time", elapsed_time, "s",
1258 check_warning_time, warning_time,
1259 check_critical_time, critical_time,
1260 TRUE, 0, FALSE, 0);
1265 char *perfd_size (int page_len)
1267 return perfdata ("size", page_len, "B",
1268 (min_page_len>0?TRUE:FALSE), min_page_len,
1269 (min_page_len>0?TRUE:FALSE), 0,
1270 TRUE, 0, FALSE, 0);
1273 void
1274 print_help (void)
1276 print_revision (progname, NP_VERSION);
1278 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1279 printf (COPYRIGHT, copyright, email);
1281 printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test"));
1282 printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for"));
1283 printf ("%s\n", _("strings and regular expressions, check connection times, and report on"));
1284 printf ("%s\n", _("certificate expiration times."));
1286 printf ("\n\n");
1288 print_usage ();
1290 printf (_("NOTE: One or both of -H and -I must be specified"));
1292 printf ("\n");
1294 printf (_(UT_HELP_VRSN));
1295 printf (_(UT_EXTRA_OPTS));
1297 printf (" %s\n", "-H, --hostname=ADDRESS");
1298 printf (" %s\n", _("Host name argument for servers using host headers (virtual host)"));
1299 printf (" %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
1300 printf (" %s\n", "-I, --IP-address=ADDRESS");
1301 printf (" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
1302 printf (" %s\n", "-p, --port=INTEGER");
1303 printf (" %s", _("Port number (default: "));
1304 printf ("%d)\n", HTTP_PORT);
1306 printf (_(UT_IPv46));
1308 #ifdef HAVE_SSL
1309 printf (" %s\n", "-S, --ssl");
1310 printf (" %s\n", _("Connect via SSL. Port defaults to 443"));
1311 printf (" %s\n", "-C, --certificate=INTEGER");
1312 printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443"));
1313 printf (" %s\n", _("(when this option is used the URL is not checked.)\n"));
1314 #endif
1316 printf (" %s\n", "-e, --expect=STRING");
1317 printf (" %s\n", _("Comma-delimited list of strings, at least one of them is expected in"));
1318 printf (" %s", _("the first (status) line of the server response (default: "));
1319 printf ("%s)\n", HTTP_EXPECT);
1320 printf (" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
1321 printf (" %s\n", "-s, --string=STRING");
1322 printf (" %s\n", _("String to expect in the content"));
1323 printf (" %s\n", "-u, --url=PATH");
1324 printf (" %s\n", _("URL to GET or POST (default: /)"));
1325 printf (" %s\n", "-P, --post=STRING");
1326 printf (" %s\n", _("URL encoded http POST data"));
1327 printf (" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE)");
1328 printf (" %s\n", _("Set HTTP method."));
1329 printf (" %s\n", "-N, --no-body");
1330 printf (" %s\n", _("Don't wait for document body: stop reading after headers."));
1331 printf (" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)"));
1332 printf (" %s\n", "-M, --max-age=SECONDS");
1333 printf (" %s\n", _("Warn if document is more than SECONDS old. the number can also be of"));
1334 printf (" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
1335 printf (" %s\n", "-T, --content-type=STRING");
1336 printf (" %s\n", _("specify Content-Type header media type when POSTing\n"));
1338 printf (" %s\n", "-l, --linespan");
1339 printf (" %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
1340 printf (" %s\n", "-r, --regex, --ereg=STRING");
1341 printf (" %s\n", _("Search page for regex STRING"));
1342 printf (" %s\n", "-R, --eregi=STRING");
1343 printf (" %s\n", _("Search page for case-insensitive regex STRING"));
1344 printf (" %s\n", "--invert-regex");
1345 printf (" %s\n", _("Return CRITICAL if found, OK if not\n"));
1347 printf (" %s\n", "-a, --authorization=AUTH_PAIR");
1348 printf (" %s\n", _("Username:password on sites with basic authentication"));
1349 printf (" %s\n", "-A, --useragent=STRING");
1350 printf (" %s\n", _("String to be sent in http header as \"User Agent\""));
1351 printf (" %s\n", "-k, --header=STRING");
1352 printf (" %s\n", _(" Any other tags to be sent in http header. Use multiple times for additional headers"));
1353 printf (" %s\n", "-L, --link");
1354 printf (" %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
1355 printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport>");
1356 printf (" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the"));
1357 printf (" %s\n", _("specified IP address. stickyport also ensure post stays the same."));
1358 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
1359 printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
1361 printf (_(UT_WARN_CRIT));
1363 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
1365 printf (_(UT_VERBOSE));
1367 printf ("\n");
1368 printf ("%s\n", _("Notes:"));
1369 printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
1370 printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
1371 printf (" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect reponse"));
1372 printf (" %s\n", _("messages from the host result in STATE_WARNING return values. If you are"));
1373 printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
1374 printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
1375 printf ("\n");
1376 printf (_(UT_EXTRA_OPTS_NOTES));
1378 #ifdef HAVE_SSL
1379 printf ("\n");
1380 printf (" %s\n", _("This plugin can also check whether an SSL enabled web server is able to"));
1381 printf (" %s\n", _("serve content (optionally within a specified time) or whether the X509 "));
1382 printf (" %s\n", _("certificate is still valid for the specified number of days."));
1383 printf ("\n");
1384 printf ("%s\n", _("Examples:"));
1385 printf (" %s\n\n", "CHECK CONTENT: check_http -w 5 -c 10 --ssl -H www.verisign.com");
1386 printf (" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
1387 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
1388 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
1389 printf (" %s\n\n", _("a STATE_CRITICAL will be returned."));
1391 printf (" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 14");
1392 printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
1393 printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
1394 printf (" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
1395 printf (" %s\n", _("the certificate is expired."));
1396 #endif
1398 printf (_(UT_SUPPORT));
1404 void
1405 print_usage (void)
1407 printf (_("Usage:"));
1408 printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname);
1409 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L]\n");
1410 printf (" [-a auth] [-f <ok | warn | critcal | follow | sticky | stickyport>]\n");
1411 printf (" [-e <expect>] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n");
1412 printf (" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n");
1413 printf (" [-A string] [-k string] [-S] [-C <age>] [-T <content-type>] [-j method]\n");