diff options
Diffstat (limited to 'web/attachments/86330-check_http.patch')
-rw-r--r-- | web/attachments/86330-check_http.patch | 353 |
1 files changed, 353 insertions, 0 deletions
diff --git a/web/attachments/86330-check_http.patch b/web/attachments/86330-check_http.patch new file mode 100644 index 0000000..df817d1 --- /dev/null +++ b/web/attachments/86330-check_http.patch | |||
@@ -0,0 +1,353 @@ | |||
1 | --- /tmp/check_http.c 2004-04-13 20:09:38.000000000 -0700 | ||
2 | +++ check_http.c 2004-04-13 20:25:40.000000000 -0700 | ||
3 | @@ -21,6 +21,8 @@ | ||
4 | * | ||
5 | * $Id: check_http.c,v 1.24.2.4 2003/06/21 05:31:23 kdebisschop Exp $ | ||
6 | * | ||
7 | + * 13-Apr-2004 -- jwz -- added "--no-body" and "--max-age" options | ||
8 | + * | ||
9 | *****************************************************************************/ | ||
10 | |||
11 | const char *progname = "check_http"; | ||
12 | @@ -45,7 +47,7 @@ | ||
13 | [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L]\n\ | ||
14 | [-a auth] [-f <ok | warn | critcal | follow>] [-e <expect>]\n\ | ||
15 | [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n\ | ||
16 | - [-P string]" | ||
17 | + [-P string] [-N] [-M <age>]" | ||
18 | |||
19 | #define LONGOPTIONS "\ | ||
20 | -H, --hostname=ADDRESS\n\ | ||
21 | @@ -63,6 +65,13 @@ | ||
22 | Port number (default: %d)\n\ | ||
23 | -P, --post=STRING\n\ | ||
24 | URL encoded http POST data\n\ | ||
25 | + -N, --no-body\n\ | ||
26 | + Don't wait for document body: stop reading after headers.\n\ | ||
27 | + (Note that this still does an HTTP GET or POST, not a HEAD.)\n\ | ||
28 | + -M, --max-age=SECONDS\n\ | ||
29 | + Warn if the document is more than SECONDS old. The number can\n\ | ||
30 | + also be of the form \"10m\" for minutes, \"10h\" for hours, or\n\ | ||
31 | + \"10d\" for days.\n\ | ||
32 | -w, --warning=INTEGER\n\ | ||
33 | Response time to result in warning status (seconds)\n\ | ||
34 | -c, --critical=INTEGER\n\ | ||
35 | @@ -159,6 +168,10 @@ | ||
36 | int check_certificate (X509 **); | ||
37 | #endif | ||
38 | |||
39 | +/* jwz */ | ||
40 | +int no_body = FALSE; | ||
41 | +int maximum_age = -1; | ||
42 | + | ||
43 | #ifdef HAVE_REGEX_H | ||
44 | enum { | ||
45 | REGS = 2, | ||
46 | @@ -311,6 +324,10 @@ | ||
47 | {"linespan", no_argument, 0, 'l'}, | ||
48 | {"onredirect", required_argument, 0, 'f'}, | ||
49 | {"certificate", required_argument, 0, 'C'}, | ||
50 | + | ||
51 | + /* jwz */ | ||
52 | + {"no-body", no_argument, 0, 'N'}, | ||
53 | + {"max-age", required_argument, 0, 'M'}, | ||
54 | {0, 0, 0, 0} | ||
55 | }; | ||
56 | #endif | ||
57 | @@ -331,7 +348,8 @@ | ||
58 | strcpy (argv[c], "-n"); | ||
59 | } | ||
60 | |||
61 | -#define OPTCHARS "Vvht:c:w:H:P:I:a:e:p:s:R:r:u:f:C:nlLS" | ||
62 | +/*#define OPTCHARS "Vvht:c:w:H:P:I:a:e:p:s:R:r:u:f:C:nlLS"*/ | ||
63 | +#define OPTCHARS "Vvht:c:w:H:P:I:a:e:p:s:R:r:u:f:C:M:nlLSN" /* jwz */ | ||
64 | |||
65 | while (1) { | ||
66 | #ifdef HAVE_GETOPT_H | ||
67 | @@ -469,6 +487,27 @@ | ||
68 | case 'v': /* verbose */ | ||
69 | verbose = TRUE; | ||
70 | break; | ||
71 | + case 'N': /* no-body (jwz) */ | ||
72 | + no_body = TRUE; | ||
73 | + break; | ||
74 | + case 'M': /* max-age (jwz) */ | ||
75 | + { | ||
76 | + int L = strlen(optarg); | ||
77 | + if (L && optarg[L-1] == 'm') | ||
78 | + maximum_age = atoi (optarg) * 60; | ||
79 | + else if (L && optarg[L-1] == 'h') | ||
80 | + maximum_age = atoi (optarg) * 60 * 60; | ||
81 | + else if (L && optarg[L-1] == 'd') | ||
82 | + maximum_age = atoi (optarg) * 60 * 60 * 24; | ||
83 | + else if (L && (optarg[L-1] == 's' || | ||
84 | + isdigit (optarg[L-1]))) | ||
85 | + maximum_age = atoi (optarg); | ||
86 | + else { | ||
87 | + fprintf (stderr, "unparsable max-age: %s\n", optarg); | ||
88 | + exit (1); | ||
89 | + } | ||
90 | + } | ||
91 | + break; | ||
92 | } | ||
93 | } | ||
94 | |||
95 | @@ -534,6 +573,223 @@ | ||
96 | |||
97 | |||
98 | |||
99 | +/* Returns 1 if we're done processing the document body; 0 to keep going. | ||
100 | + (jwz) | ||
101 | + */ | ||
102 | +static int | ||
103 | +document_headers_done (char *full_page) | ||
104 | +{ | ||
105 | + const char *body, *s; | ||
106 | + const char *end; | ||
107 | + | ||
108 | + for (body = full_page; *body; body++) { | ||
109 | + if (!strncmp (body, "\n\n", 2) || | ||
110 | + !strncmp (body, "\n\r\n", 3)) | ||
111 | + break; | ||
112 | + } | ||
113 | + | ||
114 | + if (!*body) | ||
115 | + return 0; /* haven't read end of headers yet */ | ||
116 | + | ||
117 | + full_page[body - full_page] = 0; | ||
118 | + return 1; | ||
119 | +} | ||
120 | + | ||
121 | + | ||
122 | +/* jwz */ | ||
123 | +static time_t | ||
124 | +parse_time_string (const char *string) | ||
125 | +{ | ||
126 | + struct tm tm; | ||
127 | + time_t t; | ||
128 | + memset (&tm, 0, sizeof(tm)); | ||
129 | + | ||
130 | + /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */ | ||
131 | + | ||
132 | + if (isupper (string[0]) && /* Tue */ | ||
133 | + islower (string[1]) && | ||
134 | + islower (string[2]) && | ||
135 | + ',' == string[3] && | ||
136 | + ' ' == string[4] && | ||
137 | + (isdigit(string[5]) || string[5] == ' ') && /* 25 */ | ||
138 | + isdigit (string[6]) && | ||
139 | + ' ' == string[7] && | ||
140 | + isupper (string[8]) && /* Dec */ | ||
141 | + islower (string[9]) && | ||
142 | + islower (string[10]) && | ||
143 | + ' ' == string[11] && | ||
144 | + isdigit (string[12]) && /* 2001 */ | ||
145 | + isdigit (string[13]) && | ||
146 | + isdigit (string[14]) && | ||
147 | + isdigit (string[15]) && | ||
148 | + ' ' == string[16] && | ||
149 | + isdigit (string[17]) && /* 02: */ | ||
150 | + isdigit (string[18]) && | ||
151 | + ':' == string[19] && | ||
152 | + isdigit (string[20]) && /* 59: */ | ||
153 | + isdigit (string[21]) && | ||
154 | + ':' == string[22] && | ||
155 | + isdigit (string[23]) && /* 03 */ | ||
156 | + isdigit (string[24]) && | ||
157 | + ' ' == string[25] && | ||
158 | + 'G' == string[26] && /* GMT */ | ||
159 | + 'M' == string[27] && /* GMT */ | ||
160 | + 'T' == string[28]) { | ||
161 | + | ||
162 | + tm.tm_sec = 10 * (string[23]-'0') + (string[24]-'0'); | ||
163 | + tm.tm_min = 10 * (string[20]-'0') + (string[21]-'0'); | ||
164 | + tm.tm_hour = 10 * (string[17]-'0') + (string[18]-'0'); | ||
165 | + tm.tm_mday = 10 * (string[5] == ' ' ? 0 : string[5]-'0') + (string[6]-'0'); | ||
166 | + tm.tm_mon = (!strncmp (string+8, "Jan", 3) ? 0 : | ||
167 | + !strncmp (string+8, "Feb", 3) ? 1 : | ||
168 | + !strncmp (string+8, "Mar", 3) ? 2 : | ||
169 | + !strncmp (string+8, "Apr", 3) ? 3 : | ||
170 | + !strncmp (string+8, "May", 3) ? 4 : | ||
171 | + !strncmp (string+8, "Jun", 3) ? 5 : | ||
172 | + !strncmp (string+8, "Jul", 3) ? 6 : | ||
173 | + !strncmp (string+8, "Aug", 3) ? 7 : | ||
174 | + !strncmp (string+8, "Sep", 3) ? 8 : | ||
175 | + !strncmp (string+8, "Oct", 3) ? 9 : | ||
176 | + !strncmp (string+8, "Nov", 3) ? 10 : | ||
177 | + !strncmp (string+8, "Dec", 3) ? 11 : | ||
178 | + -1); | ||
179 | + tm.tm_year = ((1000 * (string[12]-'0') + | ||
180 | + 100 * (string[13]-'0') + | ||
181 | + 10 * (string[14]-'0') + | ||
182 | + (string[15]-'0')) | ||
183 | + - 1900); | ||
184 | + | ||
185 | + tm.tm_isdst = 0; /* GMT is never in DST, right? */ | ||
186 | + | ||
187 | + if (tm.tm_mon < 0 || | ||
188 | + tm.tm_mday < 1 || | ||
189 | + tm.tm_mday > 31) | ||
190 | + return 0; | ||
191 | + | ||
192 | + /* #### This is actually wrong: we need to subtract the local timezone | ||
193 | + offset from GMT from this value. But, that's ok in this usage, | ||
194 | + because we only comparing these two GMT dates against each other, | ||
195 | + so it doesn't matter what time zone we parse them in. | ||
196 | + */ | ||
197 | + | ||
198 | + t = mktime (&tm); | ||
199 | + if (t == (time_t) -1) t = 0; | ||
200 | + | ||
201 | + if (verbose) { | ||
202 | + const char *s = string; | ||
203 | + while (*s && *s != '\r' && *s != '\n') | ||
204 | + fputc (*s++, stdout); | ||
205 | + printf (" ==> %lu\n", (unsigned long) t); | ||
206 | + } | ||
207 | + | ||
208 | + return t; | ||
209 | + | ||
210 | + } else { | ||
211 | + return 0; | ||
212 | + } | ||
213 | +} | ||
214 | + | ||
215 | + | ||
216 | +/* jwz */ | ||
217 | +static void | ||
218 | +check_document_dates (const char *headers) | ||
219 | +{ | ||
220 | + const char *s; | ||
221 | + char *server_date = 0; | ||
222 | + char *document_date = 0; | ||
223 | + | ||
224 | + s = headers; | ||
225 | + while (*s) { | ||
226 | + const char *field = s; | ||
227 | + const char *value = 0; | ||
228 | + | ||
229 | + /* Find the end of the header field */ | ||
230 | + while (*s && !isspace(*s) && *s != ':') | ||
231 | + s++; | ||
232 | + | ||
233 | + /* Remember the header value, if any. */ | ||
234 | + if (*s == ':') | ||
235 | + value = ++s; | ||
236 | + | ||
237 | + /* Skip to the end of the header, including continuation lines. */ | ||
238 | + while (*s && | ||
239 | + !(*s == '\n' && (s[1] != ' ' && s[1] != '\t'))) | ||
240 | + s++; | ||
241 | + s++; | ||
242 | + | ||
243 | + /* Process this header. */ | ||
244 | + if (value && value > field+2) { | ||
245 | + char *ff = (char *) malloc (value-field); | ||
246 | + char *ss = ff; | ||
247 | + while (field < value-1) | ||
248 | + *ss++ = tolower(*field++); | ||
249 | + *ss++ = 0; | ||
250 | + | ||
251 | + if (!strcmp (ff, "date") || | ||
252 | + !strcmp (ff, "last-modified")) { | ||
253 | + const char *e; | ||
254 | + while (*value && isspace (*value)) | ||
255 | + value++; | ||
256 | + for (e = value; *e && *e != '\r' && *e != '\n'; e++) | ||
257 | + ; | ||
258 | + ss = (char *) malloc (e - value + 1); | ||
259 | + strncpy (ss, value, e - value); | ||
260 | + ss[e - value] = 0; | ||
261 | + if (!strcmp (ff, "date")) { | ||
262 | + if (server_date) free (server_date); | ||
263 | + server_date = ss; | ||
264 | + } else { | ||
265 | + if (document_date) free (document_date); | ||
266 | + document_date = ss; | ||
267 | + } | ||
268 | + } | ||
269 | + free (ff); | ||
270 | + } | ||
271 | + } | ||
272 | + | ||
273 | + /* Done parsing the body. Now check the dates we (hopefully) parsed. | ||
274 | + */ | ||
275 | + if (!server_date || !*server_date) { | ||
276 | + terminate (STATE_UNKNOWN, "server date unknown\n"); | ||
277 | + } else if (!document_date || !*document_date) { | ||
278 | + terminate (STATE_CRITICAL, "document modification date unknown\n"); | ||
279 | + } else { | ||
280 | + time_t sd = parse_time_string (server_date); | ||
281 | + time_t dd = parse_time_string (document_date); | ||
282 | + char buf [255]; | ||
283 | + | ||
284 | + if (sd <= 0) { | ||
285 | + sprintf (buf, "server date \"%100s\" unparsable", server_date); | ||
286 | + terminate (STATE_CRITICAL, buf); | ||
287 | + | ||
288 | + } else if (dd <= 0) { | ||
289 | + sprintf (buf, "document date \"%100s\" unparsable", document_date); | ||
290 | + terminate (STATE_CRITICAL, buf); | ||
291 | + | ||
292 | + } else if (dd > sd + 30) { | ||
293 | + char buf[200]; | ||
294 | + sprintf (buf, "document is %d seconds in the future\n", dd - sd); | ||
295 | + terminate (STATE_CRITICAL, buf); | ||
296 | + | ||
297 | + } else if (dd < sd - maximum_age) { | ||
298 | + char buf[200]; | ||
299 | + int n = (sd - dd); | ||
300 | + if (n > (60 * 60 * 24 * 2)) | ||
301 | + sprintf (buf, "last modified %.1f days ago\n", | ||
302 | + ((float) n) / (60 * 60 * 24)); | ||
303 | + else | ||
304 | + sprintf (buf, "last modified %d:%02d:%02d ago\n", | ||
305 | + n / (60 * 60), (n / 60) % 60, n % 60); | ||
306 | + terminate (STATE_CRITICAL, buf); | ||
307 | + } | ||
308 | + | ||
309 | + free (server_date); | ||
310 | + free (document_date); | ||
311 | + } | ||
312 | +} | ||
313 | + | ||
314 | + | ||
315 | + | ||
316 | int | ||
317 | check_http (void) | ||
318 | { | ||
319 | @@ -625,6 +881,12 @@ | ||
320 | buffer[i] = '\0'; | ||
321 | asprintf (&full_page, "%s%s", full_page, buffer); | ||
322 | pagesize += i; | ||
323 | + | ||
324 | + /* jwz */ | ||
325 | + if (no_body && document_headers_done (full_page)) { | ||
326 | + i = 0; | ||
327 | + break; | ||
328 | + } | ||
329 | } | ||
330 | |||
331 | if (i < 0 && errno != ECONNRESET) { | ||
332 | @@ -685,7 +947,8 @@ | ||
333 | page += (size_t) strspn (page, "\r\n"); | ||
334 | header[pos - header] = 0; | ||
335 | if (verbose) | ||
336 | - printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header, page); | ||
337 | + printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header, | ||
338 | + (no_body ? " [[ skipped ]]" : page)); /* jwz */ | ||
339 | |||
340 | /* make sure the status line matches the response we are looking for */ | ||
341 | if (!strstr (status_line, server_expect)) { | ||
342 | @@ -810,6 +1073,11 @@ | ||
343 | } /* end else (server_expect_yn) */ | ||
344 | |||
345 | |||
346 | + /* jwz */ | ||
347 | + if (maximum_age >= 0) { | ||
348 | + check_document_dates (header); | ||
349 | + } | ||
350 | + | ||
351 | /* check elapsed time */ | ||
352 | elapsed_time = delta_time (tv); | ||
353 | asprintf (&msg, "HTTP problem: %s - %7.3f second response time %s%s|time=%7.3f\n", | ||