Code

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