Code

45d24a98ac06a4eae6feafb74dcc7cc5d5aeadf4
[nagiosplug.git] / plugins / check_http.c
1 /******************************************************************************
2 *
3 * Nagios check_http plugin
4 *
5 * License: GPL
6 * Copyright (c) 1999-2006 nagios-plugins team
7 *
8 * Last Modified: $Date$
9 *
10 * Description:
11 *
12 * This file contains the check_http plugin
13 *
14 *  This plugin tests the HTTP service on the specified host. It can test
15 *  normal (http) and secure (https) servers, follow redirects, search for
16 *  strings and regular expressions, check connection times, and report on
17 *  certificate expiration times.
18 *
19 *
20 * License Information:
21 *
22 * This program is free software; you can redistribute it and/or modify
23 * it under the terms of the GNU General Public License as published by
24 * the Free Software Foundation; either version 2 of the License, or
25 * (at your option) any later version.
26 *
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30 * GNU General Public License for more details.
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
36  $Id$
37  
38 ******************************************************************************/
39 /* splint -I. -I../../plugins -I../../lib/ -I/usr/kerberos/include/ ../../plugins/check_http.c */
41 const char *progname = "check_http";
42 const char *revision = "$Revision$";
43 const char *copyright = "1999-2006";
44 const char *email = "nagiosplug-devel@lists.sourceforge.net";
46 #include "common.h"
47 #include "netutils.h"
48 #include "utils.h"
50 #define INPUT_DELIMITER ";"
52 #define HTTP_EXPECT "HTTP/1."
53 enum {
54   MAX_IPV4_HOSTLENGTH = 255,
55   HTTP_PORT = 80,
56   HTTPS_PORT = 443,
57   MAX_PORT = 65535
58 };
60 #ifdef HAVE_SSL
61 int check_cert = FALSE;
62 int days_till_exp;
63 char *randbuff;
64 X509 *server_cert;
65 #  define my_recv(buf, len) ((use_ssl) ? np_net_ssl_read(buf, len) : read(sd, buf, len))
66 #  define my_send(buf, len) ((use_ssl) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
67 #else /* ifndef HAVE_SSL */
68 #  define my_recv(buf, len) read(sd, buf, len)
69 #  define my_send(buf, len) send(sd, buf, len, 0)
70 #endif /* HAVE_SSL */
71 int no_body = FALSE;
72 int maximum_age = -1;
74 enum {
75   REGS = 2,
76   MAX_RE_SIZE = 256
77 };
78 #include "regex.h"
79 regex_t preg;
80 regmatch_t pmatch[REGS];
81 char regexp[MAX_RE_SIZE];
82 char errbuf[MAX_INPUT_BUFFER];
83 int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
84 int errcode;
85 int invert_regex = 0;
87 struct timeval tv;
89 #define HTTP_URL "/"
90 #define CRLF "\r\n"
92 int specify_port = FALSE;
93 int server_port = HTTP_PORT;
94 char server_port_text[6] = "";
95 char server_type[6] = "http";
96 char *server_address;
97 char *host_name;
98 char *server_url;
99 char *user_agent;
100 int server_url_length;
101 int server_expect_yn = 0;
102 char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
103 char string_expect[MAX_INPUT_BUFFER] = "";
104 double warning_time = 0;
105 int check_warning_time = FALSE;
106 double critical_time = 0;
107 int check_critical_time = FALSE;
108 char user_auth[MAX_INPUT_BUFFER] = "";
109 int display_html = FALSE;
110 char **http_opt_headers;
111 int http_opt_headers_count = 0;
112 int onredirect = STATE_OK;
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 static char *base64 (const char *bin, size_t len);
127 int check_http (void);
128 void redir (char *pos, char *status_line);
129 int server_type_check(const char *type);
130 int server_port_check(int ssl_flag);
131 char *perfd_time (double microsec);
132 char *perfd_size (int page_len);
133 void print_help (void);
134 void print_usage (void);
136 int
137 main (int argc, char **argv)
139   int result = STATE_UNKNOWN;
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/%s (nagios-plugins %s)",
145             clean_revstring (revision), VERSION);
147   if (process_arguments (argc, argv) == ERROR)
148     usage4 (_("Could not parse arguments"));
150   if (display_html == TRUE)
151     printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", 
152       use_ssl ? "https" : "http", server_address,
153       server_port, server_url);
155   /* initialize alarm signal handling, set socket timeout, start timer */
156   (void) signal (SIGALRM, socket_timeout_alarm_handler);
157   (void) alarm (socket_timeout);
158   gettimeofday (&tv, NULL);
160   result = check_http ();
161   return result;
166 /* process command-line arguments */
167 int
168 process_arguments (int argc, char **argv)
170   int c = 1;
172   enum {
173     INVERT_REGEX = CHAR_MAX + 1
174   };
176   int option = 0;
177   static struct option longopts[] = {
178     STD_LONG_OPTS,
179     {"link", no_argument, 0, 'L'},
180     {"nohtml", no_argument, 0, 'n'},
181     {"ssl", no_argument, 0, 'S'},
182     {"post", required_argument, 0, 'P'},
183     {"IP-address", required_argument, 0, 'I'},
184     {"url", required_argument, 0, 'u'},
185     {"port", required_argument, 0, 'p'},
186     {"authorization", required_argument, 0, 'a'},
187     {"string", required_argument, 0, 's'},
188     {"expect", required_argument, 0, 'e'},
189     {"regex", required_argument, 0, 'r'},
190     {"ereg", required_argument, 0, 'r'},
191     {"eregi", required_argument, 0, 'R'},
192     {"linespan", no_argument, 0, 'l'},
193     {"onredirect", required_argument, 0, 'f'},
194     {"certificate", required_argument, 0, 'C'},
195     {"useragent", required_argument, 0, 'A'},
196     {"header", required_argument, 0, 'k'},
197     {"no-body", no_argument, 0, 'N'},
198     {"max-age", required_argument, 0, 'M'},
199     {"content-type", required_argument, 0, 'T'},
200     {"pagesize", required_argument, 0, 'm'},
201     {"invert-regex", no_argument, NULL, INVERT_REGEX},
202     {"use-ipv4", no_argument, 0, '4'},
203     {"use-ipv6", no_argument, 0, '6'},
204     {0, 0, 0, 0}
205   };
207   if (argc < 2)
208     return ERROR;
210   for (c = 1; c < argc; c++) {
211     if (strcmp ("-to", argv[c]) == 0)
212       strcpy (argv[c], "-t");
213     if (strcmp ("-hn", argv[c]) == 0)
214       strcpy (argv[c], "-H");
215     if (strcmp ("-wt", argv[c]) == 0)
216       strcpy (argv[c], "-w");
217     if (strcmp ("-ct", argv[c]) == 0)
218       strcpy (argv[c], "-c");
219     if (strcmp ("-nohtml", argv[c]) == 0)
220       strcpy (argv[c], "-n");
221   }
223   while (1) {
224     c = getopt_long (argc, argv, "Vvh46t:c:w:A:k:H:P:T:I:a:e:p:s:R:r:u:f:C:nlLSm:M:N", longopts, &option);
225     if (c == -1 || c == EOF)
226       break;
228     switch (c) {
229     case '?': /* usage */
230       usage5 ();
231       break;
232     case 'h': /* help */
233       print_help ();
234       exit (STATE_OK);
235       break;
236     case 'V': /* version */
237       print_revision (progname, revision);
238       exit (STATE_OK);
239       break;
240     case 't': /* timeout period */
241       if (!is_intnonneg (optarg))
242         usage2 (_("Timeout interval must be a positive integer"), optarg);
243       else
244         socket_timeout = atoi (optarg);
245       break;
246     case 'c': /* critical time threshold */
247       if (!is_nonnegative (optarg))
248         usage2 (_("Critical threshold must be integer"), optarg);
249       else {
250         critical_time = strtod (optarg, NULL);
251         check_critical_time = TRUE;
252       }
253       break;
254     case 'w': /* warning time threshold */
255       if (!is_nonnegative (optarg))
256         usage2 (_("Warning threshold must be integer"), optarg);
257       else {
258         warning_time = strtod (optarg, NULL);
259         check_warning_time = TRUE;
260       }
261       break;
262     case 'A': /* User Agent String */
263       asprintf (&user_agent, "User-Agent: %s", optarg);
264       break;
265     case 'k': /* Additional headers */
266       if (http_opt_headers_count == 0)
267         http_opt_headers = malloc (sizeof (char *) * (++http_opt_headers_count));
268       else
269         http_opt_headers = realloc (http_opt_headers, sizeof (char *) * (++http_opt_headers_count));
270       http_opt_headers[http_opt_headers_count - 1] = optarg;
271       /* asprintf (&http_opt_headers, "%s", optarg); */
272       break;
273     case 'L': /* show html link */
274       display_html = TRUE;
275       break;
276     case 'n': /* do not show html link */
277       display_html = FALSE;
278       break;
279     case 'C': /* Check SSL cert validity */
280 #ifdef HAVE_SSL
281       if (!is_intnonneg (optarg))
282         usage2 (_("Invalid certificate expiration period"), optarg);
283       else {
284         days_till_exp = atoi (optarg);
285         check_cert = TRUE;
286       }
287      /* Fall through to -S option */
288 #endif
289     case 'S': /* use SSL */
290 #ifndef HAVE_SSL
291       usage4 (_("Invalid option - SSL is not available"));
292 #endif
293       use_ssl = TRUE;
294       if (specify_port == FALSE)
295         server_port = HTTPS_PORT;
296       break;
297     case 'f': /* onredirect */
298       if (!strcmp (optarg, "follow"))
299         onredirect = STATE_DEPENDENT;
300       if (!strcmp (optarg, "unknown"))
301         onredirect = STATE_UNKNOWN;
302       if (!strcmp (optarg, "ok"))
303         onredirect = STATE_OK;
304       if (!strcmp (optarg, "warning"))
305         onredirect = STATE_WARNING;
306       if (!strcmp (optarg, "critical"))
307         onredirect = STATE_CRITICAL;
308       if (verbose)
309         printf(_("option f:%d \n"), onredirect);  
310       break;
311     /* Note: H, I, and u must be malloc'd or will fail on redirects */
312     case 'H': /* Host Name (virtual host) */
313       host_name = strdup (optarg);
314       if (strstr (optarg, ":"))
315         sscanf (optarg, "%*[^:]:%d", &server_port);
316       break;
317     case 'I': /* Server IP-address */
318       server_address = strdup (optarg);
319       break;
320     case 'u': /* URL path */
321       server_url = strdup (optarg);
322       server_url_length = strlen (server_url);
323       break;
324     case 'p': /* Server port */
325       if (!is_intnonneg (optarg))
326         usage2 (_("Invalid port number"), optarg);
327       else {
328         server_port = atoi (optarg);
329         specify_port = TRUE;
330       }
331       break;
332     case 'a': /* authorization info */
333       strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1);
334       user_auth[MAX_INPUT_BUFFER - 1] = 0;
335       break;
336     case 'P': /* HTTP POST data in URL encoded format */
337       if (http_method || http_post_data) break;
338       http_method = strdup("POST");
339       http_post_data = strdup (optarg);
340       break;
341     case 's': /* string or substring */
342       strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1);
343       string_expect[MAX_INPUT_BUFFER - 1] = 0;
344       break;
345     case 'e': /* string or substring */
346       strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1);
347       server_expect[MAX_INPUT_BUFFER - 1] = 0;
348       server_expect_yn = 1;
349       break;
350     case 'T': /* Content-type */
351       asprintf (&http_content_type, "%s", optarg);
352       break;
353     case 'l': /* linespan */
354       cflags &= ~REG_NEWLINE;
355       break;
356     case 'R': /* regex */
357       cflags |= REG_ICASE;
358     case 'r': /* regex */
359       strncpy (regexp, optarg, MAX_RE_SIZE - 1);
360       regexp[MAX_RE_SIZE - 1] = 0;
361       errcode = regcomp (&preg, regexp, cflags);
362       if (errcode != 0) {
363         (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
364         printf (_("Could Not Compile Regular Expression: %s"), errbuf);
365         return ERROR;
366       }
367       break;
368     case INVERT_REGEX:
369       invert_regex = 1;
370       break;
371     case '4':
372       address_family = AF_INET;
373       break;
374     case '6':
375 #ifdef USE_IPV6
376       address_family = AF_INET6;
377 #else
378       usage4 (_("IPv6 support not available"));
379 #endif
380       break;
381     case 'v': /* verbose */
382       verbose = TRUE;
383       break;
384     case 'm': /* min_page_length */
385       {
386       char *tmp;
387       if (strchr(optarg, ':') != (char *)NULL) {
388         /* range, so get two values, min:max */
389         tmp = strtok(optarg, ":");
390         if (tmp == NULL) {
391           printf("Bad format: try \"-m min:max\"\n");
392           exit (STATE_WARNING);
393         } else
394           min_page_len = atoi(tmp);
396         tmp = strtok(NULL, ":");
397         if (tmp == NULL) {
398           printf("Bad format: try \"-m min:max\"\n");
399           exit (STATE_WARNING);
400         } else
401           max_page_len = atoi(tmp);
402       } else 
403         min_page_len = atoi (optarg);
404       break;
405       }
406     case 'N': /* no-body */
407       no_body = TRUE;
408       break;
409     case 'M': /* max-age */
410                   {
411                     int L = strlen(optarg);
412                     if (L && optarg[L-1] == 'm')
413                       maximum_age = atoi (optarg) * 60;
414                     else if (L && optarg[L-1] == 'h')
415                       maximum_age = atoi (optarg) * 60 * 60;
416                     else if (L && optarg[L-1] == 'd')
417                       maximum_age = atoi (optarg) * 60 * 60 * 24;
418                     else if (L && (optarg[L-1] == 's' ||
419                                    isdigit (optarg[L-1])))
420                       maximum_age = atoi (optarg);
421                     else {
422                       fprintf (stderr, "unparsable max-age: %s\n", optarg);
423                       exit (STATE_WARNING);
424                     }
425                   }
426                   break;
427     }
428   }
430   c = optind;
432   if (server_address == NULL && c < argc)
433     server_address = strdup (argv[c++]);
435   if (host_name == NULL && c < argc)
436     host_name = strdup (argv[c++]);
438   if (server_address == NULL) {
439     if (host_name == NULL)
440       usage4 (_("You must specify a server address or host name"));
441     else
442       server_address = strdup (host_name);
443   }
445   if (check_critical_time && critical_time>(double)socket_timeout)
446     socket_timeout = (int)critical_time + 1;
448   if (http_method == NULL)
449     http_method = strdup ("GET");
451   return TRUE;
456 /* written by lauri alanko */
457 static char *
458 base64 (const char *bin, size_t len)
461   char *buf = (char *) malloc ((len + 2) / 3 * 4 + 1);
462   size_t i = 0, j = 0;
464   char BASE64_END = '=';
465   char base64_table[64];
466   strncpy (base64_table, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", 64);
468   while (j < len - 2) {
469     buf[i++] = base64_table[bin[j] >> 2];
470     buf[i++] = base64_table[((bin[j] & 3) << 4) | (bin[j + 1] >> 4)];
471     buf[i++] = base64_table[((bin[j + 1] & 15) << 2) | (bin[j + 2] >> 6)];
472     buf[i++] = base64_table[bin[j + 2] & 63];
473     j += 3;
474   }
476   switch (len - j) {
477   case 1:
478     buf[i++] = base64_table[bin[j] >> 2];
479     buf[i++] = base64_table[(bin[j] & 3) << 4];
480     buf[i++] = BASE64_END;
481     buf[i++] = BASE64_END;
482     break;
483   case 2:
484     buf[i++] = base64_table[bin[j] >> 2];
485     buf[i++] = base64_table[((bin[j] & 3) << 4) | (bin[j + 1] >> 4)];
486     buf[i++] = base64_table[(bin[j + 1] & 15) << 2];
487     buf[i++] = BASE64_END;
488     break;
489   case 0:
490     break;
491   }
493   buf[i] = '\0';
494   return buf;
499 /* Returns 1 if we're done processing the document body; 0 to keep going */
500 static int
501 document_headers_done (char *full_page)
503   const char *body;
505   for (body = full_page; *body; body++) {
506     if (!strncmp (body, "\n\n", 2) || !strncmp (body, "\n\r\n", 3))
507       break;
508   }
510   if (!*body)
511     return 0;  /* haven't read end of headers yet */
513   full_page[body - full_page] = 0;
514   return 1;
517 static time_t
518 parse_time_string (const char *string)
520   struct tm tm;
521   time_t t;
522   memset (&tm, 0, sizeof(tm));
524   /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */
526   if (isupper (string[0])  &&  /* Tue */
527     islower (string[1])  &&
528     islower (string[2])  &&
529     ',' ==   string[3]   &&
530     ' ' ==   string[4]   &&
531     (isdigit(string[5]) || string[5] == ' ') &&   /* 25 */
532     isdigit (string[6])  &&
533     ' ' ==   string[7]   &&
534     isupper (string[8])  &&  /* Dec */
535     islower (string[9])  &&
536     islower (string[10]) &&
537     ' ' ==   string[11]  &&
538     isdigit (string[12]) &&  /* 2001 */
539     isdigit (string[13]) &&
540     isdigit (string[14]) &&
541     isdigit (string[15]) &&
542     ' ' ==   string[16]  &&
543     isdigit (string[17]) &&  /* 02: */
544     isdigit (string[18]) &&
545     ':' ==   string[19]  &&
546     isdigit (string[20]) &&  /* 59: */
547     isdigit (string[21]) &&
548     ':' ==   string[22]  &&
549     isdigit (string[23]) &&  /* 03 */
550     isdigit (string[24]) &&
551     ' ' ==   string[25]  &&
552     'G' ==   string[26]  &&  /* GMT */
553     'M' ==   string[27]  &&  /* GMT */
554     'T' ==   string[28]) {
556     tm.tm_sec  = 10 * (string[23]-'0') + (string[24]-'0');
557     tm.tm_min  = 10 * (string[20]-'0') + (string[21]-'0');
558     tm.tm_hour = 10 * (string[17]-'0') + (string[18]-'0');
559     tm.tm_mday = 10 * (string[5] == ' ' ? 0 : string[5]-'0') + (string[6]-'0');
560     tm.tm_mon = (!strncmp (string+8, "Jan", 3) ? 0 :
561       !strncmp (string+8, "Feb", 3) ? 1 :
562       !strncmp (string+8, "Mar", 3) ? 2 :
563       !strncmp (string+8, "Apr", 3) ? 3 :
564       !strncmp (string+8, "May", 3) ? 4 :
565       !strncmp (string+8, "Jun", 3) ? 5 :
566       !strncmp (string+8, "Jul", 3) ? 6 :
567       !strncmp (string+8, "Aug", 3) ? 7 :
568       !strncmp (string+8, "Sep", 3) ? 8 :
569       !strncmp (string+8, "Oct", 3) ? 9 :
570       !strncmp (string+8, "Nov", 3) ? 10 :
571       !strncmp (string+8, "Dec", 3) ? 11 :
572       -1);
573     tm.tm_year = ((1000 * (string[12]-'0') +
574       100 * (string[13]-'0') +
575       10 * (string[14]-'0') +
576       (string[15]-'0'))
577       - 1900);
579     tm.tm_isdst = 0;  /* GMT is never in DST, right? */
581     if (tm.tm_mon < 0 || tm.tm_mday < 1 || tm.tm_mday > 31)
582       return 0;
584     /* 
585     This is actually wrong: we need to subtract the local timezone
586     offset from GMT from this value.  But, that's ok in this usage,
587     because we only comparing these two GMT dates against each other,
588     so it doesn't matter what time zone we parse them in.
589     */
591     t = mktime (&tm);
592     if (t == (time_t) -1) t = 0;
594     if (verbose) {
595       const char *s = string;
596       while (*s && *s != '\r' && *s != '\n')
597       fputc (*s++, stdout);
598       printf (" ==> %lu\n", (unsigned long) t);
599     }
601     return t;
603   } else {
604     return 0;
605   }
610 static void
611 check_document_dates (const char *headers)
613   const char *s;
614   char *server_date = 0;
615   char *document_date = 0;
617   s = headers;
618   while (*s) {
619     const char *field = s;
620     const char *value = 0;
622     /* Find the end of the header field */
623     while (*s && !isspace(*s) && *s != ':')
624       s++;
626     /* Remember the header value, if any. */
627     if (*s == ':')
628       value = ++s;
630     /* Skip to the end of the header, including continuation lines. */
631     while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
632       s++;
633     s++;
635     /* Process this header. */
636     if (value && value > field+2) {
637       char *ff = (char *) malloc (value-field);
638       char *ss = ff;
639       while (field < value-1)
640         *ss++ = tolower(*field++);
641       *ss++ = 0;
643       if (!strcmp (ff, "date") || !strcmp (ff, "last-modified")) {
644         const char *e;
645         while (*value && isspace (*value))
646           value++;
647         for (e = value; *e && *e != '\r' && *e != '\n'; e++)
648           ;
649         ss = (char *) malloc (e - value + 1);
650         strncpy (ss, value, e - value);
651         ss[e - value] = 0;
652         if (!strcmp (ff, "date")) {
653           if (server_date) free (server_date);
654           server_date = ss;
655         } else {
656           if (document_date) free (document_date);
657           document_date = ss;
658         }
659       }
660       free (ff);
661     }
662   }
664   /* Done parsing the body.  Now check the dates we (hopefully) parsed.  */
665   if (!server_date || !*server_date) {
666     die (STATE_UNKNOWN, _("HTTP UNKNOWN - Server date unknown\n"));
667   } else if (!document_date || !*document_date) {
668     die (STATE_CRITICAL, _("HTTP CRITICAL - Document modification date unknown\n"));
669   } else {
670     time_t srv_data = parse_time_string (server_date);
671     time_t doc_data = parse_time_string (document_date);
673     if (srv_data <= 0) {
674       die (STATE_CRITICAL, _("HTTP CRITICAL - Server date \"%100s\" unparsable"), server_date);
675     } else if (doc_data <= 0) {
676       die (STATE_CRITICAL, _("HTTP CRITICAL - Document date \"%100s\" unparsable"), document_date);
677     } else if (doc_data > srv_data + 30) {
678       die (STATE_CRITICAL, _("HTTP CRITICAL - Document is %d seconds in the future\n"), (int)doc_data - (int)srv_data);
679     } else if (doc_data < srv_data - maximum_age) {
680     int n = (srv_data - doc_data);
681     if (n > (60 * 60 * 24 * 2))
682       die (STATE_CRITICAL,
683         _("HTTP CRITICAL - Last modified %.1f days ago\n"),
684         ((float) n) / (60 * 60 * 24));
685   else
686     die (STATE_CRITICAL,
687         _("HTTP CRITICAL - Last modified %d:%02d:%02d ago\n"),
688         n / (60 * 60), (n / 60) % 60, n % 60);
689     }
691     free (server_date);
692     free (document_date);
693   }
696 int
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++)
733           ;
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);
739       }
740       free (ff);
741     }
742   }
743   return (content_length);
746 int
747 check_http (void)
749   char *msg;
750   char *status_line;
751   char *status_code;
752   char *header;
753   char *page;
754   char *auth;
755   int http_status;
756   int i = 0;
757   size_t pagesize = 0;
758   char *full_page;
759   char *buf;
760   char *pos;
761   long microsec;
762   double elapsed_time;
763   int page_len = 0;
764   int result = STATE_UNKNOWN;
766   /* try to connect to the host at the given port number */
767   if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
768     die (STATE_CRITICAL, _("HTTP CRITICAL - Unable to open TCP socket\n"));
769 #ifdef HAVE_SSL
770   if (use_ssl == TRUE) {
771     np_net_ssl_init(sd);
772     if (check_cert == TRUE) {
773       result = np_net_ssl_check_cert(days_till_exp);
774       np_net_ssl_cleanup();
775       if(sd) close(sd);
776       return result;
777     }
778   }
779 #endif /* HAVE_SSL */
781   asprintf (&buf, "%s %s HTTP/1.0\r\n%s\r\n", http_method, server_url, user_agent);
783   /* optionally send the host header info */
784   if (host_name)
785     asprintf (&buf, "%sHost: %s\r\n", buf, host_name);
787   /* optionally send any other header tag */
788   if (http_opt_headers_count) {
789     for (i = 0; i < http_opt_headers_count ; i++) {
790       for ((pos = strtok(http_opt_headers[i], INPUT_DELIMITER)); pos; (pos = strtok(NULL, INPUT_DELIMITER)))
791         asprintf (&buf, "%s%s\r\n", buf, pos);
792     }
793     free(http_opt_headers);
794   }
796   /* optionally send the authentication info */
797   if (strlen(user_auth)) {
798     auth = base64 (user_auth, strlen (user_auth));
799     asprintf (&buf, "%sAuthorization: Basic %s\r\n", buf, auth);
800   }
802   /* either send http POST data */
803   if (http_post_data) {
804     if (http_content_type) {
805       asprintf (&buf, "%sContent-Type: %s\r\n", buf, http_content_type);
806     } else {
807       asprintf (&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf);
808     }
809     
810     asprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data));
811     asprintf (&buf, "%s%s%s", buf, http_post_data, CRLF);
812   }
813   else {
814     /* or just a newline so the server knows we're done with the request */
815     asprintf (&buf, "%s%s", buf, CRLF);
816   }
818   if (verbose) printf ("%s\n", buf);
819   my_send (buf, strlen (buf));
821   /* fetch the page */
822   full_page = strdup("");
823   while ((i = my_recv (buffer, MAX_INPUT_BUFFER-1)) > 0) {
824     buffer[i] = '\0';
825     asprintf (&full_page, "%s%s", full_page, buffer);
826     pagesize += i;
828                 if (no_body && document_headers_done (full_page)) {
829                   i = 0;
830                   break;
831                 }
832   }
834   if (i < 0 && errno != ECONNRESET) {
835 #ifdef HAVE_SSL
836     /*
837     if (use_ssl) {
838       sslerr=SSL_get_error(ssl, i);
839       if ( sslerr == SSL_ERROR_SSL ) {
840         die (STATE_WARNING, _("HTTP WARNING - Client Certificate Required\n"));
841       } else {
842         die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
843       }
844     }
845     else {
846     */
847 #endif
848       die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
849 #ifdef HAVE_SSL
850       /* XXX
851     }
852     */
853 #endif
854   }
856   /* return a CRITICAL status if we couldn't read any data */
857   if (pagesize == (size_t) 0)
858     die (STATE_CRITICAL, _("HTTP CRITICAL - No data received from host\n"));
860   /* close the connection */
861 #ifdef HAVE_SSL
862   np_net_ssl_cleanup();
863 #endif
864   if(sd) close(sd);
866   /* reset the alarm */
867   alarm (0);
869   /* leave full_page untouched so we can free it later */
870   page = full_page;
872   if (verbose)
873     printf ("%s://%s:%d%s is %d characters\n",
874       use_ssl ? "https" : "http", server_address,
875       server_port, server_url, (int)pagesize);
877   /* find status line and null-terminate it */
878   status_line = page;
879   page += (size_t) strcspn (page, "\r\n");
880   pos = page;
881   page += (size_t) strspn (page, "\r\n");
882   status_line[strcspn(status_line, "\r\n")] = 0;
883   strip (status_line);
884   if (verbose)
885     printf ("STATUS: %s\n", status_line);
887   /* find header info and null-terminate it */
888   header = page;
889   while (strcspn (page, "\r\n") > 0) {
890     page += (size_t) strcspn (page, "\r\n");
891     pos = page;
892     if ((strspn (page, "\r") == 1 && strspn (page, "\r\n") >= 2) ||
893         (strspn (page, "\n") == 1 && strspn (page, "\r\n") >= 2))
894       page += (size_t) 2;
895     else
896       page += (size_t) 1;
897   }
898   page += (size_t) strspn (page, "\r\n");
899   header[pos - header] = 0;
900   if (verbose)
901     printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header,
902                 (no_body ? "  [[ skipped ]]" : page));
904   /* make sure the status line matches the response we are looking for */
905   if (!strstr (status_line, server_expect)) {
906     if (server_port == HTTP_PORT)
907       asprintf (&msg,
908                 _("Invalid HTTP response received from host\n"));
909     else
910       asprintf (&msg,
911                 _("Invalid HTTP response received from host on port %d\n"),
912                 server_port);
913     die (STATE_CRITICAL, "HTTP CRITICAL - %s", msg);
914   }
916   /* Exit here if server_expect was set by user and not default */
917   if ( server_expect_yn  )  {
918     asprintf (&msg,
919               _("HTTP OK: Status line output matched \"%s\"\n"),
920               server_expect);
921     if (verbose)
922       printf ("%s\n",msg);
923   }
924   else {
925     /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
926     /* HTTP-Version   = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
927     /* Status-Code = 3 DIGITS */
929     status_code = strchr (status_line, ' ') + sizeof (char);
930     if (strspn (status_code, "1234567890") != 3)
931       die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line);
933     http_status = atoi (status_code);
935     /* check the return code */
937     if (http_status >= 600 || http_status < 100)
938       die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line);
940     /* server errors result in a critical state */
941     else if (http_status >= 500)
942       die (STATE_CRITICAL, _("HTTP CRITICAL: %s\n"), status_line);
944     /* client errors result in a warning state */
945     else if (http_status >= 400)
946       die (STATE_WARNING, _("HTTP WARNING: %s\n"), status_line);
948     /* check redirected page if specified */
949     else if (http_status >= 300) {
951       if (onredirect == STATE_DEPENDENT)
952         redir (header, status_line);
953       else if (onredirect == STATE_UNKNOWN)
954         printf (_("HTTP UNKNOWN"));
955       else if (onredirect == STATE_OK)
956         printf (_("HTTP OK"));
957       else if (onredirect == STATE_WARNING)
958         printf (_("HTTP WARNING"));
959       else if (onredirect == STATE_CRITICAL)
960         printf (_("HTTP CRITICAL"));
961       microsec = deltime (tv);
962       elapsed_time = (double)microsec / 1.0e6;
963       die (onredirect,
964            _(" - %s - %.3f second response time %s|%s %s\n"),
965            status_line, elapsed_time, 
966            (display_html ? "</A>" : ""),
967            perfd_time (elapsed_time), perfd_size (pagesize));
968     } /* end if (http_status >= 300) */
970   } /* end else (server_expect_yn)  */
971     
972         if (maximum_age >= 0) {
973           check_document_dates (header);
974         }
976   /* check elapsed time */
977   microsec = deltime (tv);
978   elapsed_time = (double)microsec / 1.0e6;
979   asprintf (&msg,
980             _("HTTP WARNING: %s - %.3f second response time %s|%s %s\n"),
981             status_line, elapsed_time, 
982             (display_html ? "</A>" : ""),
983             perfd_time (elapsed_time), perfd_size (pagesize));
984   if (check_critical_time == TRUE && elapsed_time > critical_time)
985     die (STATE_CRITICAL, "%s", msg);
986   if (check_warning_time == TRUE && elapsed_time > warning_time)
987     die (STATE_WARNING, "%s", msg);
989   /* Page and Header content checks go here */
990   /* these checks should be last */
992   if (strlen (string_expect)) {
993     if (strstr (page, string_expect)) {
994       printf (_("HTTP OK %s - %.3f second response time %s|%s %s\n"),
995               status_line, elapsed_time,
996               (display_html ? "</A>" : ""),
997               perfd_time (elapsed_time), perfd_size (pagesize));
998       exit (STATE_OK);
999     }
1000     else {
1001       printf (_("HTTP CRITICAL - string not found%s|%s %s\n"),
1002               (display_html ? "</A>" : ""),
1003               perfd_time (elapsed_time), perfd_size (pagesize));
1004       exit (STATE_CRITICAL);
1005     }
1006   }
1008   if (strlen (regexp)) {
1009     errcode = regexec (&preg, page, REGS, pmatch, 0);
1010     if ((errcode == 0 && invert_regex == 0) || (errcode == REG_NOMATCH && invert_regex == 1)) {
1011       printf (_("HTTP OK %s - %.3f second response time %s|%s %s\n"),
1012               status_line, elapsed_time,
1013               (display_html ? "</A>" : ""),
1014               perfd_time (elapsed_time), perfd_size (pagesize));
1015       exit (STATE_OK);
1016     }
1017     else if ((errcode == REG_NOMATCH && invert_regex == 0) || (errcode == 0 && invert_regex == 1)) {
1018       if (invert_regex == 0) 
1019         msg = strdup(_("pattern not found"));
1020       else 
1021         msg = strdup(_("pattern found"));
1022       printf (("%s - %s%s|%s %s\n"),
1023         _("HTTP CRITICAL"),
1024         msg,
1025         (display_html ? "</A>" : ""),
1026         perfd_time (elapsed_time), perfd_size (pagesize));
1027       exit (STATE_CRITICAL);
1028     }
1029     else {
1030       regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1031       printf (_("HTTP CRITICAL - Execute Error: %s\n"), errbuf);
1032       exit (STATE_CRITICAL);
1033     }
1034   }
1036   /* make sure the page is of an appropriate size */
1037   /* page_len = get_content_length(header); */
1038   page_len = pagesize;
1039   if ((max_page_len > 0) && (page_len > max_page_len)) {
1040     printf (_("HTTP WARNING: page size %d too large%s|%s\n"),
1041       page_len, (display_html ? "</A>" : ""), perfd_size (page_len) );
1042     exit (STATE_WARNING);
1043   } else if ((min_page_len > 0) && (page_len < min_page_len)) {
1044     printf (_("HTTP WARNING: page size %d too small%s|%s\n"),
1045       page_len, (display_html ? "</A>" : ""), perfd_size (page_len) );
1046     exit (STATE_WARNING);
1047   }
1048   /* We only get here if all tests have been passed */
1049   asprintf (&msg, _("HTTP OK %s - %d bytes in %.3f seconds %s|%s %s\n"),
1050             status_line, page_len, elapsed_time,
1051             (display_html ? "</A>" : ""),
1052             perfd_time (elapsed_time), perfd_size (page_len));
1053   die (STATE_OK, "%s", msg);
1054   return STATE_UNKNOWN;
1059 /* per RFC 2396 */
1060 #define HDR_LOCATION "%*[Ll]%*[Oo]%*[Cc]%*[Aa]%*[Tt]%*[Ii]%*[Oo]%*[Nn]: "
1061 #define URI_HTTP "%5[HTPShtps]"
1062 #define URI_HOST "%255[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1063 #define URI_PORT "%6d" /* MAX_PORT's width is 5 chars, 6 to detect overflow */
1064 #define URI_PATH "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1065 #define HD1 URI_HTTP "://" URI_HOST ":" URI_PORT "/" URI_PATH
1066 #define HD2 URI_HTTP "://" URI_HOST "/" URI_PATH
1067 #define HD3 URI_HTTP "://" URI_HOST ":" URI_PORT
1068 #define HD4 URI_HTTP "://" URI_HOST
1069 #define HD5 URI_PATH
1071 void
1072 redir (char *pos, char *status_line)
1074   int i = 0;
1075   char *x;
1076   char xx[2];
1077   char type[6];
1078   char *addr;
1079   char *url;
1081   addr = malloc (MAX_IPV4_HOSTLENGTH + 1);
1082   if (addr == NULL)
1083     die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate addr\n"));
1084   
1085   url = malloc (strcspn (pos, "\r\n"));
1086   if (url == NULL)
1087     die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate url\n"));
1089   while (pos) {
1090     sscanf (pos, "%[Ll]%*[Oo]%*[Cc]%*[Aa]%*[Tt]%*[Ii]%*[Oo]%*[Nn]:%n", xx, &i);
1091     if (i == 0) {
1092       pos += (size_t) strcspn (pos, "\r\n");
1093       pos += (size_t) strspn (pos, "\r\n");
1094       if (strlen(pos) == 0) 
1095         die (STATE_UNKNOWN,
1096              _("HTTP UNKNOWN - Could not find redirect location - %s%s\n"),
1097              status_line, (display_html ? "</A>" : ""));
1098       continue;
1099     }
1101     pos += i;
1102     pos += strspn (pos, " \t");
1104     /*
1105      * RFC 2616 (4.2):  ``Header fields can be extended over multiple lines by
1106      * preceding each extra line with at least one SP or HT.''
1107      */
1108     for (; (i = strspn (pos, "\r\n")); pos += i) {
1109       pos += i;
1110       if (!(i = strspn (pos, " \t"))) {
1111         die (STATE_UNKNOWN, _("HTTP UNKNOWN - Empty redirect location%s\n"),
1112              display_html ? "</A>" : "");
1113       }
1114     }
1116     url = realloc (url, strcspn (pos, "\r\n") + 1);
1117     if (url == NULL)
1118       die (STATE_UNKNOWN, _("HTTP UNKNOWN - could not allocate url\n"));
1120     /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
1121     if (sscanf (pos, HD1, type, addr, &i, url) == 4)
1122       use_ssl = server_type_check (type);
1124     /* URI_HTTP URI_HOST URI_PATH */
1125     else if (sscanf (pos, HD2, type, addr, url) == 3 ) { 
1126       use_ssl = server_type_check (type);
1127       i = server_port_check (use_ssl);
1128     }
1130     /* URI_HTTP URI_HOST URI_PORT */
1131     else if(sscanf (pos, HD3, type, addr, &i) == 3) {
1132       strcpy (url, HTTP_URL);
1133       use_ssl = server_type_check (type);
1134     }
1136     /* URI_HTTP URI_HOST */
1137     else if(sscanf (pos, HD4, type, addr) == 2) {
1138       strcpy (url, HTTP_URL);
1139       use_ssl = server_type_check (type);
1140       i = server_port_check (use_ssl);
1141     }
1143     /* URI_PATH */
1144     else if (sscanf (pos, HD5, url) == 1) {
1145       /* relative url */
1146       if ((url[0] != '/')) {
1147         if ((x = strrchr(server_url, '/')))
1148           *x = '\0';
1149         asprintf (&url, "%s/%s", server_url, url);
1150       }
1151       i = server_port;
1152       strcpy (type, server_type);
1153       strcpy (addr, server_address);
1154     }           
1156     else {
1157       die (STATE_UNKNOWN,
1158            _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"),
1159            pos, (display_html ? "</A>" : ""));
1160     }
1162     break;
1164   } /* end while (pos) */
1166   if (++redir_depth > max_depth)
1167     die (STATE_WARNING,
1168          _("HTTP WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"),
1169          max_depth, type, addr, i, url, (display_html ? "</A>" : ""));
1171   if (server_port==i &&
1172       !strcmp(server_address, addr) &&
1173       (host_name && !strcmp(host_name, addr)) &&
1174       !strcmp(server_url, url))
1175     die (STATE_WARNING,
1176          _("HTTP WARNING - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
1177          type, addr, i, url, (display_html ? "</A>" : ""));
1179   strcpy (server_type, type);
1181   free (host_name);
1182   host_name = strdup (addr);
1184   free (server_address);
1185   server_address = strdup (addr);
1187   free (server_url);
1188   if ((url[0] == '/'))
1189     server_url = strdup (url);
1190   else if (asprintf(&server_url, "/%s", url) == -1)
1191     die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate server_url%s\n"),
1192          display_html ? "</A>" : "");
1193   free(url);
1195   if ((server_port = i) > MAX_PORT)
1196     die (STATE_UNKNOWN,
1197          _("HTTP UNKNOWN - Redirection to port above %d - %s://%s:%d%s%s\n"),
1198          MAX_PORT, server_type, server_address, server_port, server_url,
1199          display_html ? "</A>" : "");
1201   if (verbose)
1202     printf ("Redirection to %s://%s:%d%s\n", server_type, server_address,
1203             server_port, server_url);
1205   check_http ();
1210 int
1211 server_type_check (const char *type)
1213   if (strcmp (type, "https"))
1214     return FALSE;
1215   else
1216     return TRUE;
1219 int
1220 server_port_check (int ssl_flag)
1222   if (ssl_flag)
1223     return HTTPS_PORT;
1224   else
1225     return HTTP_PORT;
1228 char *perfd_time (double elapsed_time)
1230   return fperfdata ("time", elapsed_time, "s",
1231             check_warning_time, warning_time,
1232             check_critical_time, critical_time,
1233                    TRUE, 0, FALSE, 0);
1238 char *perfd_size (int page_len)
1240   return perfdata ("size", page_len, "B",
1241             (min_page_len>0?TRUE:FALSE), min_page_len,
1242             (min_page_len>0?TRUE:FALSE), 0,
1243             TRUE, 0, FALSE, 0);
1246 void
1247 print_help (void)
1249   print_revision (progname, revision);
1251   printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1252   printf (COPYRIGHT, copyright, email);
1254   printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test"));
1255   printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for"));
1256   printf ("%s\n", _("strings and regular expressions, check connection times, and report on"));
1257   printf ("%s\n", _("certificate expiration times."));
1259   printf ("\n\n");
1261   print_usage ();
1263   printf (_("NOTE: One or both of -H and -I must be specified"));
1265   printf ("\n");
1267   printf (_(UT_HELP_VRSN));
1269   printf (" %s\n", "-H, --hostname=ADDRESS");
1270   printf ("    %s\n", _("Host name argument for servers using host headers (virtual host)"));
1271   printf ("    %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
1272   printf (" %s\n", "-I, --IP-address=ADDRESS");
1273   printf ("    %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
1274   printf (" %s\n", "-p, --port=INTEGER");
1275   printf (" %s", _("Port number (default: "));
1276   printf ("%d)\n", HTTP_PORT);
1278   printf (_(UT_IPv46));
1280 #ifdef HAVE_SSL
1281   printf (" %s\n", "-S, --ssl");
1282   printf ("   %s\n", _("Connect via SSL. Port defaults to 443"));
1283   printf (" %s\n", "-C, --certificate=INTEGER");
1284   printf ("   %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443"));
1285   printf ("   %s\n", _("(when this option is used the url is not checked.)\n"));
1286 #endif
1288   printf (" %s\n", "-e, --expect=STRING");
1289   printf ("    %s\n", _("String to expect in first (status) line of server response (default: "));
1290   printf ("%s)\n", HTTP_EXPECT);
1291   printf ("    %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
1292   printf (" %s\n", "-s, --string=STRING");
1293   printf ("    %s\n", _("String to expect in the content"));
1294   printf (" %s\n", "-u, --url=PATH");
1295   printf ("    %s\n", _("URL to GET or POST (default: /)"));
1296   printf (" %s\n", "-P, --post=STRING");
1297   printf ("    %s\n", _("URL encoded http POST data"));
1298   printf (" %s\n", "-N, --no-body");
1299   printf ("    %s\n", _("Don't wait for document body: stop reading after headers."));
1300   printf ("    %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)"));
1301   printf (" %s\n", "-M, --max-age=SECONDS");
1302   printf ("    %s\n", _("Warn if document is more than SECONDS old. the number can also be of"));
1303   printf ("    %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
1304   printf (" %s\n", "-T, --content-type=STRING");
1305   printf ("    %s\n", _("specify Content-Type header media type when POSTing\n"));
1307   printf (" %s\n", "-l, --linespan");
1308   printf ("    %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
1309   printf (" %s\n", "-r, --regex, --ereg=STRING");
1310   printf ("    %s\n", _("Search page for regex STRING"));
1311   printf (" %s\n", "-R, --eregi=STRING");
1312   printf ("    %s\n", _("Search page for case-insensitive regex STRING"));
1313   printf (" %s\n", "--invert-regex");
1314   printf ("    %s\n", _("Return CRITICAL if found, OK if not\n"));
1316   printf (" %s\n", "-a, --authorization=AUTH_PAIR");
1317   printf ("    %s\n", _("Username:password on sites with basic authentication"));
1318   printf (" %s\n", "-A, --useragent=STRING");
1319   printf ("    %s\n", _("String to be sent in http header as \"User Agent\""));
1320   printf (" %s\n", "-k, --header=STRING");
1321   printf ("    %s\n", _(" Any other tags to be sent in http header. Use multiple times for additional headers"));
1322   printf (" %s\n", "-L, --link");
1323   printf ("    %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
1324   printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow>");
1325   printf ("    %s\n", _("How to handle redirected pages"));
1326   printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
1327   printf ("    %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
1329   printf (_(UT_WARN_CRIT));
1331   printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
1333   printf (_(UT_VERBOSE));
1335   printf (_("Notes:"));
1336   printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
1337   printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
1338   printf (" %s\n", _("other errors return STATE_UNKNOWN.  Successful connects, but incorrect reponse"));
1339   printf (" %s\n", _("messages from the host result in STATE_WARNING return values.  If you are"));
1340   printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
1341   printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
1343 #ifdef HAVE_SSL
1344   printf (" %s\n", _("This plugin can also check whether an SSL enabled web server is able to"));
1345   printf (" %s\n", _("serve content (optionally within a specified time) or whether the X509 "));
1346   printf (" %s\n", _("certificate is still valid for the specified number of days."));
1347   printf (_("Examples:"));
1348   printf (" %s\n\n", "CHECK CONTENT: check_http -w 5 -c 10 --ssl -H www.verisign.com");
1349   printf (" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
1350   printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
1351   printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
1352   printf (" %s\n\n", _("a STATE_CRITICAL will be returned."));
1354   printf (" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 14");
1355   printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
1356   printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
1357   printf (" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
1358   printf (" %s\n\n", _("the certificate is expired."));
1359 #endif
1361   printf (_(UT_SUPPORT));
1367 void
1368 print_usage (void)
1370   printf (_("Usage:"));
1371   printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname);
1372   printf ("       [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L]\n");
1373   printf ("       [-a auth] [-f <ok | warn | critcal | follow>] [-e <expect>]\n");
1374   printf ("       [-s string] [-l] [-r <regex> | -R <case-insensitive regex>] [-P string]\n");
1375   printf ("       [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>] [-A string]\n");
1376   printf ("       [-k string] [-S] [-C <age>] [-T <content-type>]\n");