Code

Fixed link -m64 problems on pst3 for solaris. Fixed _FILE_OFFSET_BITS
[nagiosplug.git] / plugins / check_http.c
1 /*****************************************************************************
2
3 * Nagios check_http plugin
4
5 * License: GPL
6 * Copyright (c) 1999-2008 Nagios Plugins Development 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 * This program is free software: you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation, either version 3 of the License, or
23 * (at your option) any later version.
24
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28 * GNU General Public License for more details.
29
30 * You should have received a copy of the GNU General Public License
31 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
32
33 * $Id$
34
35 *****************************************************************************/
37 /* splint -I. -I../../plugins -I../../lib/ -I/usr/kerberos/include/ ../../plugins/check_http.c */
39 const char *progname = "check_http";
40 const char *revision = "$Revision$";
41 const char *copyright = "1999-2008";
42 const char *email = "nagiosplug-devel@lists.sourceforge.net";
44 #include "common.h"
45 #include "netutils.h"
46 #include "utils.h"
47 #include "base64.h"
48 #include <ctype.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 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);
135 int
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/%s (nagios-plugins %s)",
148             clean_revstring (revision), VERSION);
150   if (process_arguments (argc, argv) == ERROR)
151     usage4 (_("Could not parse arguments"));
153   if (display_html == TRUE)
154     printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", 
155       use_ssl ? "https" : "http", host_name ? host_name : server_address,
156       server_port, server_url);
158   /* initialize alarm signal handling, set socket timeout, start timer */
159   (void) signal (SIGALRM, socket_timeout_alarm_handler);
160   (void) alarm (socket_timeout);
161   gettimeofday (&tv, NULL);
163   result = check_http ();
164   return result;
169 /* process command-line arguments */
170 int
171 process_arguments (int argc, char **argv)
173   int c = 1;
174   char *p;
176   enum {
177     INVERT_REGEX = CHAR_MAX + 1
178   };
180   int option = 0;
181   static struct option longopts[] = {
182     STD_LONG_OPTS,
183     {"link", no_argument, 0, 'L'},
184     {"nohtml", no_argument, 0, 'n'},
185     {"ssl", no_argument, 0, 'S'},
186     {"post", required_argument, 0, 'P'},
187     {"IP-address", required_argument, 0, 'I'},
188     {"url", required_argument, 0, 'u'},
189     {"port", required_argument, 0, 'p'},
190     {"authorization", required_argument, 0, 'a'},
191     {"string", required_argument, 0, 's'},
192     {"expect", required_argument, 0, 'e'},
193     {"regex", required_argument, 0, 'r'},
194     {"ereg", required_argument, 0, 'r'},
195     {"eregi", required_argument, 0, 'R'},
196     {"linespan", no_argument, 0, 'l'},
197     {"onredirect", required_argument, 0, 'f'},
198     {"certificate", required_argument, 0, 'C'},
199     {"useragent", required_argument, 0, 'A'},
200     {"header", required_argument, 0, 'k'},
201     {"no-body", no_argument, 0, 'N'},
202     {"max-age", required_argument, 0, 'M'},
203     {"content-type", required_argument, 0, 'T'},
204     {"pagesize", required_argument, 0, 'm'},
205     {"invert-regex", no_argument, NULL, INVERT_REGEX},
206     {"use-ipv4", no_argument, 0, '4'},
207     {"use-ipv6", no_argument, 0, '6'},
208     {0, 0, 0, 0}
209   };
211   if (argc < 2)
212     return ERROR;
214   for (c = 1; c < argc; c++) {
215     if (strcmp ("-to", argv[c]) == 0)
216       strcpy (argv[c], "-t");
217     if (strcmp ("-hn", argv[c]) == 0)
218       strcpy (argv[c], "-H");
219     if (strcmp ("-wt", argv[c]) == 0)
220       strcpy (argv[c], "-w");
221     if (strcmp ("-ct", argv[c]) == 0)
222       strcpy (argv[c], "-c");
223     if (strcmp ("-nohtml", argv[c]) == 0)
224       strcpy (argv[c], "-n");
225   }
227   while (1) {
228     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);
229     if (c == -1 || c == EOF)
230       break;
232     switch (c) {
233     case '?': /* usage */
234       usage5 ();
235       break;
236     case 'h': /* help */
237       print_help ();
238       exit (STATE_OK);
239       break;
240     case 'V': /* version */
241       print_revision (progname, revision);
242       exit (STATE_OK);
243       break;
244     case 't': /* timeout period */
245       if (!is_intnonneg (optarg))
246         usage2 (_("Timeout interval must be a positive integer"), optarg);
247       else
248         socket_timeout = atoi (optarg);
249       break;
250     case 'c': /* critical time threshold */
251       if (!is_nonnegative (optarg))
252         usage2 (_("Critical threshold must be integer"), optarg);
253       else {
254         critical_time = strtod (optarg, NULL);
255         check_critical_time = TRUE;
256       }
257       break;
258     case 'w': /* warning time threshold */
259       if (!is_nonnegative (optarg))
260         usage2 (_("Warning threshold must be integer"), optarg);
261       else {
262         warning_time = strtod (optarg, NULL);
263         check_warning_time = TRUE;
264       }
265       break;
266     case 'A': /* User Agent String */
267       asprintf (&user_agent, "User-Agent: %s", optarg);
268       break;
269     case 'k': /* Additional headers */
270       if (http_opt_headers_count == 0)
271         http_opt_headers = malloc (sizeof (char *) * (++http_opt_headers_count));
272       else
273         http_opt_headers = realloc (http_opt_headers, sizeof (char *) * (++http_opt_headers_count));
274       http_opt_headers[http_opt_headers_count - 1] = optarg;
275       /* asprintf (&http_opt_headers, "%s", optarg); */
276       break;
277     case 'L': /* show html link */
278       display_html = TRUE;
279       break;
280     case 'n': /* do not show html link */
281       display_html = FALSE;
282       break;
283     case 'C': /* Check SSL cert validity */
284 #ifdef HAVE_SSL
285       if (!is_intnonneg (optarg))
286         usage2 (_("Invalid certificate expiration period"), optarg);
287       else {
288         days_till_exp = atoi (optarg);
289         check_cert = TRUE;
290       }
291      /* Fall through to -S option */
292 #endif
293     case 'S': /* use SSL */
294 #ifndef HAVE_SSL
295       usage4 (_("Invalid option - SSL is not available"));
296 #endif
297       use_ssl = TRUE;
298       if (specify_port == FALSE)
299         server_port = HTTPS_PORT;
300       break;
301     case 'f': /* onredirect */
302       if (!strcmp (optarg, "follow"))
303         onredirect = STATE_DEPENDENT;
304       if (!strcmp (optarg, "unknown"))
305         onredirect = STATE_UNKNOWN;
306       if (!strcmp (optarg, "ok"))
307         onredirect = STATE_OK;
308       if (!strcmp (optarg, "warning"))
309         onredirect = STATE_WARNING;
310       if (!strcmp (optarg, "critical"))
311         onredirect = STATE_CRITICAL;
312       if (verbose)
313         printf(_("option f:%d \n"), onredirect);  
314       break;
315     /* Note: H, I, and u must be malloc'd or will fail on redirects */
316     case 'H': /* Host Name (virtual host) */
317       host_name = strdup (optarg);
318       if (host_name[0] == '[') {
319         if ((p = strstr (host_name, "]:")) != NULL) /* [IPv6]:port */
320           server_port = atoi (p + 2);
321       } else if ((p = strchr (host_name, ':')) != NULL
322                  && strchr (++p, ':') == NULL) /* IPv4:port or host:port */
323           server_port = atoi (p);
324       break;
325     case 'I': /* Server IP-address */
326       server_address = strdup (optarg);
327       break;
328     case 'u': /* URL path */
329       server_url = strdup (optarg);
330       server_url_length = strlen (server_url);
331       break;
332     case 'p': /* Server port */
333       if (!is_intnonneg (optarg))
334         usage2 (_("Invalid port number"), optarg);
335       else {
336         server_port = atoi (optarg);
337         specify_port = TRUE;
338       }
339       break;
340     case 'a': /* authorization info */
341       strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1);
342       user_auth[MAX_INPUT_BUFFER - 1] = 0;
343       break;
344     case 'P': /* HTTP POST data in URL encoded format */
345       if (http_method || http_post_data) break;
346       http_method = strdup("POST");
347       http_post_data = strdup (optarg);
348       break;
349     case 's': /* string or substring */
350       strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1);
351       string_expect[MAX_INPUT_BUFFER - 1] = 0;
352       break;
353     case 'e': /* string or substring */
354       strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1);
355       server_expect[MAX_INPUT_BUFFER - 1] = 0;
356       server_expect_yn = 1;
357       break;
358     case 'T': /* Content-type */
359       asprintf (&http_content_type, "%s", optarg);
360       break;
361     case 'l': /* linespan */
362       cflags &= ~REG_NEWLINE;
363       break;
364     case 'R': /* regex */
365       cflags |= REG_ICASE;
366     case 'r': /* regex */
367       strncpy (regexp, optarg, MAX_RE_SIZE - 1);
368       regexp[MAX_RE_SIZE - 1] = 0;
369       errcode = regcomp (&preg, regexp, cflags);
370       if (errcode != 0) {
371         (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
372         printf (_("Could Not Compile Regular Expression: %s"), errbuf);
373         return ERROR;
374       }
375       break;
376     case INVERT_REGEX:
377       invert_regex = 1;
378       break;
379     case '4':
380       address_family = AF_INET;
381       break;
382     case '6':
383 #ifdef USE_IPV6
384       address_family = AF_INET6;
385 #else
386       usage4 (_("IPv6 support not available"));
387 #endif
388       break;
389     case 'v': /* verbose */
390       verbose = TRUE;
391       break;
392     case 'm': /* min_page_length */
393       {
394       char *tmp;
395       if (strchr(optarg, ':') != (char *)NULL) {
396         /* range, so get two values, min:max */
397         tmp = strtok(optarg, ":");
398         if (tmp == NULL) {
399           printf("Bad format: try \"-m min:max\"\n");
400           exit (STATE_WARNING);
401         } else
402           min_page_len = atoi(tmp);
404         tmp = strtok(NULL, ":");
405         if (tmp == NULL) {
406           printf("Bad format: try \"-m min:max\"\n");
407           exit (STATE_WARNING);
408         } else
409           max_page_len = atoi(tmp);
410       } else 
411         min_page_len = atoi (optarg);
412       break;
413       }
414     case 'N': /* no-body */
415       no_body = TRUE;
416       break;
417     case 'M': /* max-age */
418                   {
419                     int L = strlen(optarg);
420                     if (L && optarg[L-1] == 'm')
421                       maximum_age = atoi (optarg) * 60;
422                     else if (L && optarg[L-1] == 'h')
423                       maximum_age = atoi (optarg) * 60 * 60;
424                     else if (L && optarg[L-1] == 'd')
425                       maximum_age = atoi (optarg) * 60 * 60 * 24;
426                     else if (L && (optarg[L-1] == 's' ||
427                                    isdigit (optarg[L-1])))
428                       maximum_age = atoi (optarg);
429                     else {
430                       fprintf (stderr, "unparsable max-age: %s\n", optarg);
431                       exit (STATE_WARNING);
432                     }
433                   }
434                   break;
435     }
436   }
438   c = optind;
440   if (server_address == NULL && c < argc)
441     server_address = strdup (argv[c++]);
443   if (host_name == NULL && c < argc)
444     host_name = strdup (argv[c++]);
446   if (server_address == NULL) {
447     if (host_name == NULL)
448       usage4 (_("You must specify a server address or host name"));
449     else
450       server_address = strdup (host_name);
451   }
453   if (check_critical_time && critical_time>(double)socket_timeout)
454     socket_timeout = (int)critical_time + 1;
456   if (http_method == NULL)
457     http_method = strdup ("GET");
459   return TRUE;
464 /* Returns 1 if we're done processing the document body; 0 to keep going */
465 static int
466 document_headers_done (char *full_page)
468   const char *body;
470   for (body = full_page; *body; body++) {
471     if (!strncmp (body, "\n\n", 2) || !strncmp (body, "\n\r\n", 3))
472       break;
473   }
475   if (!*body)
476     return 0;  /* haven't read end of headers yet */
478   full_page[body - full_page] = 0;
479   return 1;
482 static time_t
483 parse_time_string (const char *string)
485   struct tm tm;
486   time_t t;
487   memset (&tm, 0, sizeof(tm));
489   /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */
491   if (isupper (string[0])  &&  /* Tue */
492     islower (string[1])  &&
493     islower (string[2])  &&
494     ',' ==   string[3]   &&
495     ' ' ==   string[4]   &&
496     (isdigit(string[5]) || string[5] == ' ') &&   /* 25 */
497     isdigit (string[6])  &&
498     ' ' ==   string[7]   &&
499     isupper (string[8])  &&  /* Dec */
500     islower (string[9])  &&
501     islower (string[10]) &&
502     ' ' ==   string[11]  &&
503     isdigit (string[12]) &&  /* 2001 */
504     isdigit (string[13]) &&
505     isdigit (string[14]) &&
506     isdigit (string[15]) &&
507     ' ' ==   string[16]  &&
508     isdigit (string[17]) &&  /* 02: */
509     isdigit (string[18]) &&
510     ':' ==   string[19]  &&
511     isdigit (string[20]) &&  /* 59: */
512     isdigit (string[21]) &&
513     ':' ==   string[22]  &&
514     isdigit (string[23]) &&  /* 03 */
515     isdigit (string[24]) &&
516     ' ' ==   string[25]  &&
517     'G' ==   string[26]  &&  /* GMT */
518     'M' ==   string[27]  &&  /* GMT */
519     'T' ==   string[28]) {
521     tm.tm_sec  = 10 * (string[23]-'0') + (string[24]-'0');
522     tm.tm_min  = 10 * (string[20]-'0') + (string[21]-'0');
523     tm.tm_hour = 10 * (string[17]-'0') + (string[18]-'0');
524     tm.tm_mday = 10 * (string[5] == ' ' ? 0 : string[5]-'0') + (string[6]-'0');
525     tm.tm_mon = (!strncmp (string+8, "Jan", 3) ? 0 :
526       !strncmp (string+8, "Feb", 3) ? 1 :
527       !strncmp (string+8, "Mar", 3) ? 2 :
528       !strncmp (string+8, "Apr", 3) ? 3 :
529       !strncmp (string+8, "May", 3) ? 4 :
530       !strncmp (string+8, "Jun", 3) ? 5 :
531       !strncmp (string+8, "Jul", 3) ? 6 :
532       !strncmp (string+8, "Aug", 3) ? 7 :
533       !strncmp (string+8, "Sep", 3) ? 8 :
534       !strncmp (string+8, "Oct", 3) ? 9 :
535       !strncmp (string+8, "Nov", 3) ? 10 :
536       !strncmp (string+8, "Dec", 3) ? 11 :
537       -1);
538     tm.tm_year = ((1000 * (string[12]-'0') +
539       100 * (string[13]-'0') +
540       10 * (string[14]-'0') +
541       (string[15]-'0'))
542       - 1900);
544     tm.tm_isdst = 0;  /* GMT is never in DST, right? */
546     if (tm.tm_mon < 0 || tm.tm_mday < 1 || tm.tm_mday > 31)
547       return 0;
549     /* 
550     This is actually wrong: we need to subtract the local timezone
551     offset from GMT from this value.  But, that's ok in this usage,
552     because we only comparing these two GMT dates against each other,
553     so it doesn't matter what time zone we parse them in.
554     */
556     t = mktime (&tm);
557     if (t == (time_t) -1) t = 0;
559     if (verbose) {
560       const char *s = string;
561       while (*s && *s != '\r' && *s != '\n')
562       fputc (*s++, stdout);
563       printf (" ==> %lu\n", (unsigned long) t);
564     }
566     return t;
568   } else {
569     return 0;
570   }
575 static void
576 check_document_dates (const char *headers)
578   const char *s;
579   char *server_date = 0;
580   char *document_date = 0;
582   s = headers;
583   while (*s) {
584     const char *field = s;
585     const char *value = 0;
587     /* Find the end of the header field */
588     while (*s && !isspace(*s) && *s != ':')
589       s++;
591     /* Remember the header value, if any. */
592     if (*s == ':')
593       value = ++s;
595     /* Skip to the end of the header, including continuation lines. */
596     while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
597       s++;
598     s++;
600     /* Process this header. */
601     if (value && value > field+2) {
602       char *ff = (char *) malloc (value-field);
603       char *ss = ff;
604       while (field < value-1)
605         *ss++ = tolower(*field++);
606       *ss++ = 0;
608       if (!strcmp (ff, "date") || !strcmp (ff, "last-modified")) {
609         const char *e;
610         while (*value && isspace (*value))
611           value++;
612         for (e = value; *e && *e != '\r' && *e != '\n'; e++)
613           ;
614         ss = (char *) malloc (e - value + 1);
615         strncpy (ss, value, e - value);
616         ss[e - value] = 0;
617         if (!strcmp (ff, "date")) {
618           if (server_date) free (server_date);
619           server_date = ss;
620         } else {
621           if (document_date) free (document_date);
622           document_date = ss;
623         }
624       }
625       free (ff);
626     }
627   }
629   /* Done parsing the body.  Now check the dates we (hopefully) parsed.  */
630   if (!server_date || !*server_date) {
631     die (STATE_UNKNOWN, _("HTTP UNKNOWN - Server date unknown\n"));
632   } else if (!document_date || !*document_date) {
633     die (STATE_CRITICAL, _("HTTP CRITICAL - Document modification date unknown\n"));
634   } else {
635     time_t srv_data = parse_time_string (server_date);
636     time_t doc_data = parse_time_string (document_date);
638     if (srv_data <= 0) {
639       die (STATE_CRITICAL, _("HTTP CRITICAL - Server date \"%100s\" unparsable"), server_date);
640     } else if (doc_data <= 0) {
641       die (STATE_CRITICAL, _("HTTP CRITICAL - Document date \"%100s\" unparsable"), document_date);
642     } else if (doc_data > srv_data + 30) {
643       die (STATE_CRITICAL, _("HTTP CRITICAL - Document is %d seconds in the future\n"), (int)doc_data - (int)srv_data);
644     } else if (doc_data < srv_data - maximum_age) {
645     int n = (srv_data - doc_data);
646     if (n > (60 * 60 * 24 * 2))
647       die (STATE_CRITICAL,
648         _("HTTP CRITICAL - Last modified %.1f days ago\n"),
649         ((float) n) / (60 * 60 * 24));
650   else
651     die (STATE_CRITICAL,
652         _("HTTP CRITICAL - Last modified %d:%02d:%02d ago\n"),
653         n / (60 * 60), (n / 60) % 60, n % 60);
654     }
656     free (server_date);
657     free (document_date);
658   }
661 int
662 get_content_length (const char *headers)
664   const char *s;
665   int content_length = 0;
667   s = headers;
668   while (*s) {
669     const char *field = s;
670     const char *value = 0;
672     /* Find the end of the header field */
673     while (*s && !isspace(*s) && *s != ':')
674       s++;
676     /* Remember the header value, if any. */
677     if (*s == ':')
678       value = ++s;
680     /* Skip to the end of the header, including continuation lines. */
681     while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
682       s++;
683     s++;
685     /* Process this header. */
686     if (value && value > field+2) {
687       char *ff = (char *) malloc (value-field);
688       char *ss = ff;
689       while (field < value-1)
690         *ss++ = tolower(*field++);
691       *ss++ = 0;
693       if (!strcmp (ff, "content-length")) {
694         const char *e;
695         while (*value && isspace (*value))
696           value++;
697         for (e = value; *e && *e != '\r' && *e != '\n'; e++)
698           ;
699         ss = (char *) malloc (e - value + 1);
700         strncpy (ss, value, e - value);
701         ss[e - value] = 0;
702         content_length = atoi(ss);
703         free (ss);
704       }
705       free (ff);
706     }
707   }
708   return (content_length);
711 int
712 check_http (void)
714   char *msg;
715   char *status_line;
716   char *status_code;
717   char *header;
718   char *page;
719   char *auth;
720   int http_status;
721   int i = 0;
722   size_t pagesize = 0;
723   char *full_page;
724   char *buf;
725   char *pos;
726   long microsec;
727   double elapsed_time;
728   int page_len = 0;
729   int result = STATE_UNKNOWN;
731   /* try to connect to the host at the given port number */
732   if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
733     die (STATE_CRITICAL, _("HTTP CRITICAL - Unable to open TCP socket\n"));
734 #ifdef HAVE_SSL
735   if (use_ssl == TRUE) {
736     np_net_ssl_init(sd);
737     if (check_cert == TRUE) {
738       result = np_net_ssl_check_cert(days_till_exp);
739       np_net_ssl_cleanup();
740       if(sd) close(sd);
741       return result;
742     }
743   }
744 #endif /* HAVE_SSL */
746   asprintf (&buf, "%s %s HTTP/1.0\r\n%s\r\n", http_method, server_url, user_agent);
748   /* tell HTTP/1.1 servers not to keep the connection alive */
749   asprintf (&buf, "%sConnection: close\r\n", buf);
751   /* optionally send the host header info */
752   if (host_name)
753     asprintf (&buf, "%sHost: %s\r\n", buf, host_name);
755   /* optionally send any other header tag */
756   if (http_opt_headers_count) {
757     for (i = 0; i < http_opt_headers_count ; i++) {
758       for ((pos = strtok(http_opt_headers[i], INPUT_DELIMITER)); pos; (pos = strtok(NULL, INPUT_DELIMITER)))
759         asprintf (&buf, "%s%s\r\n", buf, pos);
760     }
761     free(http_opt_headers);
762   }
764   /* optionally send the authentication info */
765   if (strlen(user_auth)) {
766     base64_encode_alloc (user_auth, strlen (user_auth), &auth);
767     asprintf (&buf, "%sAuthorization: Basic %s\r\n", buf, auth);
768   }
770   /* either send http POST data */
771   if (http_post_data) {
772     if (http_content_type) {
773       asprintf (&buf, "%sContent-Type: %s\r\n", buf, http_content_type);
774     } else {
775       asprintf (&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf);
776     }
777     
778     asprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data));
779     asprintf (&buf, "%s%s%s", buf, http_post_data, CRLF);
780   }
781   else {
782     /* or just a newline so the server knows we're done with the request */
783     asprintf (&buf, "%s%s", buf, CRLF);
784   }
786   if (verbose) printf ("%s\n", buf);
787   my_send (buf, strlen (buf));
789   /* fetch the page */
790   full_page = strdup("");
791   while ((i = my_recv (buffer, MAX_INPUT_BUFFER-1)) > 0) {
792     buffer[i] = '\0';
793     asprintf (&full_page, "%s%s", full_page, buffer);
794     pagesize += i;
796                 if (no_body && document_headers_done (full_page)) {
797                   i = 0;
798                   break;
799                 }
800   }
802   if (i < 0 && errno != ECONNRESET) {
803 #ifdef HAVE_SSL
804     /*
805     if (use_ssl) {
806       sslerr=SSL_get_error(ssl, i);
807       if ( sslerr == SSL_ERROR_SSL ) {
808         die (STATE_WARNING, _("HTTP WARNING - Client Certificate Required\n"));
809       } else {
810         die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
811       }
812     }
813     else {
814     */
815 #endif
816       die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
817 #ifdef HAVE_SSL
818       /* XXX
819     }
820     */
821 #endif
822   }
824   /* return a CRITICAL status if we couldn't read any data */
825   if (pagesize == (size_t) 0)
826     die (STATE_CRITICAL, _("HTTP CRITICAL - No data received from host\n"));
828   /* close the connection */
829 #ifdef HAVE_SSL
830   np_net_ssl_cleanup();
831 #endif
832   if(sd) close(sd);
834   /* reset the alarm */
835   alarm (0);
837   /* leave full_page untouched so we can free it later */
838   page = full_page;
840   if (verbose)
841     printf ("%s://%s:%d%s is %d characters\n",
842       use_ssl ? "https" : "http", server_address,
843       server_port, server_url, (int)pagesize);
845   /* find status line and null-terminate it */
846   status_line = page;
847   page += (size_t) strcspn (page, "\r\n");
848   pos = page;
849   page += (size_t) strspn (page, "\r\n");
850   status_line[strcspn(status_line, "\r\n")] = 0;
851   strip (status_line);
852   if (verbose)
853     printf ("STATUS: %s\n", status_line);
855   /* find header info and null-terminate it */
856   header = page;
857   while (strcspn (page, "\r\n") > 0) {
858     page += (size_t) strcspn (page, "\r\n");
859     pos = page;
860     if ((strspn (page, "\r") == 1 && strspn (page, "\r\n") >= 2) ||
861         (strspn (page, "\n") == 1 && strspn (page, "\r\n") >= 2))
862       page += (size_t) 2;
863     else
864       page += (size_t) 1;
865   }
866   page += (size_t) strspn (page, "\r\n");
867   header[pos - header] = 0;
868   if (verbose)
869     printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header,
870                 (no_body ? "  [[ skipped ]]" : page));
872   /* make sure the status line matches the response we are looking for */
873   if (!strstr (status_line, server_expect)) {
874     if (server_port == HTTP_PORT)
875       asprintf (&msg,
876                 _("Invalid HTTP response received from host\n"));
877     else
878       asprintf (&msg,
879                 _("Invalid HTTP response received from host on port %d\n"),
880                 server_port);
881     die (STATE_CRITICAL, "HTTP CRITICAL - %s", msg);
882   }
884   /* Exit here if server_expect was set by user and not default */
885   if ( server_expect_yn  )  {
886     asprintf (&msg,
887               _("HTTP OK: Status line output matched \"%s\"\n"),
888               server_expect);
889     if (verbose)
890       printf ("%s\n",msg);
891   }
892   else {
893     /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
894     /* HTTP-Version   = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
895     /* Status-Code = 3 DIGITS */
897     status_code = strchr (status_line, ' ') + sizeof (char);
898     if (strspn (status_code, "1234567890") != 3)
899       die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line);
901     http_status = atoi (status_code);
903     /* check the return code */
905     if (http_status >= 600 || http_status < 100)
906       die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line);
908     /* server errors result in a critical state */
909     else if (http_status >= 500)
910       die (STATE_CRITICAL, _("HTTP CRITICAL: %s\n"), status_line);
912     /* client errors result in a warning state */
913     else if (http_status >= 400)
914       die (STATE_WARNING, _("HTTP WARNING: %s\n"), status_line);
916     /* check redirected page if specified */
917     else if (http_status >= 300) {
919       if (onredirect == STATE_DEPENDENT)
920         redir (header, status_line);
921       else if (onredirect == STATE_UNKNOWN)
922         printf (_("HTTP UNKNOWN"));
923       else if (onredirect == STATE_OK)
924         printf (_("HTTP OK"));
925       else if (onredirect == STATE_WARNING)
926         printf (_("HTTP WARNING"));
927       else if (onredirect == STATE_CRITICAL)
928         printf (_("HTTP CRITICAL"));
929       microsec = deltime (tv);
930       elapsed_time = (double)microsec / 1.0e6;
931       die (onredirect,
932            _(" - %s - %.3f second response time %s|%s %s\n"),
933            status_line, elapsed_time, 
934            (display_html ? "</A>" : ""),
935            perfd_time (elapsed_time), perfd_size (pagesize));
936     } /* end if (http_status >= 300) */
938   } /* end else (server_expect_yn)  */
939     
940         if (maximum_age >= 0) {
941           check_document_dates (header);
942         }
944   /* check elapsed time */
945   microsec = deltime (tv);
946   elapsed_time = (double)microsec / 1.0e6;
947   asprintf (&msg,
948             _(" - %s - %.3f second response time %s|%s %s\n"),
949             status_line, elapsed_time, 
950             (display_html ? "</A>" : ""),
951             perfd_time (elapsed_time), perfd_size (pagesize));
952   if (check_critical_time == TRUE && elapsed_time > critical_time)
953     die (STATE_CRITICAL, "HTTP %s: %s", _("CRITICAL"), msg);
954   if (check_warning_time == TRUE && elapsed_time > warning_time)
955     die (STATE_WARNING, "HTTP %s: %s", _("WARNING"), msg);
957   /* Page and Header content checks go here */
958   /* these checks should be last */
960   if (strlen (string_expect)) {
961     if (strstr (page, string_expect)) {
962       printf (_("HTTP OK %s - %.3f second response time %s|%s %s\n"),
963               status_line, elapsed_time,
964               (display_html ? "</A>" : ""),
965               perfd_time (elapsed_time), perfd_size (pagesize));
966       exit (STATE_OK);
967     }
968     else {
969       printf (_("HTTP CRITICAL - string not found%s|%s %s\n"),
970               (display_html ? "</A>" : ""),
971               perfd_time (elapsed_time), perfd_size (pagesize));
972       exit (STATE_CRITICAL);
973     }
974   }
976   if (strlen (regexp)) {
977     errcode = regexec (&preg, page, REGS, pmatch, 0);
978     if ((errcode == 0 && invert_regex == 0) || (errcode == REG_NOMATCH && invert_regex == 1)) {
979       printf (_("HTTP OK %s - %.3f second response time %s|%s %s\n"),
980               status_line, elapsed_time,
981               (display_html ? "</A>" : ""),
982               perfd_time (elapsed_time), perfd_size (pagesize));
983       exit (STATE_OK);
984     }
985     else if ((errcode == REG_NOMATCH && invert_regex == 0) || (errcode == 0 && invert_regex == 1)) {
986       if (invert_regex == 0) 
987         msg = strdup(_("pattern not found"));
988       else 
989         msg = strdup(_("pattern found"));
990       printf (("%s - %s%s|%s %s\n"),
991         _("HTTP CRITICAL"),
992         msg,
993         (display_html ? "</A>" : ""),
994         perfd_time (elapsed_time), perfd_size (pagesize));
995       exit (STATE_CRITICAL);
996     }
997     else {
998       regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
999       printf (_("HTTP CRITICAL - Execute Error: %s\n"), errbuf);
1000       exit (STATE_CRITICAL);
1001     }
1002   }
1004   /* make sure the page is of an appropriate size */
1005   /* page_len = get_content_length(header); */
1006   page_len = pagesize;
1007   if ((max_page_len > 0) && (page_len > max_page_len)) {
1008     printf (_("HTTP WARNING: page size %d too large%s|%s\n"),
1009       page_len, (display_html ? "</A>" : ""), perfd_size (page_len) );
1010     exit (STATE_WARNING);
1011   } else if ((min_page_len > 0) && (page_len < min_page_len)) {
1012     printf (_("HTTP WARNING: page size %d too small%s|%s\n"),
1013       page_len, (display_html ? "</A>" : ""), perfd_size (page_len) );
1014     exit (STATE_WARNING);
1015   }
1016   /* We only get here if all tests have been passed */
1017   asprintf (&msg, _("HTTP OK %s - %d bytes in %.3f seconds %s|%s %s\n"),
1018             status_line, page_len, elapsed_time,
1019             (display_html ? "</A>" : ""),
1020             perfd_time (elapsed_time), perfd_size (page_len));
1021   die (STATE_OK, "%s", msg);
1022   return STATE_UNKNOWN;
1027 /* per RFC 2396 */
1028 #define URI_HTTP "%5[HTPShtps]"
1029 #define URI_HOST "%255[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1030 #define URI_PORT "%6d" /* MAX_PORT's width is 5 chars, 6 to detect overflow */
1031 #define URI_PATH "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1032 #define HD1 URI_HTTP "://" URI_HOST ":" URI_PORT "/" URI_PATH
1033 #define HD2 URI_HTTP "://" URI_HOST "/" URI_PATH
1034 #define HD3 URI_HTTP "://" URI_HOST ":" URI_PORT
1035 #define HD4 URI_HTTP "://" URI_HOST
1036 #define HD5 URI_PATH
1038 void
1039 redir (char *pos, char *status_line)
1041   int i = 0;
1042   char *x;
1043   char xx[2];
1044   char type[6];
1045   char *addr;
1046   char *url;
1048   addr = malloc (MAX_IPV4_HOSTLENGTH + 1);
1049   if (addr == NULL)
1050     die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate addr\n"));
1051   
1052   url = malloc (strcspn (pos, "\r\n"));
1053   if (url == NULL)
1054     die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate url\n"));
1056   while (pos) {
1057     sscanf (pos, "%1[Ll]%*1[Oo]%*1[Cc]%*1[Aa]%*1[Tt]%*1[Ii]%*1[Oo]%*1[Nn]:%n", xx, &i);
1058     if (i == 0) {
1059       pos += (size_t) strcspn (pos, "\r\n");
1060       pos += (size_t) strspn (pos, "\r\n");
1061       if (strlen(pos) == 0) 
1062         die (STATE_UNKNOWN,
1063              _("HTTP UNKNOWN - Could not find redirect location - %s%s\n"),
1064              status_line, (display_html ? "</A>" : ""));
1065       continue;
1066     }
1068     pos += i;
1069     pos += strspn (pos, " \t");
1071     /*
1072      * RFC 2616 (4.2):  ``Header fields can be extended over multiple lines by
1073      * preceding each extra line with at least one SP or HT.''
1074      */
1075     for (; (i = strspn (pos, "\r\n")); pos += i) {
1076       pos += i;
1077       if (!(i = strspn (pos, " \t"))) {
1078         die (STATE_UNKNOWN, _("HTTP UNKNOWN - Empty redirect location%s\n"),
1079              display_html ? "</A>" : "");
1080       }
1081     }
1083     url = realloc (url, strcspn (pos, "\r\n") + 1);
1084     if (url == NULL)
1085       die (STATE_UNKNOWN, _("HTTP UNKNOWN - could not allocate url\n"));
1087     /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
1088     if (sscanf (pos, HD1, type, addr, &i, url) == 4)
1089       use_ssl = server_type_check (type);
1091     /* URI_HTTP URI_HOST URI_PATH */
1092     else if (sscanf (pos, HD2, type, addr, url) == 3 ) { 
1093       use_ssl = server_type_check (type);
1094       i = server_port_check (use_ssl);
1095     }
1097     /* URI_HTTP URI_HOST URI_PORT */
1098     else if(sscanf (pos, HD3, type, addr, &i) == 3) {
1099       strcpy (url, HTTP_URL);
1100       use_ssl = server_type_check (type);
1101     }
1103     /* URI_HTTP URI_HOST */
1104     else if(sscanf (pos, HD4, type, addr) == 2) {
1105       strcpy (url, HTTP_URL);
1106       use_ssl = server_type_check (type);
1107       i = server_port_check (use_ssl);
1108     }
1110     /* URI_PATH */
1111     else if (sscanf (pos, HD5, url) == 1) {
1112       /* relative url */
1113       if ((url[0] != '/')) {
1114         if ((x = strrchr(server_url, '/')))
1115           *x = '\0';
1116         asprintf (&url, "%s/%s", server_url, url);
1117       }
1118       i = server_port;
1119       strcpy (type, server_type);
1120       strcpy (addr, host_name ? host_name : server_address);
1121     }           
1123     else {
1124       die (STATE_UNKNOWN,
1125            _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"),
1126            pos, (display_html ? "</A>" : ""));
1127     }
1129     break;
1131   } /* end while (pos) */
1133   if (++redir_depth > max_depth)
1134     die (STATE_WARNING,
1135          _("HTTP WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"),
1136          max_depth, type, addr, i, url, (display_html ? "</A>" : ""));
1138   if (server_port==i &&
1139       !strcmp(server_address, addr) &&
1140       (host_name && !strcmp(host_name, addr)) &&
1141       !strcmp(server_url, url))
1142     die (STATE_WARNING,
1143          _("HTTP WARNING - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
1144          type, addr, i, url, (display_html ? "</A>" : ""));
1146   strcpy (server_type, type);
1148   free (host_name);
1149   host_name = strdup (addr);
1151   free (server_address);
1152   server_address = strdup (addr);
1154   free (server_url);
1155   if ((url[0] == '/'))
1156     server_url = strdup (url);
1157   else if (asprintf(&server_url, "/%s", url) == -1)
1158     die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate server_url%s\n"),
1159          display_html ? "</A>" : "");
1160   free(url);
1162   if ((server_port = i) > MAX_PORT)
1163     die (STATE_UNKNOWN,
1164          _("HTTP UNKNOWN - Redirection to port above %d - %s://%s:%d%s%s\n"),
1165          MAX_PORT, server_type, server_address, server_port, server_url,
1166          display_html ? "</A>" : "");
1168   if (verbose)
1169     printf (_("Redirection to %s://%s:%d%s\n"), server_type,
1170             host_name ? host_name : server_address, server_port, server_url);
1172   check_http ();
1177 int
1178 server_type_check (const char *type)
1180   if (strcmp (type, "https"))
1181     return FALSE;
1182   else
1183     return TRUE;
1186 int
1187 server_port_check (int ssl_flag)
1189   if (ssl_flag)
1190     return HTTPS_PORT;
1191   else
1192     return HTTP_PORT;
1195 char *perfd_time (double elapsed_time)
1197   return fperfdata ("time", elapsed_time, "s",
1198             check_warning_time, warning_time,
1199             check_critical_time, critical_time,
1200                    TRUE, 0, FALSE, 0);
1205 char *perfd_size (int page_len)
1207   return perfdata ("size", page_len, "B",
1208             (min_page_len>0?TRUE:FALSE), min_page_len,
1209             (min_page_len>0?TRUE:FALSE), 0,
1210             TRUE, 0, FALSE, 0);
1213 void
1214 print_help (void)
1216   print_revision (progname, revision);
1218   printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1219   printf (COPYRIGHT, copyright, email);
1221   printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test"));
1222   printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for"));
1223   printf ("%s\n", _("strings and regular expressions, check connection times, and report on"));
1224   printf ("%s\n", _("certificate expiration times."));
1226   printf ("\n\n");
1228   print_usage ();
1230   printf (_("NOTE: One or both of -H and -I must be specified"));
1232   printf ("\n");
1234   printf (_(UT_HELP_VRSN));
1236   printf (" %s\n", "-H, --hostname=ADDRESS");
1237   printf ("    %s\n", _("Host name argument for servers using host headers (virtual host)"));
1238   printf ("    %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
1239   printf (" %s\n", "-I, --IP-address=ADDRESS");
1240   printf ("    %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
1241   printf (" %s\n", "-p, --port=INTEGER");
1242   printf (" %s", _("Port number (default: "));
1243   printf ("%d)\n", HTTP_PORT);
1245   printf (_(UT_IPv46));
1247 #ifdef HAVE_SSL
1248   printf (" %s\n", "-S, --ssl");
1249   printf ("   %s\n", _("Connect via SSL. Port defaults to 443"));
1250   printf (" %s\n", "-C, --certificate=INTEGER");
1251   printf ("   %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443"));
1252   printf ("   %s\n", _("(when this option is used the url is not checked.)\n"));
1253 #endif
1255   printf (" %s\n", "-e, --expect=STRING");
1256   printf ("    %s\n", _("String to expect in first (status) line of server response (default: "));
1257   printf ("%s)\n", HTTP_EXPECT);
1258   printf ("    %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
1259   printf (" %s\n", "-s, --string=STRING");
1260   printf ("    %s\n", _("String to expect in the content"));
1261   printf (" %s\n", "-u, --url=PATH");
1262   printf ("    %s\n", _("URL to GET or POST (default: /)"));
1263   printf (" %s\n", "-P, --post=STRING");
1264   printf ("    %s\n", _("URL encoded http POST data"));
1265   printf (" %s\n", "-N, --no-body");
1266   printf ("    %s\n", _("Don't wait for document body: stop reading after headers."));
1267   printf ("    %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)"));
1268   printf (" %s\n", "-M, --max-age=SECONDS");
1269   printf ("    %s\n", _("Warn if document is more than SECONDS old. the number can also be of"));
1270   printf ("    %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
1271   printf (" %s\n", "-T, --content-type=STRING");
1272   printf ("    %s\n", _("specify Content-Type header media type when POSTing\n"));
1274   printf (" %s\n", "-l, --linespan");
1275   printf ("    %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
1276   printf (" %s\n", "-r, --regex, --ereg=STRING");
1277   printf ("    %s\n", _("Search page for regex STRING"));
1278   printf (" %s\n", "-R, --eregi=STRING");
1279   printf ("    %s\n", _("Search page for case-insensitive regex STRING"));
1280   printf (" %s\n", "--invert-regex");
1281   printf ("    %s\n", _("Return CRITICAL if found, OK if not\n"));
1283   printf (" %s\n", "-a, --authorization=AUTH_PAIR");
1284   printf ("    %s\n", _("Username:password on sites with basic authentication"));
1285   printf (" %s\n", "-A, --useragent=STRING");
1286   printf ("    %s\n", _("String to be sent in http header as \"User Agent\""));
1287   printf (" %s\n", "-k, --header=STRING");
1288   printf ("    %s\n", _(" Any other tags to be sent in http header. Use multiple times for additional headers"));
1289   printf (" %s\n", "-L, --link");
1290   printf ("    %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
1291   printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow>");
1292   printf ("    %s\n", _("How to handle redirected pages"));
1293   printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
1294   printf ("    %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
1296   printf (_(UT_WARN_CRIT));
1298   printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
1300   printf (_(UT_VERBOSE));
1302   printf (_("Notes:"));
1303   printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
1304   printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
1305   printf (" %s\n", _("other errors return STATE_UNKNOWN.  Successful connects, but incorrect reponse"));
1306   printf (" %s\n", _("messages from the host result in STATE_WARNING return values.  If you are"));
1307   printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
1308   printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
1310 #ifdef HAVE_SSL
1311   printf (" %s\n", _("This plugin can also check whether an SSL enabled web server is able to"));
1312   printf (" %s\n", _("serve content (optionally within a specified time) or whether the X509 "));
1313   printf (" %s\n", _("certificate is still valid for the specified number of days."));
1314   printf (_("Examples:"));
1315   printf (" %s\n\n", "CHECK CONTENT: check_http -w 5 -c 10 --ssl -H www.verisign.com");
1316   printf (" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
1317   printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
1318   printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
1319   printf (" %s\n\n", _("a STATE_CRITICAL will be returned."));
1321   printf (" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 14");
1322   printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
1323   printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
1324   printf (" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
1325   printf (" %s\n\n", _("the certificate is expired."));
1326 #endif
1328   printf (_(UT_SUPPORT));
1334 void
1335 print_usage (void)
1337   printf (_("Usage:"));
1338   printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname);
1339   printf ("       [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L]\n");
1340   printf ("       [-a auth] [-f <ok | warn | critcal | follow>] [-e <expect>]\n");
1341   printf ("       [-s string] [-l] [-r <regex> | -R <case-insensitive regex>] [-P string]\n");
1342   printf ("       [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>] [-A string]\n");
1343   printf ("       [-k string] [-S] [-C <age>] [-T <content-type>]\n");