Code

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