Code

Moved base64 function to /lib.
[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"
51 #include "base64.h"
53 #define INPUT_DELIMITER ";"
55 #define HTTP_EXPECT "HTTP/1."
56 enum {
57   MAX_IPV4_HOSTLENGTH = 255,
58   HTTP_PORT = 80,
59   HTTPS_PORT = 443,
60   MAX_PORT = 65535
61 };
63 #ifdef HAVE_SSL
64 int check_cert = FALSE;
65 int days_till_exp;
66 char *randbuff;
67 X509 *server_cert;
68 #  define my_recv(buf, len) ((use_ssl) ? np_net_ssl_read(buf, len) : read(sd, buf, len))
69 #  define my_send(buf, len) ((use_ssl) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
70 #else /* ifndef HAVE_SSL */
71 #  define my_recv(buf, len) read(sd, buf, len)
72 #  define my_send(buf, len) send(sd, buf, len, 0)
73 #endif /* HAVE_SSL */
74 int no_body = FALSE;
75 int maximum_age = -1;
77 enum {
78   REGS = 2,
79   MAX_RE_SIZE = 256
80 };
81 #include "regex.h"
82 regex_t preg;
83 regmatch_t pmatch[REGS];
84 char regexp[MAX_RE_SIZE];
85 char errbuf[MAX_INPUT_BUFFER];
86 int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
87 int errcode;
88 int invert_regex = 0;
90 struct timeval tv;
92 #define HTTP_URL "/"
93 #define CRLF "\r\n"
95 int specify_port = FALSE;
96 int server_port = HTTP_PORT;
97 char server_port_text[6] = "";
98 char server_type[6] = "http";
99 char *server_address;
100 char *host_name;
101 char *server_url;
102 char *user_agent;
103 int server_url_length;
104 int server_expect_yn = 0;
105 char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
106 char string_expect[MAX_INPUT_BUFFER] = "";
107 double warning_time = 0;
108 int check_warning_time = FALSE;
109 double critical_time = 0;
110 int check_critical_time = FALSE;
111 char user_auth[MAX_INPUT_BUFFER] = "";
112 int display_html = FALSE;
113 char **http_opt_headers;
114 int http_opt_headers_count = 0;
115 int onredirect = STATE_OK;
116 int use_ssl = FALSE;
117 int verbose = FALSE;
118 int sd;
119 int min_page_len = 0;
120 int max_page_len = 0;
121 int redir_depth = 0;
122 int max_depth = 15;
123 char *http_method;
124 char *http_post_data;
125 char *http_content_type;
126 char buffer[MAX_INPUT_BUFFER];
128 int process_arguments (int, char **);
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 /* Returns 1 if we're done processing the document body; 0 to keep going */
459 static int
460 document_headers_done (char *full_page)
462   const char *body;
464   for (body = full_page; *body; body++) {
465     if (!strncmp (body, "\n\n", 2) || !strncmp (body, "\n\r\n", 3))
466       break;
467   }
469   if (!*body)
470     return 0;  /* haven't read end of headers yet */
472   full_page[body - full_page] = 0;
473   return 1;
476 static time_t
477 parse_time_string (const char *string)
479   struct tm tm;
480   time_t t;
481   memset (&tm, 0, sizeof(tm));
483   /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */
485   if (isupper (string[0])  &&  /* Tue */
486     islower (string[1])  &&
487     islower (string[2])  &&
488     ',' ==   string[3]   &&
489     ' ' ==   string[4]   &&
490     (isdigit(string[5]) || string[5] == ' ') &&   /* 25 */
491     isdigit (string[6])  &&
492     ' ' ==   string[7]   &&
493     isupper (string[8])  &&  /* Dec */
494     islower (string[9])  &&
495     islower (string[10]) &&
496     ' ' ==   string[11]  &&
497     isdigit (string[12]) &&  /* 2001 */
498     isdigit (string[13]) &&
499     isdigit (string[14]) &&
500     isdigit (string[15]) &&
501     ' ' ==   string[16]  &&
502     isdigit (string[17]) &&  /* 02: */
503     isdigit (string[18]) &&
504     ':' ==   string[19]  &&
505     isdigit (string[20]) &&  /* 59: */
506     isdigit (string[21]) &&
507     ':' ==   string[22]  &&
508     isdigit (string[23]) &&  /* 03 */
509     isdigit (string[24]) &&
510     ' ' ==   string[25]  &&
511     'G' ==   string[26]  &&  /* GMT */
512     'M' ==   string[27]  &&  /* GMT */
513     'T' ==   string[28]) {
515     tm.tm_sec  = 10 * (string[23]-'0') + (string[24]-'0');
516     tm.tm_min  = 10 * (string[20]-'0') + (string[21]-'0');
517     tm.tm_hour = 10 * (string[17]-'0') + (string[18]-'0');
518     tm.tm_mday = 10 * (string[5] == ' ' ? 0 : string[5]-'0') + (string[6]-'0');
519     tm.tm_mon = (!strncmp (string+8, "Jan", 3) ? 0 :
520       !strncmp (string+8, "Feb", 3) ? 1 :
521       !strncmp (string+8, "Mar", 3) ? 2 :
522       !strncmp (string+8, "Apr", 3) ? 3 :
523       !strncmp (string+8, "May", 3) ? 4 :
524       !strncmp (string+8, "Jun", 3) ? 5 :
525       !strncmp (string+8, "Jul", 3) ? 6 :
526       !strncmp (string+8, "Aug", 3) ? 7 :
527       !strncmp (string+8, "Sep", 3) ? 8 :
528       !strncmp (string+8, "Oct", 3) ? 9 :
529       !strncmp (string+8, "Nov", 3) ? 10 :
530       !strncmp (string+8, "Dec", 3) ? 11 :
531       -1);
532     tm.tm_year = ((1000 * (string[12]-'0') +
533       100 * (string[13]-'0') +
534       10 * (string[14]-'0') +
535       (string[15]-'0'))
536       - 1900);
538     tm.tm_isdst = 0;  /* GMT is never in DST, right? */
540     if (tm.tm_mon < 0 || tm.tm_mday < 1 || tm.tm_mday > 31)
541       return 0;
543     /* 
544     This is actually wrong: we need to subtract the local timezone
545     offset from GMT from this value.  But, that's ok in this usage,
546     because we only comparing these two GMT dates against each other,
547     so it doesn't matter what time zone we parse them in.
548     */
550     t = mktime (&tm);
551     if (t == (time_t) -1) t = 0;
553     if (verbose) {
554       const char *s = string;
555       while (*s && *s != '\r' && *s != '\n')
556       fputc (*s++, stdout);
557       printf (" ==> %lu\n", (unsigned long) t);
558     }
560     return t;
562   } else {
563     return 0;
564   }
569 static void
570 check_document_dates (const char *headers)
572   const char *s;
573   char *server_date = 0;
574   char *document_date = 0;
576   s = headers;
577   while (*s) {
578     const char *field = s;
579     const char *value = 0;
581     /* Find the end of the header field */
582     while (*s && !isspace(*s) && *s != ':')
583       s++;
585     /* Remember the header value, if any. */
586     if (*s == ':')
587       value = ++s;
589     /* Skip to the end of the header, including continuation lines. */
590     while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
591       s++;
592     s++;
594     /* Process this header. */
595     if (value && value > field+2) {
596       char *ff = (char *) malloc (value-field);
597       char *ss = ff;
598       while (field < value-1)
599         *ss++ = tolower(*field++);
600       *ss++ = 0;
602       if (!strcmp (ff, "date") || !strcmp (ff, "last-modified")) {
603         const char *e;
604         while (*value && isspace (*value))
605           value++;
606         for (e = value; *e && *e != '\r' && *e != '\n'; e++)
607           ;
608         ss = (char *) malloc (e - value + 1);
609         strncpy (ss, value, e - value);
610         ss[e - value] = 0;
611         if (!strcmp (ff, "date")) {
612           if (server_date) free (server_date);
613           server_date = ss;
614         } else {
615           if (document_date) free (document_date);
616           document_date = ss;
617         }
618       }
619       free (ff);
620     }
621   }
623   /* Done parsing the body.  Now check the dates we (hopefully) parsed.  */
624   if (!server_date || !*server_date) {
625     die (STATE_UNKNOWN, _("HTTP UNKNOWN - Server date unknown\n"));
626   } else if (!document_date || !*document_date) {
627     die (STATE_CRITICAL, _("HTTP CRITICAL - Document modification date unknown\n"));
628   } else {
629     time_t srv_data = parse_time_string (server_date);
630     time_t doc_data = parse_time_string (document_date);
632     if (srv_data <= 0) {
633       die (STATE_CRITICAL, _("HTTP CRITICAL - Server date \"%100s\" unparsable"), server_date);
634     } else if (doc_data <= 0) {
635       die (STATE_CRITICAL, _("HTTP CRITICAL - Document date \"%100s\" unparsable"), document_date);
636     } else if (doc_data > srv_data + 30) {
637       die (STATE_CRITICAL, _("HTTP CRITICAL - Document is %d seconds in the future\n"), (int)doc_data - (int)srv_data);
638     } else if (doc_data < srv_data - maximum_age) {
639     int n = (srv_data - doc_data);
640     if (n > (60 * 60 * 24 * 2))
641       die (STATE_CRITICAL,
642         _("HTTP CRITICAL - Last modified %.1f days ago\n"),
643         ((float) n) / (60 * 60 * 24));
644   else
645     die (STATE_CRITICAL,
646         _("HTTP CRITICAL - Last modified %d:%02d:%02d ago\n"),
647         n / (60 * 60), (n / 60) % 60, n % 60);
648     }
650     free (server_date);
651     free (document_date);
652   }
655 int
656 get_content_length (const char *headers)
658   const char *s;
659   int content_length = 0;
661   s = headers;
662   while (*s) {
663     const char *field = s;
664     const char *value = 0;
666     /* Find the end of the header field */
667     while (*s && !isspace(*s) && *s != ':')
668       s++;
670     /* Remember the header value, if any. */
671     if (*s == ':')
672       value = ++s;
674     /* Skip to the end of the header, including continuation lines. */
675     while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
676       s++;
677     s++;
679     /* Process this header. */
680     if (value && value > field+2) {
681       char *ff = (char *) malloc (value-field);
682       char *ss = ff;
683       while (field < value-1)
684         *ss++ = tolower(*field++);
685       *ss++ = 0;
687       if (!strcmp (ff, "content-length")) {
688         const char *e;
689         while (*value && isspace (*value))
690           value++;
691         for (e = value; *e && *e != '\r' && *e != '\n'; e++)
692           ;
693         ss = (char *) malloc (e - value + 1);
694         strncpy (ss, value, e - value);
695         ss[e - value] = 0;
696         content_length = atoi(ss);
697         free (ss);
698       }
699       free (ff);
700     }
701   }
702   return (content_length);
705 int
706 check_http (void)
708   char *msg;
709   char *status_line;
710   char *status_code;
711   char *header;
712   char *page;
713   char *auth;
714   int http_status;
715   int i = 0;
716   size_t pagesize = 0;
717   char *full_page;
718   char *buf;
719   char *pos;
720   long microsec;
721   double elapsed_time;
722   int page_len = 0;
723   int result = STATE_UNKNOWN;
725   /* try to connect to the host at the given port number */
726   if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
727     die (STATE_CRITICAL, _("HTTP CRITICAL - Unable to open TCP socket\n"));
728 #ifdef HAVE_SSL
729   if (use_ssl == TRUE) {
730     np_net_ssl_init(sd);
731     if (check_cert == TRUE) {
732       result = np_net_ssl_check_cert(days_till_exp);
733       np_net_ssl_cleanup();
734       if(sd) close(sd);
735       return result;
736     }
737   }
738 #endif /* HAVE_SSL */
740   asprintf (&buf, "%s %s HTTP/1.0\r\n%s\r\n", http_method, server_url, user_agent);
742   /* tell HTTP/1.1 servers not to keep the connection alive */
743   asprintf (&buf, "%sConnection: close\r\n", buf);
745   /* optionally send the host header info */
746   if (host_name)
747     asprintf (&buf, "%sHost: %s\r\n", buf, host_name);
749   /* optionally send any other header tag */
750   if (http_opt_headers_count) {
751     for (i = 0; i < http_opt_headers_count ; i++) {
752       for ((pos = strtok(http_opt_headers[i], INPUT_DELIMITER)); pos; (pos = strtok(NULL, INPUT_DELIMITER)))
753         asprintf (&buf, "%s%s\r\n", buf, pos);
754     }
755     free(http_opt_headers);
756   }
758   /* optionally send the authentication info */
759   if (strlen(user_auth)) {
760     auth = base64 (user_auth, strlen (user_auth));
761     asprintf (&buf, "%sAuthorization: Basic %s\r\n", buf, auth);
762   }
764   /* either send http POST data */
765   if (http_post_data) {
766     if (http_content_type) {
767       asprintf (&buf, "%sContent-Type: %s\r\n", buf, http_content_type);
768     } else {
769       asprintf (&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf);
770     }
771     
772     asprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data));
773     asprintf (&buf, "%s%s%s", buf, http_post_data, CRLF);
774   }
775   else {
776     /* or just a newline so the server knows we're done with the request */
777     asprintf (&buf, "%s%s", buf, CRLF);
778   }
780   if (verbose) printf ("%s\n", buf);
781   my_send (buf, strlen (buf));
783   /* fetch the page */
784   full_page = strdup("");
785   while ((i = my_recv (buffer, MAX_INPUT_BUFFER-1)) > 0) {
786     buffer[i] = '\0';
787     asprintf (&full_page, "%s%s", full_page, buffer);
788     pagesize += i;
790                 if (no_body && document_headers_done (full_page)) {
791                   i = 0;
792                   break;
793                 }
794   }
796   if (i < 0 && errno != ECONNRESET) {
797 #ifdef HAVE_SSL
798     /*
799     if (use_ssl) {
800       sslerr=SSL_get_error(ssl, i);
801       if ( sslerr == SSL_ERROR_SSL ) {
802         die (STATE_WARNING, _("HTTP WARNING - Client Certificate Required\n"));
803       } else {
804         die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
805       }
806     }
807     else {
808     */
809 #endif
810       die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
811 #ifdef HAVE_SSL
812       /* XXX
813     }
814     */
815 #endif
816   }
818   /* return a CRITICAL status if we couldn't read any data */
819   if (pagesize == (size_t) 0)
820     die (STATE_CRITICAL, _("HTTP CRITICAL - No data received from host\n"));
822   /* close the connection */
823 #ifdef HAVE_SSL
824   np_net_ssl_cleanup();
825 #endif
826   if(sd) close(sd);
828   /* reset the alarm */
829   alarm (0);
831   /* leave full_page untouched so we can free it later */
832   page = full_page;
834   if (verbose)
835     printf ("%s://%s:%d%s is %d characters\n",
836       use_ssl ? "https" : "http", server_address,
837       server_port, server_url, (int)pagesize);
839   /* find status line and null-terminate it */
840   status_line = page;
841   page += (size_t) strcspn (page, "\r\n");
842   pos = page;
843   page += (size_t) strspn (page, "\r\n");
844   status_line[strcspn(status_line, "\r\n")] = 0;
845   strip (status_line);
846   if (verbose)
847     printf ("STATUS: %s\n", status_line);
849   /* find header info and null-terminate it */
850   header = page;
851   while (strcspn (page, "\r\n") > 0) {
852     page += (size_t) strcspn (page, "\r\n");
853     pos = page;
854     if ((strspn (page, "\r") == 1 && strspn (page, "\r\n") >= 2) ||
855         (strspn (page, "\n") == 1 && strspn (page, "\r\n") >= 2))
856       page += (size_t) 2;
857     else
858       page += (size_t) 1;
859   }
860   page += (size_t) strspn (page, "\r\n");
861   header[pos - header] = 0;
862   if (verbose)
863     printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header,
864                 (no_body ? "  [[ skipped ]]" : page));
866   /* make sure the status line matches the response we are looking for */
867   if (!strstr (status_line, server_expect)) {
868     if (server_port == HTTP_PORT)
869       asprintf (&msg,
870                 _("Invalid HTTP response received from host\n"));
871     else
872       asprintf (&msg,
873                 _("Invalid HTTP response received from host on port %d\n"),
874                 server_port);
875     die (STATE_CRITICAL, "HTTP CRITICAL - %s", msg);
876   }
878   /* Exit here if server_expect was set by user and not default */
879   if ( server_expect_yn  )  {
880     asprintf (&msg,
881               _("HTTP OK: Status line output matched \"%s\"\n"),
882               server_expect);
883     if (verbose)
884       printf ("%s\n",msg);
885   }
886   else {
887     /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
888     /* HTTP-Version   = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
889     /* Status-Code = 3 DIGITS */
891     status_code = strchr (status_line, ' ') + sizeof (char);
892     if (strspn (status_code, "1234567890") != 3)
893       die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line);
895     http_status = atoi (status_code);
897     /* check the return code */
899     if (http_status >= 600 || http_status < 100)
900       die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line);
902     /* server errors result in a critical state */
903     else if (http_status >= 500)
904       die (STATE_CRITICAL, _("HTTP CRITICAL: %s\n"), status_line);
906     /* client errors result in a warning state */
907     else if (http_status >= 400)
908       die (STATE_WARNING, _("HTTP WARNING: %s\n"), status_line);
910     /* check redirected page if specified */
911     else if (http_status >= 300) {
913       if (onredirect == STATE_DEPENDENT)
914         redir (header, status_line);
915       else if (onredirect == STATE_UNKNOWN)
916         printf (_("HTTP UNKNOWN"));
917       else if (onredirect == STATE_OK)
918         printf (_("HTTP OK"));
919       else if (onredirect == STATE_WARNING)
920         printf (_("HTTP WARNING"));
921       else if (onredirect == STATE_CRITICAL)
922         printf (_("HTTP CRITICAL"));
923       microsec = deltime (tv);
924       elapsed_time = (double)microsec / 1.0e6;
925       die (onredirect,
926            _(" - %s - %.3f second response time %s|%s %s\n"),
927            status_line, elapsed_time, 
928            (display_html ? "</A>" : ""),
929            perfd_time (elapsed_time), perfd_size (pagesize));
930     } /* end if (http_status >= 300) */
932   } /* end else (server_expect_yn)  */
933     
934         if (maximum_age >= 0) {
935           check_document_dates (header);
936         }
938   /* check elapsed time */
939   microsec = deltime (tv);
940   elapsed_time = (double)microsec / 1.0e6;
941   asprintf (&msg,
942             _("HTTP WARNING: %s - %.3f second response time %s|%s %s\n"),
943             status_line, elapsed_time, 
944             (display_html ? "</A>" : ""),
945             perfd_time (elapsed_time), perfd_size (pagesize));
946   if (check_critical_time == TRUE && elapsed_time > critical_time)
947     die (STATE_CRITICAL, "%s", msg);
948   if (check_warning_time == TRUE && elapsed_time > warning_time)
949     die (STATE_WARNING, "%s", msg);
951   /* Page and Header content checks go here */
952   /* these checks should be last */
954   if (strlen (string_expect)) {
955     if (strstr (page, string_expect)) {
956       printf (_("HTTP OK %s - %.3f second response time %s|%s %s\n"),
957               status_line, elapsed_time,
958               (display_html ? "</A>" : ""),
959               perfd_time (elapsed_time), perfd_size (pagesize));
960       exit (STATE_OK);
961     }
962     else {
963       printf (_("HTTP CRITICAL - string not found%s|%s %s\n"),
964               (display_html ? "</A>" : ""),
965               perfd_time (elapsed_time), perfd_size (pagesize));
966       exit (STATE_CRITICAL);
967     }
968   }
970   if (strlen (regexp)) {
971     errcode = regexec (&preg, page, REGS, pmatch, 0);
972     if ((errcode == 0 && invert_regex == 0) || (errcode == REG_NOMATCH && invert_regex == 1)) {
973       printf (_("HTTP OK %s - %.3f second response time %s|%s %s\n"),
974               status_line, elapsed_time,
975               (display_html ? "</A>" : ""),
976               perfd_time (elapsed_time), perfd_size (pagesize));
977       exit (STATE_OK);
978     }
979     else if ((errcode == REG_NOMATCH && invert_regex == 0) || (errcode == 0 && invert_regex == 1)) {
980       if (invert_regex == 0) 
981         msg = strdup(_("pattern not found"));
982       else 
983         msg = strdup(_("pattern found"));
984       printf (("%s - %s%s|%s %s\n"),
985         _("HTTP CRITICAL"),
986         msg,
987         (display_html ? "</A>" : ""),
988         perfd_time (elapsed_time), perfd_size (pagesize));
989       exit (STATE_CRITICAL);
990     }
991     else {
992       regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
993       printf (_("HTTP CRITICAL - Execute Error: %s\n"), errbuf);
994       exit (STATE_CRITICAL);
995     }
996   }
998   /* make sure the page is of an appropriate size */
999   /* page_len = get_content_length(header); */
1000   page_len = pagesize;
1001   if ((max_page_len > 0) && (page_len > max_page_len)) {
1002     printf (_("HTTP WARNING: page size %d too large%s|%s\n"),
1003       page_len, (display_html ? "</A>" : ""), perfd_size (page_len) );
1004     exit (STATE_WARNING);
1005   } else if ((min_page_len > 0) && (page_len < min_page_len)) {
1006     printf (_("HTTP WARNING: page size %d too small%s|%s\n"),
1007       page_len, (display_html ? "</A>" : ""), perfd_size (page_len) );
1008     exit (STATE_WARNING);
1009   }
1010   /* We only get here if all tests have been passed */
1011   asprintf (&msg, _("HTTP OK %s - %d bytes in %.3f seconds %s|%s %s\n"),
1012             status_line, page_len, elapsed_time,
1013             (display_html ? "</A>" : ""),
1014             perfd_time (elapsed_time), perfd_size (page_len));
1015   die (STATE_OK, "%s", msg);
1016   return STATE_UNKNOWN;
1021 /* per RFC 2396 */
1022 #define URI_HTTP "%5[HTPShtps]"
1023 #define URI_HOST "%255[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1024 #define URI_PORT "%6d" /* MAX_PORT's width is 5 chars, 6 to detect overflow */
1025 #define URI_PATH "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1026 #define HD1 URI_HTTP "://" URI_HOST ":" URI_PORT "/" URI_PATH
1027 #define HD2 URI_HTTP "://" URI_HOST "/" URI_PATH
1028 #define HD3 URI_HTTP "://" URI_HOST ":" URI_PORT
1029 #define HD4 URI_HTTP "://" URI_HOST
1030 #define HD5 URI_PATH
1032 void
1033 redir (char *pos, char *status_line)
1035   int i = 0;
1036   char *x;
1037   char xx[2];
1038   char type[6];
1039   char *addr;
1040   char *url;
1042   addr = malloc (MAX_IPV4_HOSTLENGTH + 1);
1043   if (addr == NULL)
1044     die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate addr\n"));
1045   
1046   url = malloc (strcspn (pos, "\r\n"));
1047   if (url == NULL)
1048     die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate url\n"));
1050   while (pos) {
1051     sscanf (pos, "%1[Ll]%*1[Oo]%*1[Cc]%*1[Aa]%*1[Tt]%*1[Ii]%*1[Oo]%*1[Nn]:%n", xx, &i);
1052     if (i == 0) {
1053       pos += (size_t) strcspn (pos, "\r\n");
1054       pos += (size_t) strspn (pos, "\r\n");
1055       if (strlen(pos) == 0) 
1056         die (STATE_UNKNOWN,
1057              _("HTTP UNKNOWN - Could not find redirect location - %s%s\n"),
1058              status_line, (display_html ? "</A>" : ""));
1059       continue;
1060     }
1062     pos += i;
1063     pos += strspn (pos, " \t");
1065     /*
1066      * RFC 2616 (4.2):  ``Header fields can be extended over multiple lines by
1067      * preceding each extra line with at least one SP or HT.''
1068      */
1069     for (; (i = strspn (pos, "\r\n")); pos += i) {
1070       pos += i;
1071       if (!(i = strspn (pos, " \t"))) {
1072         die (STATE_UNKNOWN, _("HTTP UNKNOWN - Empty redirect location%s\n"),
1073              display_html ? "</A>" : "");
1074       }
1075     }
1077     url = realloc (url, strcspn (pos, "\r\n") + 1);
1078     if (url == NULL)
1079       die (STATE_UNKNOWN, _("HTTP UNKNOWN - could not allocate url\n"));
1081     /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
1082     if (sscanf (pos, HD1, type, addr, &i, url) == 4)
1083       use_ssl = server_type_check (type);
1085     /* URI_HTTP URI_HOST URI_PATH */
1086     else if (sscanf (pos, HD2, type, addr, url) == 3 ) { 
1087       use_ssl = server_type_check (type);
1088       i = server_port_check (use_ssl);
1089     }
1091     /* URI_HTTP URI_HOST URI_PORT */
1092     else if(sscanf (pos, HD3, type, addr, &i) == 3) {
1093       strcpy (url, HTTP_URL);
1094       use_ssl = server_type_check (type);
1095     }
1097     /* URI_HTTP URI_HOST */
1098     else if(sscanf (pos, HD4, type, addr) == 2) {
1099       strcpy (url, HTTP_URL);
1100       use_ssl = server_type_check (type);
1101       i = server_port_check (use_ssl);
1102     }
1104     /* URI_PATH */
1105     else if (sscanf (pos, HD5, url) == 1) {
1106       /* relative url */
1107       if ((url[0] != '/')) {
1108         if ((x = strrchr(server_url, '/')))
1109           *x = '\0';
1110         asprintf (&url, "%s/%s", server_url, url);
1111       }
1112       i = server_port;
1113       strcpy (type, server_type);
1114       strcpy (addr, host_name ? host_name : server_address);
1115     }           
1117     else {
1118       die (STATE_UNKNOWN,
1119            _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"),
1120            pos, (display_html ? "</A>" : ""));
1121     }
1123     break;
1125   } /* end while (pos) */
1127   if (++redir_depth > max_depth)
1128     die (STATE_WARNING,
1129          _("HTTP WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"),
1130          max_depth, type, addr, i, url, (display_html ? "</A>" : ""));
1132   if (server_port==i &&
1133       !strcmp(server_address, addr) &&
1134       (host_name && !strcmp(host_name, addr)) &&
1135       !strcmp(server_url, url))
1136     die (STATE_WARNING,
1137          _("HTTP WARNING - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
1138          type, addr, i, url, (display_html ? "</A>" : ""));
1140   strcpy (server_type, type);
1142   free (host_name);
1143   host_name = strdup (addr);
1145   free (server_address);
1146   server_address = strdup (addr);
1148   free (server_url);
1149   if ((url[0] == '/'))
1150     server_url = strdup (url);
1151   else if (asprintf(&server_url, "/%s", url) == -1)
1152     die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate server_url%s\n"),
1153          display_html ? "</A>" : "");
1154   free(url);
1156   if ((server_port = i) > MAX_PORT)
1157     die (STATE_UNKNOWN,
1158          _("HTTP UNKNOWN - Redirection to port above %d - %s://%s:%d%s%s\n"),
1159          MAX_PORT, server_type, server_address, server_port, server_url,
1160          display_html ? "</A>" : "");
1162   if (verbose)
1163     printf (_("Redirection to %s://%s:%d%s\n"), server_type,
1164             host_name ? host_name : server_address, server_port, server_url);
1166   check_http ();
1171 int
1172 server_type_check (const char *type)
1174   if (strcmp (type, "https"))
1175     return FALSE;
1176   else
1177     return TRUE;
1180 int
1181 server_port_check (int ssl_flag)
1183   if (ssl_flag)
1184     return HTTPS_PORT;
1185   else
1186     return HTTP_PORT;
1189 char *perfd_time (double elapsed_time)
1191   return fperfdata ("time", elapsed_time, "s",
1192             check_warning_time, warning_time,
1193             check_critical_time, critical_time,
1194                    TRUE, 0, FALSE, 0);
1199 char *perfd_size (int page_len)
1201   return perfdata ("size", page_len, "B",
1202             (min_page_len>0?TRUE:FALSE), min_page_len,
1203             (min_page_len>0?TRUE:FALSE), 0,
1204             TRUE, 0, FALSE, 0);
1207 void
1208 print_help (void)
1210   print_revision (progname, revision);
1212   printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1213   printf (COPYRIGHT, copyright, email);
1215   printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test"));
1216   printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for"));
1217   printf ("%s\n", _("strings and regular expressions, check connection times, and report on"));
1218   printf ("%s\n", _("certificate expiration times."));
1220   printf ("\n\n");
1222   print_usage ();
1224   printf (_("NOTE: One or both of -H and -I must be specified"));
1226   printf ("\n");
1228   printf (_(UT_HELP_VRSN));
1230   printf (" %s\n", "-H, --hostname=ADDRESS");
1231   printf ("    %s\n", _("Host name argument for servers using host headers (virtual host)"));
1232   printf ("    %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
1233   printf (" %s\n", "-I, --IP-address=ADDRESS");
1234   printf ("    %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
1235   printf (" %s\n", "-p, --port=INTEGER");
1236   printf (" %s", _("Port number (default: "));
1237   printf ("%d)\n", HTTP_PORT);
1239   printf (_(UT_IPv46));
1241 #ifdef HAVE_SSL
1242   printf (" %s\n", "-S, --ssl");
1243   printf ("   %s\n", _("Connect via SSL. Port defaults to 443"));
1244   printf (" %s\n", "-C, --certificate=INTEGER");
1245   printf ("   %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443"));
1246   printf ("   %s\n", _("(when this option is used the url is not checked.)\n"));
1247 #endif
1249   printf (" %s\n", "-e, --expect=STRING");
1250   printf ("    %s\n", _("String to expect in first (status) line of server response (default: "));
1251   printf ("%s)\n", HTTP_EXPECT);
1252   printf ("    %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
1253   printf (" %s\n", "-s, --string=STRING");
1254   printf ("    %s\n", _("String to expect in the content"));
1255   printf (" %s\n", "-u, --url=PATH");
1256   printf ("    %s\n", _("URL to GET or POST (default: /)"));
1257   printf (" %s\n", "-P, --post=STRING");
1258   printf ("    %s\n", _("URL encoded http POST data"));
1259   printf (" %s\n", "-N, --no-body");
1260   printf ("    %s\n", _("Don't wait for document body: stop reading after headers."));
1261   printf ("    %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)"));
1262   printf (" %s\n", "-M, --max-age=SECONDS");
1263   printf ("    %s\n", _("Warn if document is more than SECONDS old. the number can also be of"));
1264   printf ("    %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
1265   printf (" %s\n", "-T, --content-type=STRING");
1266   printf ("    %s\n", _("specify Content-Type header media type when POSTing\n"));
1268   printf (" %s\n", "-l, --linespan");
1269   printf ("    %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
1270   printf (" %s\n", "-r, --regex, --ereg=STRING");
1271   printf ("    %s\n", _("Search page for regex STRING"));
1272   printf (" %s\n", "-R, --eregi=STRING");
1273   printf ("    %s\n", _("Search page for case-insensitive regex STRING"));
1274   printf (" %s\n", "--invert-regex");
1275   printf ("    %s\n", _("Return CRITICAL if found, OK if not\n"));
1277   printf (" %s\n", "-a, --authorization=AUTH_PAIR");
1278   printf ("    %s\n", _("Username:password on sites with basic authentication"));
1279   printf (" %s\n", "-A, --useragent=STRING");
1280   printf ("    %s\n", _("String to be sent in http header as \"User Agent\""));
1281   printf (" %s\n", "-k, --header=STRING");
1282   printf ("    %s\n", _(" Any other tags to be sent in http header. Use multiple times for additional headers"));
1283   printf (" %s\n", "-L, --link");
1284   printf ("    %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
1285   printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow>");
1286   printf ("    %s\n", _("How to handle redirected pages"));
1287   printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
1288   printf ("    %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
1290   printf (_(UT_WARN_CRIT));
1292   printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
1294   printf (_(UT_VERBOSE));
1296   printf (_("Notes:"));
1297   printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
1298   printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
1299   printf (" %s\n", _("other errors return STATE_UNKNOWN.  Successful connects, but incorrect reponse"));
1300   printf (" %s\n", _("messages from the host result in STATE_WARNING return values.  If you are"));
1301   printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
1302   printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
1304 #ifdef HAVE_SSL
1305   printf (" %s\n", _("This plugin can also check whether an SSL enabled web server is able to"));
1306   printf (" %s\n", _("serve content (optionally within a specified time) or whether the X509 "));
1307   printf (" %s\n", _("certificate is still valid for the specified number of days."));
1308   printf (_("Examples:"));
1309   printf (" %s\n\n", "CHECK CONTENT: check_http -w 5 -c 10 --ssl -H www.verisign.com");
1310   printf (" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
1311   printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
1312   printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
1313   printf (" %s\n\n", _("a STATE_CRITICAL will be returned."));
1315   printf (" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 14");
1316   printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
1317   printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
1318   printf (" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
1319   printf (" %s\n\n", _("the certificate is expired."));
1320 #endif
1322   printf (_(UT_SUPPORT));
1328 void
1329 print_usage (void)
1331   printf (_("Usage:"));
1332   printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname);
1333   printf ("       [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L]\n");
1334   printf ("       [-a auth] [-f <ok | warn | critcal | follow>] [-e <expect>]\n");
1335   printf ("       [-s string] [-l] [-r <regex> | -R <case-insensitive regex>] [-P string]\n");
1336   printf ("       [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>] [-A string]\n");
1337   printf ("       [-k string] [-S] [-C <age>] [-T <content-type>]\n");