Code

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