Code

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