Code

5e33ec86113e485a55a24b1750e3ef6aea799bab
[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 };
59 #ifdef HAVE_SSL
60 int check_cert = FALSE;
61 int days_till_exp;
62 char *randbuff;
63 X509 *server_cert;
64 #  define my_recv(buf, len) ((use_ssl) ? np_net_ssl_read(buf, len) : read(sd, buf, len))
65 #  define my_send(buf, len) ((use_ssl) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
66 #else /* ifndef HAVE_SSL */
67 #  define my_recv(buf, len) read(sd, buf, len)
68 #  define my_send(buf, len) send(sd, buf, len, 0)
69 #endif /* HAVE_SSL */
70 int no_body = FALSE;
71 int maximum_age = -1;
73 enum {
74   REGS = 2,
75   MAX_RE_SIZE = 256
76 };
77 #include "regex.h"
78 regex_t preg;
79 regmatch_t pmatch[REGS];
80 char regexp[MAX_RE_SIZE];
81 char errbuf[MAX_INPUT_BUFFER];
82 int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
83 int errcode;
84 int invert_regex = 0;
86 struct timeval tv;
88 #define HTTP_URL "/"
89 #define CRLF "\r\n"
91 int specify_port = FALSE;
92 int server_port = HTTP_PORT;
93 char server_port_text[6] = "";
94 char server_type[6] = "http";
95 char *server_address;
96 char *host_name;
97 char *server_url;
98 char *user_agent;
99 int server_url_length;
100 int server_expect_yn = 0;
101 char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
102 char string_expect[MAX_INPUT_BUFFER] = "";
103 double warning_time = 0;
104 int check_warning_time = FALSE;
105 double critical_time = 0;
106 int check_critical_time = FALSE;
107 char user_auth[MAX_INPUT_BUFFER] = "";
108 int display_html = FALSE;
109 char **http_opt_headers;
110 int http_opt_headers_count = 0;
111 int onredirect = STATE_OK;
112 int use_ssl = FALSE;
113 int verbose = FALSE;
114 int sd;
115 int min_page_len = 0;
116 int max_page_len = 0;
117 int redir_depth = 0;
118 int max_depth = 15;
119 char *http_method;
120 char *http_post_data;
121 char *http_content_type;
122 char buffer[MAX_INPUT_BUFFER];
124 int process_arguments (int, char **);
125 static char *base64 (const char *bin, size_t len);
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   /* Set default URL. Must be malloced for subsequent realloc if --onredirect=follow */
141   server_url = strdup(HTTP_URL);
142   server_url_length = strlen(server_url);
143   asprintf (&user_agent, "User-Agent: check_http/%s (nagios-plugins %s)",
144             clean_revstring (revision), VERSION);
146   if (process_arguments (argc, argv) == ERROR)
147     usage4 (_("Could not parse arguments"));
149   if (display_html == TRUE)
150     printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", 
151       use_ssl ? "https" : "http", host_name,
152       server_port, server_url);
154   /* initialize alarm signal handling, set socket timeout, start timer */
155   (void) signal (SIGALRM, socket_timeout_alarm_handler);
156   (void) alarm (socket_timeout);
157   gettimeofday (&tv, NULL);
159   result = check_http ();
160   return result;
165 /* process command-line arguments */
166 int
167 process_arguments (int argc, char **argv)
169   int c = 1;
171   enum {
172     INVERT_REGEX = CHAR_MAX + 1
173   };
175   int option = 0;
176   static struct option longopts[] = {
177     STD_LONG_OPTS,
178     {"link", no_argument, 0, 'L'},
179     {"nohtml", no_argument, 0, 'n'},
180     {"ssl", no_argument, 0, 'S'},
181     {"post", required_argument, 0, 'P'},
182     {"IP-address", required_argument, 0, 'I'},
183     {"url", required_argument, 0, 'u'},
184     {"port", required_argument, 0, 'p'},
185     {"authorization", required_argument, 0, 'a'},
186     {"string", required_argument, 0, 's'},
187     {"expect", required_argument, 0, 'e'},
188     {"regex", required_argument, 0, 'r'},
189     {"ereg", required_argument, 0, 'r'},
190     {"eregi", required_argument, 0, 'R'},
191     {"linespan", no_argument, 0, 'l'},
192     {"onredirect", required_argument, 0, 'f'},
193     {"certificate", required_argument, 0, 'C'},
194     {"useragent", required_argument, 0, 'A'},
195     {"header", required_argument, 0, 'k'},
196     {"no-body", no_argument, 0, 'N'},
197     {"max-age", required_argument, 0, 'M'},
198     {"content-type", required_argument, 0, 'T'},
199     {"pagesize", required_argument, 0, 'm'},
200     {"invert-regex", no_argument, NULL, INVERT_REGEX},
201     {"use-ipv4", no_argument, 0, '4'},
202     {"use-ipv6", no_argument, 0, '6'},
203     {0, 0, 0, 0}
204   };
206   if (argc < 2)
207     return ERROR;
209   for (c = 1; c < argc; c++) {
210     if (strcmp ("-to", argv[c]) == 0)
211       strcpy (argv[c], "-t");
212     if (strcmp ("-hn", argv[c]) == 0)
213       strcpy (argv[c], "-H");
214     if (strcmp ("-wt", argv[c]) == 0)
215       strcpy (argv[c], "-w");
216     if (strcmp ("-ct", argv[c]) == 0)
217       strcpy (argv[c], "-c");
218     if (strcmp ("-nohtml", argv[c]) == 0)
219       strcpy (argv[c], "-n");
220   }
222   while (1) {
223     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);
224     if (c == -1 || c == EOF)
225       break;
227     switch (c) {
228     case '?': /* usage */
229       usage5 ();
230       break;
231     case 'h': /* help */
232       print_help ();
233       exit (STATE_OK);
234       break;
235     case 'V': /* version */
236       print_revision (progname, revision);
237       exit (STATE_OK);
238       break;
239     case 't': /* timeout period */
240       if (!is_intnonneg (optarg))
241         usage2 (_("Timeout interval must be a positive integer"), optarg);
242       else
243         socket_timeout = atoi (optarg);
244       break;
245     case 'c': /* critical time threshold */
246       if (!is_nonnegative (optarg))
247         usage2 (_("Critical threshold must be integer"), optarg);
248       else {
249         critical_time = strtod (optarg, NULL);
250         check_critical_time = TRUE;
251       }
252       break;
253     case 'w': /* warning time threshold */
254       if (!is_nonnegative (optarg))
255         usage2 (_("Warning threshold must be integer"), optarg);
256       else {
257         warning_time = strtod (optarg, NULL);
258         check_warning_time = TRUE;
259       }
260       break;
261     case 'A': /* User Agent String */
262       asprintf (&user_agent, "User-Agent: %s", optarg);
263       break;
264     case 'k': /* Additional headers */
265       if (http_opt_headers_count == 0)
266         http_opt_headers = malloc (sizeof (char *) * (++http_opt_headers_count));
267       else
268         http_opt_headers = realloc (http_opt_headers, sizeof (char *) * (++http_opt_headers_count));
269       http_opt_headers[http_opt_headers_count - 1] = optarg;
270       /* asprintf (&http_opt_headers, "%s", optarg); */
271       break;
272     case 'L': /* show html link */
273       display_html = TRUE;
274       break;
275     case 'n': /* do not show html link */
276       display_html = FALSE;
277       break;
278     case 'C': /* Check SSL cert validity */
279 #ifdef HAVE_SSL
280       if (!is_intnonneg (optarg))
281         usage2 (_("Invalid certificate expiration period"), optarg);
282       else {
283         days_till_exp = atoi (optarg);
284         check_cert = TRUE;
285       }
286      /* Fall through to -S option */
287 #endif
288     case 'S': /* use SSL */
289 #ifndef HAVE_SSL
290       usage4 (_("Invalid option - SSL is not available"));
291 #endif
292       use_ssl = TRUE;
293       if (specify_port == FALSE)
294         server_port = HTTPS_PORT;
295       break;
296     case 'f': /* onredirect */
297       if (!strcmp (optarg, "follow"))
298         onredirect = STATE_DEPENDENT;
299       if (!strcmp (optarg, "unknown"))
300         onredirect = STATE_UNKNOWN;
301       if (!strcmp (optarg, "ok"))
302         onredirect = STATE_OK;
303       if (!strcmp (optarg, "warning"))
304         onredirect = STATE_WARNING;
305       if (!strcmp (optarg, "critical"))
306         onredirect = STATE_CRITICAL;
307       if (verbose)
308         printf(_("option f:%d \n"), onredirect);  
309       break;
310     /* Note: H, I, and u must be malloc'd or will fail on redirects */
311     case 'H': /* Host Name (virtual host) */
312       host_name = strdup (optarg);
313       if (strstr (optarg, ":"))
314         sscanf (optarg, "%*[^:]:%d", &server_port);
315       break;
316     case 'I': /* Server IP-address */
317       server_address = strdup (optarg);
318       break;
319     case 'u': /* URL path */
320       server_url = strdup (optarg);
321       server_url_length = strlen (server_url);
322       break;
323     case 'p': /* Server port */
324       if (!is_intnonneg (optarg))
325         usage2 (_("Invalid port number"), optarg);
326       else {
327         server_port = atoi (optarg);
328         specify_port = TRUE;
329       }
330       break;
331     case 'a': /* authorization info */
332       strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1);
333       user_auth[MAX_INPUT_BUFFER - 1] = 0;
334       break;
335     case 'P': /* HTTP POST data in URL encoded format */
336       if (http_method || http_post_data) break;
337       http_method = strdup("POST");
338       http_post_data = strdup (optarg);
339       break;
340     case 's': /* string or substring */
341       strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1);
342       string_expect[MAX_INPUT_BUFFER - 1] = 0;
343       break;
344     case 'e': /* string or substring */
345       strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1);
346       server_expect[MAX_INPUT_BUFFER - 1] = 0;
347       server_expect_yn = 1;
348       break;
349     case 'T': /* Content-type */
350       asprintf (&http_content_type, "%s", optarg);
351       break;
352     case 'l': /* linespan */
353       cflags &= ~REG_NEWLINE;
354       break;
355     case 'R': /* regex */
356       cflags |= REG_ICASE;
357     case 'r': /* regex */
358       strncpy (regexp, optarg, MAX_RE_SIZE - 1);
359       regexp[MAX_RE_SIZE - 1] = 0;
360       errcode = regcomp (&preg, regexp, cflags);
361       if (errcode != 0) {
362         (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
363         printf (_("Could Not Compile Regular Expression: %s"), errbuf);
364         return ERROR;
365       }
366       break;
367     case INVERT_REGEX:
368       invert_regex = 1;
369       break;
370     case '4':
371       address_family = AF_INET;
372       break;
373     case '6':
374 #ifdef USE_IPV6
375       address_family = AF_INET6;
376 #else
377       usage4 (_("IPv6 support not available"));
378 #endif
379       break;
380     case 'v': /* verbose */
381       verbose = TRUE;
382       break;
383     case 'm': /* min_page_length */
384       {
385       char *tmp;
386       if (strchr(optarg, ':') != (char *)NULL) {
387         /* range, so get two values, min:max */
388         tmp = strtok(optarg, ":");
389         if (tmp == NULL) {
390           printf("Bad format: try \"-m min:max\"\n");
391           exit (STATE_WARNING);
392         } else
393           min_page_len = atoi(tmp);
395         tmp = strtok(NULL, ":");
396         if (tmp == NULL) {
397           printf("Bad format: try \"-m min:max\"\n");
398           exit (STATE_WARNING);
399         } else
400           max_page_len = atoi(tmp);
401       } else 
402         min_page_len = atoi (optarg);
403       break;
404       }
405     case 'N': /* no-body */
406       no_body = TRUE;
407       break;
408     case 'M': /* max-age */
409                   {
410                     int L = strlen(optarg);
411                     if (L && optarg[L-1] == 'm')
412                       maximum_age = atoi (optarg) * 60;
413                     else if (L && optarg[L-1] == 'h')
414                       maximum_age = atoi (optarg) * 60 * 60;
415                     else if (L && optarg[L-1] == 'd')
416                       maximum_age = atoi (optarg) * 60 * 60 * 24;
417                     else if (L && (optarg[L-1] == 's' ||
418                                    isdigit (optarg[L-1])))
419                       maximum_age = atoi (optarg);
420                     else {
421                       fprintf (stderr, "unparsable max-age: %s\n", optarg);
422                       exit (STATE_WARNING);
423                     }
424                   }
425                   break;
426     }
427   }
429   c = optind;
431   if (server_address == NULL && c < argc)
432     server_address = strdup (argv[c++]);
434   if (host_name == NULL && c < argc)
435     host_name = strdup (argv[c++]);
437   if (server_address == NULL) {
438     if (host_name == NULL)
439       usage4 (_("You must specify a server address or host name"));
440     else
441       server_address = strdup (host_name);
442   }
444   if (check_critical_time && critical_time>(double)socket_timeout)
445     socket_timeout = (int)critical_time + 1;
447   if (http_method == NULL)
448     http_method = strdup ("GET");
450   return TRUE;
455 /* written by lauri alanko */
456 static char *
457 base64 (const char *bin, size_t len)
460   char *buf = (char *) malloc ((len + 2) / 3 * 4 + 1);
461   size_t i = 0, j = 0;
463   char BASE64_END = '=';
464   char base64_table[64];
465   strncpy (base64_table, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", 64);
467   while (j < len - 2) {
468     buf[i++] = base64_table[bin[j] >> 2];
469     buf[i++] = base64_table[((bin[j] & 3) << 4) | (bin[j + 1] >> 4)];
470     buf[i++] = base64_table[((bin[j + 1] & 15) << 2) | (bin[j + 2] >> 6)];
471     buf[i++] = base64_table[bin[j + 2] & 63];
472     j += 3;
473   }
475   switch (len - j) {
476   case 1:
477     buf[i++] = base64_table[bin[j] >> 2];
478     buf[i++] = base64_table[(bin[j] & 3) << 4];
479     buf[i++] = BASE64_END;
480     buf[i++] = BASE64_END;
481     break;
482   case 2:
483     buf[i++] = base64_table[bin[j] >> 2];
484     buf[i++] = base64_table[((bin[j] & 3) << 4) | (bin[j + 1] >> 4)];
485     buf[i++] = base64_table[(bin[j + 1] & 15) << 2];
486     buf[i++] = BASE64_END;
487     break;
488   case 0:
489     break;
490   }
492   buf[i] = '\0';
493   return buf;
498 /* Returns 1 if we're done processing the document body; 0 to keep going */
499 static int
500 document_headers_done (char *full_page)
502   const char *body;
504   for (body = full_page; *body; body++) {
505     if (!strncmp (body, "\n\n", 2) || !strncmp (body, "\n\r\n", 3))
506       break;
507   }
509   if (!*body)
510     return 0;  /* haven't read end of headers yet */
512   full_page[body - full_page] = 0;
513   return 1;
516 static time_t
517 parse_time_string (const char *string)
519   struct tm tm;
520   time_t t;
521   memset (&tm, 0, sizeof(tm));
523   /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */
525   if (isupper (string[0])  &&  /* Tue */
526     islower (string[1])  &&
527     islower (string[2])  &&
528     ',' ==   string[3]   &&
529     ' ' ==   string[4]   &&
530     (isdigit(string[5]) || string[5] == ' ') &&   /* 25 */
531     isdigit (string[6])  &&
532     ' ' ==   string[7]   &&
533     isupper (string[8])  &&  /* Dec */
534     islower (string[9])  &&
535     islower (string[10]) &&
536     ' ' ==   string[11]  &&
537     isdigit (string[12]) &&  /* 2001 */
538     isdigit (string[13]) &&
539     isdigit (string[14]) &&
540     isdigit (string[15]) &&
541     ' ' ==   string[16]  &&
542     isdigit (string[17]) &&  /* 02: */
543     isdigit (string[18]) &&
544     ':' ==   string[19]  &&
545     isdigit (string[20]) &&  /* 59: */
546     isdigit (string[21]) &&
547     ':' ==   string[22]  &&
548     isdigit (string[23]) &&  /* 03 */
549     isdigit (string[24]) &&
550     ' ' ==   string[25]  &&
551     'G' ==   string[26]  &&  /* GMT */
552     'M' ==   string[27]  &&  /* GMT */
553     'T' ==   string[28]) {
555     tm.tm_sec  = 10 * (string[23]-'0') + (string[24]-'0');
556     tm.tm_min  = 10 * (string[20]-'0') + (string[21]-'0');
557     tm.tm_hour = 10 * (string[17]-'0') + (string[18]-'0');
558     tm.tm_mday = 10 * (string[5] == ' ' ? 0 : string[5]-'0') + (string[6]-'0');
559     tm.tm_mon = (!strncmp (string+8, "Jan", 3) ? 0 :
560       !strncmp (string+8, "Feb", 3) ? 1 :
561       !strncmp (string+8, "Mar", 3) ? 2 :
562       !strncmp (string+8, "Apr", 3) ? 3 :
563       !strncmp (string+8, "May", 3) ? 4 :
564       !strncmp (string+8, "Jun", 3) ? 5 :
565       !strncmp (string+8, "Jul", 3) ? 6 :
566       !strncmp (string+8, "Aug", 3) ? 7 :
567       !strncmp (string+8, "Sep", 3) ? 8 :
568       !strncmp (string+8, "Oct", 3) ? 9 :
569       !strncmp (string+8, "Nov", 3) ? 10 :
570       !strncmp (string+8, "Dec", 3) ? 11 :
571       -1);
572     tm.tm_year = ((1000 * (string[12]-'0') +
573       100 * (string[13]-'0') +
574       10 * (string[14]-'0') +
575       (string[15]-'0'))
576       - 1900);
578     tm.tm_isdst = 0;  /* GMT is never in DST, right? */
580     if (tm.tm_mon < 0 || tm.tm_mday < 1 || tm.tm_mday > 31)
581       return 0;
583     /* 
584     This is actually wrong: we need to subtract the local timezone
585     offset from GMT from this value.  But, that's ok in this usage,
586     because we only comparing these two GMT dates against each other,
587     so it doesn't matter what time zone we parse them in.
588     */
590     t = mktime (&tm);
591     if (t == (time_t) -1) t = 0;
593     if (verbose) {
594       const char *s = string;
595       while (*s && *s != '\r' && *s != '\n')
596       fputc (*s++, stdout);
597       printf (" ==> %lu\n", (unsigned long) t);
598     }
600     return t;
602   } else {
603     return 0;
604   }
609 static void
610 check_document_dates (const char *headers)
612   const char *s;
613   char *server_date = 0;
614   char *document_date = 0;
616   s = headers;
617   while (*s) {
618     const char *field = s;
619     const char *value = 0;
621     /* Find the end of the header field */
622     while (*s && !isspace(*s) && *s != ':')
623       s++;
625     /* Remember the header value, if any. */
626     if (*s == ':')
627       value = ++s;
629     /* Skip to the end of the header, including continuation lines. */
630     while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
631       s++;
632     s++;
634     /* Process this header. */
635     if (value && value > field+2) {
636       char *ff = (char *) malloc (value-field);
637       char *ss = ff;
638       while (field < value-1)
639         *ss++ = tolower(*field++);
640       *ss++ = 0;
642       if (!strcmp (ff, "date") || !strcmp (ff, "last-modified")) {
643         const char *e;
644         while (*value && isspace (*value))
645           value++;
646         for (e = value; *e && *e != '\r' && *e != '\n'; e++)
647           ;
648         ss = (char *) malloc (e - value + 1);
649         strncpy (ss, value, e - value);
650         ss[e - value] = 0;
651         if (!strcmp (ff, "date")) {
652           if (server_date) free (server_date);
653           server_date = ss;
654         } else {
655           if (document_date) free (document_date);
656           document_date = ss;
657         }
658       }
659       free (ff);
660     }
661   }
663   /* Done parsing the body.  Now check the dates we (hopefully) parsed.  */
664   if (!server_date || !*server_date) {
665     die (STATE_UNKNOWN, _("HTTP UNKNOWN - Server date unknown\n"));
666   } else if (!document_date || !*document_date) {
667     die (STATE_CRITICAL, _("HTTP CRITICAL - Document modification date unknown\n"));
668   } else {
669     time_t srv_data = parse_time_string (server_date);
670     time_t doc_data = parse_time_string (document_date);
672     if (srv_data <= 0) {
673       die (STATE_CRITICAL, _("HTTP CRITICAL - Server date \"%100s\" unparsable"), server_date);
674     } else if (doc_data <= 0) {
675       die (STATE_CRITICAL, _("HTTP CRITICAL - Document date \"%100s\" unparsable"), document_date);
676     } else if (doc_data > srv_data + 30) {
677       die (STATE_CRITICAL, _("HTTP CRITICAL - Document is %d seconds in the future\n"), (int)doc_data - (int)srv_data);
678     } else if (doc_data < srv_data - maximum_age) {
679     int n = (srv_data - doc_data);
680     if (n > (60 * 60 * 24 * 2))
681       die (STATE_CRITICAL,
682         _("HTTP CRITICAL - Last modified %.1f days ago\n"),
683         ((float) n) / (60 * 60 * 24));
684   else
685     die (STATE_CRITICAL,
686         _("HTTP CRITICAL - Last modified %d:%02d:%02d ago\n"),
687         n / (60 * 60), (n / 60) % 60, n % 60);
688     }
690     free (server_date);
691     free (document_date);
692   }
695 int
696 get_content_length (const char *headers)
698   const char *s;
699   int content_length = 0;
701   s = headers;
702   while (*s) {
703     const char *field = s;
704     const char *value = 0;
706     /* Find the end of the header field */
707     while (*s && !isspace(*s) && *s != ':')
708       s++;
710     /* Remember the header value, if any. */
711     if (*s == ':')
712       value = ++s;
714     /* Skip to the end of the header, including continuation lines. */
715     while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
716       s++;
717     s++;
719     /* Process this header. */
720     if (value && value > field+2) {
721       char *ff = (char *) malloc (value-field);
722       char *ss = ff;
723       while (field < value-1)
724         *ss++ = tolower(*field++);
725       *ss++ = 0;
727       if (!strcmp (ff, "content-length")) {
728         const char *e;
729         while (*value && isspace (*value))
730           value++;
731         for (e = value; *e && *e != '\r' && *e != '\n'; e++)
732           ;
733         ss = (char *) malloc (e - value + 1);
734         strncpy (ss, value, e - value);
735         ss[e - value] = 0;
736         content_length = atoi(ss);
737         free (ss);
738       }
739       free (ff);
740     }
741   }
742   return (content_length);
745 int
746 check_http (void)
748   char *msg;
749   char *status_line;
750   char *status_code;
751   char *header;
752   char *page;
753   char *auth;
754   int http_status;
755   int i = 0;
756   size_t pagesize = 0;
757   char *full_page;
758   char *buf;
759   char *pos;
760   long microsec;
761   double elapsed_time;
762   int page_len = 0;
763   int result = STATE_UNKNOWN;
765   /* try to connect to the host at the given port number */
766   if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
767     die (STATE_CRITICAL, _("HTTP CRITICAL - Unable to open TCP socket\n"));
768 #ifdef HAVE_SSL
769   if (use_ssl == TRUE) {
770     np_net_ssl_init(sd);
771     if (check_cert == TRUE) {
772       result = np_net_ssl_check_cert(days_till_exp);
773       np_net_ssl_cleanup();
774       if(sd) close(sd);
775       return result;
776     }
777   }
778 #endif /* HAVE_SSL */
780   asprintf (&buf, "%s %s HTTP/1.0\r\n%s\r\n", http_method, server_url, user_agent);
782   /* optionally send the host header info */
783   if (host_name)
784     asprintf (&buf, "%sHost: %s\r\n", buf, host_name);
786   /* optionally send any other header tag */
787   if (http_opt_headers_count) {
788     for (i = 0; i < http_opt_headers_count ; i++) {
789       for ((pos = strtok(http_opt_headers[i], INPUT_DELIMITER)); pos; (pos = strtok(NULL, INPUT_DELIMITER)))
790         asprintf (&buf, "%s%s\r\n", buf, pos);
791     }
792     free(http_opt_headers);
793   }
795   /* optionally send the authentication info */
796   if (strlen(user_auth)) {
797     auth = base64 (user_auth, strlen (user_auth));
798     asprintf (&buf, "%sAuthorization: Basic %s\r\n", buf, auth);
799   }
801   /* either send http POST data */
802   if (http_post_data) {
803     if (http_content_type) {
804       asprintf (&buf, "%sContent-Type: %s\r\n", buf, http_content_type);
805     } else {
806       asprintf (&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf);
807     }
808     
809     asprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data));
810     asprintf (&buf, "%s%s%s", buf, http_post_data, CRLF);
811   }
812   else {
813     /* or just a newline so the server knows we're done with the request */
814     asprintf (&buf, "%s%s", buf, CRLF);
815   }
817   if (verbose) printf ("%s\n", buf);
818   my_send (buf, strlen (buf));
820   /* fetch the page */
821   full_page = strdup("");
822   while ((i = my_recv (buffer, MAX_INPUT_BUFFER-1)) > 0) {
823     buffer[i] = '\0';
824     asprintf (&full_page, "%s%s", full_page, buffer);
825     pagesize += i;
827                 if (no_body && document_headers_done (full_page)) {
828                   i = 0;
829                   break;
830                 }
831   }
833   if (i < 0 && errno != ECONNRESET) {
834 #ifdef HAVE_SSL
835     /*
836     if (use_ssl) {
837       sslerr=SSL_get_error(ssl, i);
838       if ( sslerr == SSL_ERROR_SSL ) {
839         die (STATE_WARNING, _("HTTP WARNING - Client Certificate Required\n"));
840       } else {
841         die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
842       }
843     }
844     else {
845     */
846 #endif
847       die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
848 #ifdef HAVE_SSL
849       /* XXX
850     }
851     */
852 #endif
853   }
855   /* return a CRITICAL status if we couldn't read any data */
856   if (pagesize == (size_t) 0)
857     die (STATE_CRITICAL, _("HTTP CRITICAL - No data received from host\n"));
859   /* close the connection */
860 #ifdef HAVE_SSL
861   np_net_ssl_cleanup();
862 #endif
863   if(sd) close(sd);
865   /* reset the alarm */
866   alarm (0);
868   /* leave full_page untouched so we can free it later */
869   page = full_page;
871   if (verbose)
872     printf ("%s://%s:%d%s is %d characters\n",
873       use_ssl ? "https" : "http", server_address,
874       server_port, server_url, (int)pagesize);
876   /* find status line and null-terminate it */
877   status_line = page;
878   page += (size_t) strcspn (page, "\r\n");
879   pos = page;
880   page += (size_t) strspn (page, "\r\n");
881   status_line[strcspn(status_line, "\r\n")] = 0;
882   strip (status_line);
883   if (verbose)
884     printf ("STATUS: %s\n", status_line);
886   /* find header info and null-terminate it */
887   header = page;
888   while (strcspn (page, "\r\n") > 0) {
889     page += (size_t) strcspn (page, "\r\n");
890     pos = page;
891     if ((strspn (page, "\r") == 1 && strspn (page, "\r\n") >= 2) ||
892         (strspn (page, "\n") == 1 && strspn (page, "\r\n") >= 2))
893       page += (size_t) 2;
894     else
895       page += (size_t) 1;
896   }
897   page += (size_t) strspn (page, "\r\n");
898   header[pos - header] = 0;
899   if (verbose)
900     printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header,
901                 (no_body ? "  [[ skipped ]]" : page));
903   /* make sure the status line matches the response we are looking for */
904   if (!strstr (status_line, server_expect)) {
905     if (server_port == HTTP_PORT)
906       asprintf (&msg,
907                 _("Invalid HTTP response received from host\n"));
908     else
909       asprintf (&msg,
910                 _("Invalid HTTP response received from host on port %d\n"),
911                 server_port);
912     die (STATE_CRITICAL, "HTTP CRITICAL - %s", msg);
913   }
915   /* Exit here if server_expect was set by user and not default */
916   if ( server_expect_yn  )  {
917     asprintf (&msg,
918               _("HTTP OK: Status line output matched \"%s\"\n"),
919               server_expect);
920     if (verbose)
921       printf ("%s\n",msg);
922   }
923   else {
924     /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
925     /* HTTP-Version   = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
926     /* Status-Code = 3 DIGITS */
928     status_code = strchr (status_line, ' ') + sizeof (char);
929     if (strspn (status_code, "1234567890") != 3)
930       die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line);
932     http_status = atoi (status_code);
934     /* check the return code */
936     if (http_status >= 600 || http_status < 100)
937       die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line);
939     /* server errors result in a critical state */
940     else if (http_status >= 500)
941       die (STATE_CRITICAL, _("HTTP CRITICAL: %s\n"), status_line);
943     /* client errors result in a warning state */
944     else if (http_status >= 400)
945       die (STATE_WARNING, _("HTTP WARNING: %s\n"), status_line);
947     /* check redirected page if specified */
948     else if (http_status >= 300) {
950       if (onredirect == STATE_DEPENDENT)
951         redir (header, status_line);
952       else if (onredirect == STATE_UNKNOWN)
953         printf (_("HTTP UNKNOWN"));
954       else if (onredirect == STATE_OK)
955         printf (_("HTTP OK"));
956       else if (onredirect == STATE_WARNING)
957         printf (_("HTTP WARNING"));
958       else if (onredirect == STATE_CRITICAL)
959         printf (_("HTTP CRITICAL"));
960       microsec = deltime (tv);
961       elapsed_time = (double)microsec / 1.0e6;
962       die (onredirect,
963            _(" - %s - %.3f second response time %s|%s %s\n"),
964            status_line, elapsed_time, 
965            (display_html ? "</A>" : ""),
966            perfd_time (elapsed_time), perfd_size (pagesize));
967     } /* end if (http_status >= 300) */
969   } /* end else (server_expect_yn)  */
970     
971         if (maximum_age >= 0) {
972           check_document_dates (header);
973         }
975   /* check elapsed time */
976   microsec = deltime (tv);
977   elapsed_time = (double)microsec / 1.0e6;
978   asprintf (&msg,
979             _("HTTP WARNING: %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   if (check_critical_time == TRUE && elapsed_time > critical_time)
984     die (STATE_CRITICAL, "%s", msg);
985   if (check_warning_time == TRUE && elapsed_time > warning_time)
986     die (STATE_WARNING, "%s", msg);
988   /* Page and Header content checks go here */
989   /* these checks should be last */
991   if (strlen (string_expect)) {
992     if (strstr (page, string_expect)) {
993       printf (_("HTTP OK %s - %.3f second response time %s|%s %s\n"),
994               status_line, elapsed_time,
995               (display_html ? "</A>" : ""),
996               perfd_time (elapsed_time), perfd_size (pagesize));
997       exit (STATE_OK);
998     }
999     else {
1000       printf (_("HTTP CRITICAL - string not found%s|%s %s\n"),
1001               (display_html ? "</A>" : ""),
1002               perfd_time (elapsed_time), perfd_size (pagesize));
1003       exit (STATE_CRITICAL);
1004     }
1005   }
1007   if (strlen (regexp)) {
1008     errcode = regexec (&preg, page, REGS, pmatch, 0);
1009     if ((errcode == 0 && invert_regex == 0) || (errcode == REG_NOMATCH && invert_regex == 1)) {
1010       printf (_("HTTP OK %s - %.3f second response time %s|%s %s\n"),
1011               status_line, elapsed_time,
1012               (display_html ? "</A>" : ""),
1013               perfd_time (elapsed_time), perfd_size (pagesize));
1014       exit (STATE_OK);
1015     }
1016     else if ((errcode == REG_NOMATCH && invert_regex == 0) || (errcode == 0 && invert_regex == 1)) {
1017       if (invert_regex == 0) 
1018         msg = strdup(_("pattern not found"));
1019       else 
1020         msg = strdup(_("pattern found"));
1021       printf (("%s - %s%s|%s %s\n"),
1022         _("HTTP CRITICAL"),
1023         msg,
1024         (display_html ? "</A>" : ""),
1025         perfd_time (elapsed_time), perfd_size (pagesize));
1026       exit (STATE_CRITICAL);
1027     }
1028     else {
1029       regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1030       printf (_("HTTP CRITICAL - Execute Error: %s\n"), errbuf);
1031       exit (STATE_CRITICAL);
1032     }
1033   }
1035   /* make sure the page is of an appropriate size */
1036   /* page_len = get_content_length(header); */
1037   page_len = pagesize;
1038   if ((max_page_len > 0) && (page_len > max_page_len)) {
1039     printf (_("HTTP WARNING: page size %d too large%s|%s\n"),
1040       page_len, (display_html ? "</A>" : ""), perfd_size (page_len) );
1041     exit (STATE_WARNING);
1042   } else if ((min_page_len > 0) && (page_len < min_page_len)) {
1043     printf (_("HTTP WARNING: page size %d too small%s|%s\n"),
1044       page_len, (display_html ? "</A>" : ""), perfd_size (page_len) );
1045     exit (STATE_WARNING);
1046   }
1047   /* We only get here if all tests have been passed */
1048   asprintf (&msg, _("HTTP OK %s - %d bytes in %.3f seconds %s|%s %s\n"),
1049             status_line, page_len, elapsed_time,
1050             (display_html ? "</A>" : ""),
1051             perfd_time (elapsed_time), perfd_size (page_len));
1052   die (STATE_OK, "%s", msg);
1053   return STATE_UNKNOWN;
1058 /* per RFC 2396 */
1059 #define HDR_LOCATION "%*[Ll]%*[Oo]%*[Cc]%*[Aa]%*[Tt]%*[Ii]%*[Oo]%*[Nn]: "
1060 #define URI_HTTP "%[HTPShtps]://"
1061 #define URI_HOST "%[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1062 #define URI_PORT ":%[0123456789]"
1063 #define URI_PATH "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1064 #define HD1 URI_HTTP URI_HOST URI_PORT URI_PATH
1065 #define HD2 URI_HTTP URI_HOST URI_PATH
1066 #define HD3 URI_HTTP URI_HOST URI_PORT
1067 #define HD4 URI_HTTP URI_HOST
1068 #define HD5 URI_PATH
1070 void
1071 redir (char *pos, char *status_line)
1073   int i = 0;
1074   char *x;
1075   char xx[2];
1076   char type[6];
1077   char *addr;
1078   char port[6];
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\r\n");
1104     url = realloc (url, strcspn (pos, "\r\n"));
1105     if (url == NULL)
1106       die (STATE_UNKNOWN, _("HTTP UNKNOWN - could not allocate url\n"));
1108     /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
1109     if (sscanf (pos, HD1, type, addr, port, url) == 4) {
1110       use_ssl = server_type_check (type);
1111       i = atoi (port);
1112     }
1114     /* URI_HTTP URI_HOST URI_PATH */
1115     else if (sscanf (pos, HD2, type, addr, url) == 3 ) { 
1116       use_ssl = server_type_check (type);
1117       i = server_port_check (use_ssl);
1118     }
1120     /* URI_HTTP URI_HOST URI_PORT */
1121     else if(sscanf (pos, HD3, type, addr, port) == 3) {
1122       strcpy (url, HTTP_URL);
1123       use_ssl = server_type_check (type);
1124       i = atoi (port);
1125     }
1127     /* URI_HTTP URI_HOST */
1128     else if(sscanf (pos, HD4, type, addr) == 2) {
1129       strcpy (url, HTTP_URL);
1130       use_ssl = server_type_check (type);
1131       i = server_port_check (use_ssl);
1132     }
1134     /* URI_PATH */
1135     else if (sscanf (pos, HD5, url) == 1) {
1136       /* relative url */
1137       if ((url[0] != '/')) {
1138         if ((x = strrchr(server_url, '/')))
1139           *x = '\0';
1140         asprintf (&url, "%s/%s", server_url, url);
1141       }
1142       i = server_port;
1143       strcpy (type, server_type);
1144       strcpy (addr, host_name);
1145     }           
1147     else {
1148       die (STATE_UNKNOWN,
1149            _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"),
1150            pos, (display_html ? "</A>" : ""));
1151     }
1153     break;
1155   } /* end while (pos) */
1157   if (++redir_depth > max_depth)
1158     die (STATE_WARNING,
1159          _("HTTP WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"),
1160          max_depth, type, addr, i, url, (display_html ? "</A>" : ""));
1162   if (server_port==i &&
1163       !strcmp(server_address, addr) &&
1164       (host_name && !strcmp(host_name, addr)) &&
1165       !strcmp(server_url, url))
1166     die (STATE_WARNING,
1167          _("HTTP WARNING - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
1168          type, addr, i, url, (display_html ? "</A>" : ""));
1170   server_port = i;
1171   strcpy (server_type, type);
1173   free (host_name);
1174   host_name = strdup (addr);
1176   free (server_address);
1177   server_address = strdup (addr);
1179   free (server_url);
1180   server_url = strdup (url);
1182   check_http ();
1187 int
1188 server_type_check (const char *type)
1190   if (strcmp (type, "https"))
1191     return FALSE;
1192   else
1193     return TRUE;
1196 int
1197 server_port_check (int ssl_flag)
1199   if (ssl_flag)
1200     return HTTPS_PORT;
1201   else
1202     return HTTP_PORT;
1205 char *perfd_time (double elapsed_time)
1207   return fperfdata ("time", elapsed_time, "s",
1208             check_warning_time, warning_time,
1209             check_critical_time, critical_time,
1210                    TRUE, 0, FALSE, 0);
1215 char *perfd_size (int page_len)
1217   return perfdata ("size", page_len, "B",
1218             (min_page_len>0?TRUE:FALSE), min_page_len,
1219             (min_page_len>0?TRUE:FALSE), 0,
1220             TRUE, 0, FALSE, 0);
1223 void
1224 print_help (void)
1226   print_revision (progname, revision);
1228   printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1229   printf (COPYRIGHT, copyright, email);
1231   printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test"));
1232   printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for"));
1233   printf ("%s\n", _("strings and regular expressions, check connection times, and report on"));
1234   printf ("%s\n", _("certificate expiration times."));
1236   printf ("\n\n");
1238   print_usage ();
1240   printf (_("NOTE: One or both of -H and -I must be specified"));
1242   printf ("\n");
1244   printf (_(UT_HELP_VRSN));
1246   printf (" %s\n", "-H, --hostname=ADDRESS");
1247   printf ("    %s\n", _("Host name argument for servers using host headers (virtual host)"));
1248   printf ("    %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
1249   printf (" %s\n", "-I, --IP-address=ADDRESS");
1250   printf ("    %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
1251   printf (" %s\n", "-p, --port=INTEGER");
1252   printf (" %s", _("Port number (default: "));
1253   printf ("%d)\n", HTTP_PORT);
1255   printf (_(UT_IPv46));
1257 #ifdef HAVE_SSL
1258   printf (" %s\n", "-S, --ssl");
1259   printf ("   %s\n", _("Connect via SSL. Port defaults to 443"));
1260   printf (" %s\n", "-C, --certificate=INTEGER");
1261   printf ("   %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443"));
1262   printf ("   %s\n", _("(when this option is used the url is not checked.)\n"));
1263 #endif
1265   printf (" %s\n", "-e, --expect=STRING");
1266   printf ("    %s\n", _("String to expect in first (status) line of server response (default: "));
1267   printf ("%s)\n", HTTP_EXPECT);
1268   printf ("    %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
1269   printf (" %s\n", "-s, --string=STRING");
1270   printf ("    %s\n", _("String to expect in the content"));
1271   printf (" %s\n", "-u, --url=PATH");
1272   printf ("    %s\n", _("URL to GET or POST (default: /)"));
1273   printf (" %s\n", "-P, --post=STRING");
1274   printf ("    %s\n", _("URL encoded http POST data"));
1275   printf (" %s\n", "-N, --no-body");
1276   printf ("    %s\n", _("Don't wait for document body: stop reading after headers."));
1277   printf ("    %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)"));
1278   printf (" %s\n", "-M, --max-age=SECONDS");
1279   printf ("    %s\n", _("Warn if document is more than SECONDS old. the number can also be of"));
1280   printf ("    %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
1281   printf (" %s\n", "-T, --content-type=STRING");
1282   printf ("    %s\n", _("specify Content-Type header media type when POSTing\n"));
1284   printf (" %s\n", "-l, --linespan");
1285   printf ("    %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
1286   printf (" %s\n", "-r, --regex, --ereg=STRING");
1287   printf ("    %s\n", _("Search page for regex STRING"));
1288   printf (" %s\n", "-R, --eregi=STRING");
1289   printf ("    %s\n", _("Search page for case-insensitive regex STRING"));
1290   printf (" %s\n", "--invert-regex");
1291   printf ("    %s\n", _("Return CRITICAL if found, OK if not\n"));
1293   printf (" %s\n", "-a, --authorization=AUTH_PAIR");
1294   printf ("    %s\n", _("Username:password on sites with basic authentication"));
1295   printf (" %s\n", "-A, --useragent=STRING");
1296   printf ("    %s\n", _("String to be sent in http header as \"User Agent\""));
1297   printf (" %s\n", "-k, --header=STRING");
1298   printf ("    %s\n", _(" Any other tags to be sent in http header. Use multiple times for additional headers"));
1299   printf (" %s\n", "-L, --link");
1300   printf ("    %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
1301   printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow>");
1302   printf ("    %s\n", _("How to handle redirected pages"));
1303   printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
1304   printf ("    %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
1306   printf (_(UT_WARN_CRIT));
1308   printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
1310   printf (_(UT_VERBOSE));
1312   printf (_("Notes:"));
1313   printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
1314   printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
1315   printf (" %s\n", _("other errors return STATE_UNKNOWN.  Successful connects, but incorrect reponse"));
1316   printf (" %s\n", _("messages from the host result in STATE_WARNING return values.  If you are"));
1317   printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
1318   printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
1320 #ifdef HAVE_SSL
1321   printf (" %s\n", _("This plugin can also check whether an SSL enabled web server is able to"));
1322   printf (" %s\n", _("serve content (optionally within a specified time) or whether the X509 "));
1323   printf (" %s\n", _("certificate is still valid for the specified number of days."));
1324   printf (_("Examples:"));
1325   printf (" %s\n\n", "CHECK CONTENT: check_http -w 5 -c 10 --ssl -H www.verisign.com");
1326   printf (" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
1327   printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
1328   printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
1329   printf (" %s\n\n", _("a STATE_CRITICAL will be returned."));
1331   printf (" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 14");
1332   printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
1333   printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
1334   printf (" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
1335   printf (" %s\n\n", _("the certificate is expired."));
1336 #endif
1338   printf (_(UT_SUPPORT));
1344 void
1345 print_usage (void)
1347   printf (_("Usage:"));
1348   printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname);
1349   printf ("       [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L]\n");
1350   printf ("       [-a auth] [-f <ok | warn | critcal | follow>] [-e <expect>]\n");
1351   printf ("       [-s string] [-l] [-r <regex> | -R <case-insensitive regex>] [-P string]\n");
1352   printf ("       [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>] [-A string]\n");
1353   printf ("       [-k string] [-S] [-C <age>] [-T <content-type>]\n");