Code

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