Code

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