Code

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