summaryrefslogtreecommitdiffstats
path: root/web/attachments/427519-http-parser.bundle
diff options
context:
space:
mode:
Diffstat (limited to 'web/attachments/427519-http-parser.bundle')
-rw-r--r--web/attachments/427519-http-parser.bundle1396
1 files changed, 1396 insertions, 0 deletions
diff --git a/web/attachments/427519-http-parser.bundle b/web/attachments/427519-http-parser.bundle
new file mode 100644
index 0000000..74ab9e4
--- /dev/null
+++ b/web/attachments/427519-http-parser.bundle
@@ -0,0 +1,1396 @@
1From 256d8d15acf98ee405f79b75a52692531d173f49 Mon Sep 17 00:00:00 2001
2From: Ferenc Wagner <wferi@niif.hu>
3Date: Wed, 2 Nov 2011 10:03:38 +0100
4Subject: [PATCH 0/9] check_http: add support for chunked encoding via http-parser
5
6Hi,
7
8Here is an attempt to add support for chunked encoding in check_http
9by switching to the third-party HTTP parser from Joyent hosted at
10https://github.com/joyent/http-parser. The switch makes much of the
11in-house ad-hoc parsing code redundant, and induces some changes in
12the semantics of the -e switch, but that should be regarded as a step
13forward, since the role of that switch was to verify HTTP correctness
14(at least in part) and now we have a much better mechanism for that:
15the parser itself. The pagesize limits (-m switch) also gained a
16clearer semantics: they check the content size now, as that may be
17available even when -N is used, and does not depend on the transfer
18encoding.
19
20Ferenc Wagner (9):
21 check_http: do not print page length if body was not read
22 Add lib/http-parser submodule and adjust Makefile.am to use it in
23 check_http
24 check_http: move status code and redirect location parsing to
25 http-parser
26 check_http: whitespace change to fix up indentation by removing dummy
27 block
28 check_http: constify and rename the location argument for redir()
29 check_http: make list of parsed headers configurable
30 check_http: use header parsing machinery in check_document_dates()
31 check_http: also read the response content via http-parse
32 check_http: check content length instead of response length
33
34 .gitmodules | 3 +
35 lib/Makefile.am | 10 +-
36 lib/http-parser | 1 +
37 plugins/Makefile.am | 9 +-
38 plugins/check_http.c | 596 ++++++++++++++++++++------------------------------
39 5 files changed, 256 insertions(+), 363 deletions(-)
40 create mode 100644 .gitmodules
41 create mode 160000 lib/http-parser
42
43--
441.7.2.5
45
46From abc1d1c539376cb5531a9686e581ff62acf421e5 Mon Sep 17 00:00:00 2001
47From: Ferenc Wagner <wferi@niif.hu>
48Date: Mon, 31 Oct 2011 15:10:54 +0100
49Subject: [PATCH 1/9] check_http: do not print page length if body was not read
50
51
52Signed-off-by: Ferenc Wagner <wferi@niif.hu>
53---
54 plugins/check_http.c | 2 +-
55 1 files changed, 1 insertions(+), 1 deletions(-)
56
57diff --git a/plugins/check_http.c b/plugins/check_http.c
58index 433c28e..6df9d23 100644
59--- a/plugins/check_http.c
60+++ b/plugins/check_http.c
61@@ -923,7 +923,7 @@ check_http (void)
62 /* leave full_page untouched so we can free it later */
63 page = full_page;
64
65- if (verbose)
66+ if (verbose && !no_body)
67 printf ("%s://%s:%d%s is %d characters\n",
68 use_ssl ? "https" : "http", server_address,
69 server_port, server_url, (int)pagesize);
70--
711.7.2.5
72
73
74From 27536d84b73489308f129ff5623ffd1445dfc5fb Mon Sep 17 00:00:00 2001
75From: Ferenc Wagner <wferi@niif.hu>
76Date: Mon, 31 Oct 2011 15:14:38 +0100
77Subject: [PATCH 2/9] Add lib/http-parser submodule and adjust Makefile.am to use it in check_http
78
79
80Signed-off-by: Ferenc Wagner <wferi@niif.hu>
81---
82 .gitmodules | 3 +++
83 lib/Makefile.am | 10 +++++++++-
84 lib/http-parser | 1 +
85 plugins/Makefile.am | 9 +++++----
86 4 files changed, 18 insertions(+), 5 deletions(-)
87 create mode 100644 .gitmodules
88 create mode 160000 lib/http-parser
89
90diff --git a/.gitmodules b/.gitmodules
91new file mode 100644
92index 0000000..5270743
93--- /dev/null
94+++ b/.gitmodules
95@@ -0,0 +1,3 @@
96+[submodule "lib/http-parser"]
97+ path = lib/http-parser
98+ url = git://github.com/joyent/http-parser.git
99diff --git a/lib/Makefile.am b/lib/Makefile.am
100index 99fa591..561b7cf 100644
101--- a/lib/Makefile.am
102+++ b/lib/Makefile.am
103@@ -2,7 +2,7 @@
104
105 SUBDIRS = . tests
106
107-noinst_LIBRARIES = libnagiosplug.a
108+noinst_LIBRARIES = libnagiosplug.a http-parser/libhttp_parser.a
109
110 AM_CPPFLAGS = -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\"
111
112@@ -18,3 +18,11 @@ INCLUDES = -I$(srcdir) -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/p
113 test test-debug:
114 cd tests && make $@
115
116+http-parser/libhttp_parser.a:
117+ cd http-parser && $(MAKE) package
118+
119+mostlyclean-local:
120+ cd http-parser && $(MAKE) clean
121+
122+check-local:
123+ cd http-parser && $(MAKE) test
124diff --git a/lib/http-parser b/lib/http-parser
125new file mode 160000
126index 0000000..f1d48aa
127--- /dev/null
128+++ b/lib/http-parser
129@@ -0,0 +1 @@
130+Subproject commit f1d48aa31c932f80a64122a75a87bc909b4073f9
131diff --git a/plugins/Makefile.am b/plugins/Makefile.am
132index 36a28b0..2df105e 100644
133--- a/plugins/Makefile.am
134+++ b/plugins/Makefile.am
135@@ -13,7 +13,7 @@ AM_CFLAGS = -DNP_VERSION='"$(NP_VERSION)"'
136
137 VPATH = $(top_srcdir) $(top_srcdir)/lib $(top_srcdir)/plugins $(top_srcdir)/plugins/t
138
139-INCLUDES = -I.. -I$(top_srcdir)/lib -I$(top_srcdir)/gl -I$(top_srcdir)/intl @LDAPINCLUDE@ @PGINCLUDE@ @SSLINCLUDE@
140+INCLUDES = -I.. -I$(top_srcdir)/lib -I$(top_srcdir)/lib/http-parser -I$(top_srcdir)/gl -I$(top_srcdir)/intl @LDAPINCLUDE@ @PGINCLUDE@ @SSLINCLUDE@
141
142 localedir = $(datadir)/locale
143 # gettext docs say to use AM_CPPFLAGS, but per module_CPPFLAGS override this
144@@ -48,6 +48,7 @@ BASEOBJS = utils.o ../lib/libnagiosplug.a ../gl/libgnu.a
145 NETOBJS = netutils.o $(BASEOBJS) $(EXTRA_NETOBJS)
146 SSLOBJS = sslutils.o
147 NETLIBS = $(NETOBJS) $(SOCKETLIBS)
148+HTTPPARSER = ../lib/http-parser/libhttp_parser.a
149
150 TESTS_ENVIRONMENT = perl -I $(top_builddir) -I $(top_srcdir)
151
152@@ -70,7 +71,7 @@ check_dns_LDADD = $(NETLIBS) runcmd.o
153 check_dummy_LDADD = $(BASEOBJS)
154 check_fping_LDADD = $(NETLIBS) popen.o
155 check_game_LDADD = $(BASEOBJS) runcmd.o
156-check_http_LDADD = $(SSLOBJS) $(NETLIBS) $(SSLLIBS)
157+check_http_LDADD = $(SSLOBJS) $(NETLIBS) $(SSLLIBS) $(HTTPPARSER)
158 check_hpjd_LDADD = $(NETLIBS) popen.o
159 check_ldap_LDADD = $(NETLIBS) $(LDAPLIBS)
160 check_load_LDADD = $(BASEOBJS) popen.o
161@@ -115,7 +116,7 @@ check_dns_DEPENDENCIES = check_dns.c $(NETOBJS) runcmd.o $(DEPLIBS)
162 check_dummy_DEPENDENCIES = check_dummy.c $(DEPLIBS)
163 check_fping_DEPENDENCIES = check_fping.c $(NETOBJS) popen.o $(DEPLIBS)
164 check_game_DEPENDENCIES = check_game.c $(DEPLIBS) runcmd.o
165-check_http_DEPENDENCIES = check_http.c $(SSLOBJS) $(NETOBJS) $(DEPLIBS)
166+check_http_DEPENDENCIES = check_http.c $(SSLOBJS) $(NETOBJS) $(DEPLIBS) $(HTTPPARSER)
167 check_hpjd_DEPENDENCIES = check_hpjd.c $(NETOBJS) popen.o $(DEPLIBS)
168 check_ide_smart_DEPENDENCIES = check_ide_smart.c $(BASEOBJS) $(DEPLIBS)
169 check_ldap_DEPENDENCIES = check_ldap.c $(NETOBJS) $(DEPLIBS)
170@@ -170,7 +171,7 @@ install-exec-hook:
171 cd $(DESTDIR)$(libexecdir) && \
172 for i in $(check_tcp_programs) ; do rm -f $$i; ln -s check_tcp $$i ; done ;\
173 if [ -x check_ldap ] ; then rm -f check_ldaps ; ln -s check_ldap check_ldaps ; fi
174-
175+
176 clean-local:
177 rm -f $(check_tcp_programs)
178 rm -f NP-VERSION-FILE
179--
1801.7.2.5
181
182
183From e8b35f17bf23515dc43233ebbde1c0ccb11d5ecb Mon Sep 17 00:00:00 2001
184From: Ferenc Wagner <wferi@niif.hu>
185Date: Mon, 31 Oct 2011 15:20:48 +0100
186Subject: [PATCH 3/9] check_http: move status code and redirect location parsing to http-parser
187
188This changes the semantics of the -e switch, as http-parser doesn't make
189the status string available. But it does substantial HTTP verification,
190so much of the original functionality will be regained once HTTP parsing
191errors become CRITICAL.
192
193This introduces some new gettext strings.
194
195Signed-off-by: Ferenc Wagner <wferi@niif.hu>
196---
197 plugins/check_http.c | 264 +++++++++++++++++++++++++-------------------------
198 1 files changed, 131 insertions(+), 133 deletions(-)
199
200diff --git a/plugins/check_http.c b/plugins/check_http.c
201index 6df9d23..ada7a95 100644
202--- a/plugins/check_http.c
203+++ b/plugins/check_http.c
204@@ -41,6 +41,7 @@ const char *email = "nagiosplug-devel@lists.sourceforge.net";
205 #include "netutils.h"
206 #include "utils.h"
207 #include "base64.h"
208+#include "http_parser.h"
209 #include <ctype.h>
210
211 #define INPUT_DELIMITER ";"
212@@ -48,7 +49,15 @@ const char *email = "nagiosplug-devel@lists.sourceforge.net";
213 #define STICKY_HOST 1
214 #define STICKY_PORT 2
215
216-#define HTTP_EXPECT "HTTP/1."
217+struct parser_data_t {
218+ enum http_errno prev_callback; /* use HPE_CB_ macros for identifying callbacks */
219+ char *current_header;
220+ size_t current_header_length;
221+ int parsing_location;
222+ char *location;
223+ size_t location_length;
224+};
225+
226 enum {
227 MAX_IPV4_HOSTLENGTH = 255,
228 HTTP_PORT = 80,
229@@ -97,8 +106,7 @@ char *host_name;
230 char *server_url;
231 char *user_agent;
232 int server_url_length;
233-int server_expect_yn = 0;
234-char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
235+int status_expect = -1;
236 char string_expect[MAX_INPUT_BUFFER] = "";
237 char output_string_search[30] = "";
238 char *warning_thresholds = NULL;
239@@ -126,7 +134,7 @@ char buffer[MAX_INPUT_BUFFER];
240
241 int process_arguments (int, char **);
242 int check_http (void);
243-void redir (char *pos, char *status_line);
244+void redir (char *pos);
245 int server_type_check(const char *type);
246 int server_port_check(int ssl_flag);
247 char *perfd_time (double microsec);
248@@ -367,10 +375,8 @@ process_arguments (int argc, char **argv)
249 strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1);
250 string_expect[MAX_INPUT_BUFFER - 1] = 0;
251 break;
252- case 'e': /* string or substring */
253- strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1);
254- server_expect[MAX_INPUT_BUFFER - 1] = 0;
255- server_expect_yn = 1;
256+ case 'e': /* expected HTTP response code */
257+ status_expect = atoi (optarg);
258 break;
259 case 'T': /* Content-type */
260 asprintf (&http_content_type, "%s", optarg);
261@@ -589,26 +595,6 @@ parse_time_string (const char *string)
262 }
263 }
264
265-/* Checks if the server 'reply' is one of the expected 'statuscodes' */
266-static int
267-expected_statuscode (const char *reply, const char *statuscodes)
268-{
269- char *expected, *code;
270- int result = 0;
271-
272- if ((expected = strdup (statuscodes)) == NULL)
273- die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
274-
275- for (code = strtok (expected, ","); code != NULL; code = strtok (NULL, ","))
276- if (strstr (reply, code) != NULL) {
277- result = 1;
278- break;
279- }
280-
281- free (expected);
282- return result;
283-}
284-
285 static int
286 check_document_dates (const char *headers, char **msg)
287 {
288@@ -772,16 +758,78 @@ prepend_slash (char *path)
289 return newpath;
290 }
291
292+/*
293+Returns 0 on success, 1 if allocation fails.
294+Works on binary data, but also zero-terminates the result
295+for easier string handling.
296+*/
297+int
298+append (char **orig, size_t *orig_len, const char *extra, size_t len)
299+{
300+ *orig = realloc (*orig, *orig_len + len + 1);
301+ if (!*orig) return 1;
302+ memcpy (*orig + *orig_len, extra, len);
303+ *orig_len += len;
304+ (*orig)[*orig_len] = 0;
305+ return 0;
306+}
307+
308+int
309+header_field_callback (http_parser *parser, const char *at, size_t length)
310+{
311+ struct parser_data_t *data = parser->data;
312+
313+ switch (data->prev_callback) {
314+ case HPE_CB_header_value:
315+ data->current_header_length = 0;
316+ /* fall through */
317+ case 0:
318+ data->prev_callback = HPE_CB_header_field;
319+ /* fall through */
320+ case HPE_CB_header_field:
321+ return append (&data->current_header, &data->current_header_length, at, length);
322+ default:
323+ return 1;
324+ }
325+}
326+
327+int
328+header_value_callback (http_parser *parser, const char *at, size_t length)
329+{
330+ struct parser_data_t *data = parser->data;
331+
332+ switch (data->prev_callback) {
333+ case HPE_CB_header_field:
334+ data->parsing_location = !strcasecmp (data->current_header, "location");
335+ data->prev_callback = HPE_CB_header_value;
336+ /* fall through */
337+ case HPE_CB_header_value:
338+ return data->parsing_location &&
339+ append (&data->location, &data->location_length, at, length);
340+ default:
341+ return 1;
342+ }
343+}
344+
345+int
346+headers_complete_callback (http_parser *parser)
347+{
348+ struct parser_data_t *data = parser->data;
349+
350+ data->prev_callback = HPE_CB_headers_complete;
351+
352+ if (no_body) /* Terminate parsing (thus reading) if the -N option is set */
353+ return 2; /* 1 means don't expect body in this callback */
354+ return 0;
355+}
356+
357 int
358 check_http (void)
359 {
360 char *msg;
361- char *status_line;
362- char *status_code;
363 char *header;
364 char *page;
365 char *auth;
366- int http_status;
367 int i = 0;
368 size_t pagesize = 0;
369 char *full_page;
370@@ -792,6 +840,9 @@ check_http (void)
371 double elapsed_time;
372 int page_len = 0;
373 int result = STATE_OK;
374+ http_parser_settings settings;
375+ http_parser parser;
376+ struct parser_data_t parser_data;
377
378 /* try to connect to the host at the given port number */
379 if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
380@@ -869,9 +920,29 @@ check_http (void)
381 if (verbose) printf ("%s\n", buf);
382 my_send (buf, strlen (buf));
383
384+ /* Initialize the HTTP parser */
385+ http_parser_init (&parser, HTTP_RESPONSE);
386+ memset (&parser_data, 0, sizeof parser_data);
387+ parser.data = &parser_data;
388+ memset (&settings, 0, sizeof settings);
389+ settings.on_header_field = header_field_callback;
390+ settings.on_header_value = header_value_callback;
391+ settings.on_headers_complete = headers_complete_callback;
392+
393 /* fetch the page */
394 full_page = strdup("");
395- while ((i = my_recv (buffer, MAX_INPUT_BUFFER-1)) > 0) {
396+ while ((i = my_recv (buffer, MAX_INPUT_BUFFER-1)) >= 0) {
397+ int nparsed = http_parser_execute(&parser, &settings, buffer, i);
398+ if (nparsed != i) {
399+ enum http_errno code = HTTP_PARSER_ERRNO (&parser);
400+ if (code == HPE_CB_headers_complete) { /* the -N check fired */
401+ /* break; FIXME this would break the current header code */
402+ } else {
403+ printf ("http_parser_execute returned %d instead of %i: %s\n",
404+ nparsed, i, http_errno_description (code));
405+ }
406+ }
407+ if (i == 0) break;
408 buffer[i] = '\0';
409 asprintf (&full_page_new, "%s%s", full_page, buffer);
410 free (full_page);
411@@ -928,15 +999,9 @@ check_http (void)
412 use_ssl ? "https" : "http", server_address,
413 server_port, server_url, (int)pagesize);
414
415- /* find status line and null-terminate it */
416- status_line = page;
417+ /* skip status line */
418 page += (size_t) strcspn (page, "\r\n");
419- pos = page;
420 page += (size_t) strspn (page, "\r\n");
421- status_line[strcspn(status_line, "\r\n")] = 0;
422- strip (status_line);
423- if (verbose)
424- printf ("STATUS: %s\n", status_line);
425
426 /* find header info and null-terminate it */
427 header = page;
428@@ -955,68 +1020,38 @@ check_http (void)
429 printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header,
430 (no_body ? " [[ skipped ]]" : page));
431
432- /* make sure the status line matches the response we are looking for */
433- if (!expected_statuscode (status_line, server_expect)) {
434- if (server_port == HTTP_PORT)
435- asprintf (&msg,
436- _("Invalid HTTP response received from host: %s\n"),
437- status_line);
438- else
439- asprintf (&msg,
440- _("Invalid HTTP response received from host on port %d: %s\n"),
441- server_port, status_line);
442- die (STATE_CRITICAL, "HTTP CRITICAL - %s", msg);
443- }
444-
445- /* Bypass normal status line check if server_expect was set by user and not default */
446- /* NOTE: After this if/else block msg *MUST* be an asprintf-allocated string */
447- if ( server_expect_yn ) {
448- asprintf (&msg,
449- _("Status line output matched \"%s\" - "), server_expect);
450- if (verbose)
451- printf ("%s\n",msg);
452- }
453- else {
454- /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
455- /* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
456- /* Status-Code = 3 DIGITS */
457-
458- status_code = strchr (status_line, ' ') + sizeof (char);
459- if (strspn (status_code, "1234567890") != 3)
460- die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line);
461-
462- http_status = atoi (status_code);
463-
464- /* check the return code */
465-
466- if (http_status >= 600 || http_status < 100) {
467- die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line);
468+ if (status_expect != -1) {
469+ if (parser.status_code == status_expect)
470+ asprintf (&msg, _("Got expected code %d - "), status_expect);
471+ else {
472+ asprintf (&msg, _("Invalid HTTP status received from host: %d\n"),
473+ parser.status_code);
474+ die (STATE_CRITICAL, "HTTP CRITICAL - %s", msg);
475+ }
476+ } else {
477+ if (parser.status_code >= 600 || parser.status_code < 100) {
478+ die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%d)\n"), parser.status_code);
479 }
480 /* server errors result in a critical state */
481- else if (http_status >= 500) {
482- asprintf (&msg, _("%s - "), status_line);
483+ else if (parser.status_code >= 500) {
484 result = STATE_CRITICAL;
485 }
486 /* client errors result in a warning state */
487- else if (http_status >= 400) {
488- asprintf (&msg, _("%s - "), status_line);
489+ else if (parser.status_code >= 400) {
490 result = max_state_alt(STATE_WARNING, result);
491 }
492 /* check redirected page if specified */
493- else if (http_status >= 300) {
494-
495- if (onredirect == STATE_DEPENDENT)
496- redir (header, status_line);
497+ else if (parser.status_code >= 300) {
498+ if (onredirect == STATE_DEPENDENT) {
499+ if (parser_data.location)
500+ redir (parser_data.location);
501+ else die (STATE_CRITICAL, _("Redirect without Location header\n"));
502+ }
503 else
504 result = max_state_alt(onredirect, result);
505- asprintf (&msg, _("%s - "), status_line);
506- } /* end if (http_status >= 300) */
507- else {
508- /* Print OK status anyway */
509- asprintf (&msg, _("%s - "), status_line);
510 }
511-
512- } /* end else (server_expect_yn) */
513+ asprintf (&msg, _("%d - "), parser.status_code);
514+ }
515
516 /* reset the alarm - must be called *after* redir or we'll never die on redirects! */
517 alarm (0);
518@@ -1111,11 +1146,10 @@ check_http (void)
519 #define HD5 URI_PATH
520
521 void
522-redir (char *pos, char *status_line)
523+redir (char *pos)
524 {
525 int i = 0;
526 char *x;
527- char xx[2];
528 char type[6];
529 char *addr;
530 char *url;
531@@ -1124,41 +1158,11 @@ redir (char *pos, char *status_line)
532 if (addr == NULL)
533 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate addr\n"));
534
535- url = malloc (strcspn (pos, "\r\n"));
536+ url = malloc (strlen (pos) + 1);
537 if (url == NULL)
538 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
539
540- while (pos) {
541- sscanf (pos, "%1[Ll]%*1[Oo]%*1[Cc]%*1[Aa]%*1[Tt]%*1[Ii]%*1[Oo]%*1[Nn]:%n", xx, &i);
542- if (i == 0) {
543- pos += (size_t) strcspn (pos, "\r\n");
544- pos += (size_t) strspn (pos, "\r\n");
545- if (strlen(pos) == 0)
546- die (STATE_UNKNOWN,
547- _("HTTP UNKNOWN - Could not find redirect location - %s%s\n"),
548- status_line, (display_html ? "</A>" : ""));
549- continue;
550- }
551-
552- pos += i;
553- pos += strspn (pos, " \t");
554-
555- /*
556- * RFC 2616 (4.2): ``Header fields can be extended over multiple lines by
557- * preceding each extra line with at least one SP or HT.''
558- */
559- for (; (i = strspn (pos, "\r\n")); pos += i) {
560- pos += i;
561- if (!(i = strspn (pos, " \t"))) {
562- die (STATE_UNKNOWN, _("HTTP UNKNOWN - Empty redirect location%s\n"),
563- display_html ? "</A>" : "");
564- }
565- }
566-
567- url = realloc (url, strcspn (pos, "\r\n") + 1);
568- if (url == NULL)
569- die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
570-
571+ { /* dummy block to reduce patch diff */
572 /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
573 if (sscanf (pos, HD1, type, addr, &i, url) == 4) {
574 url = prepend_slash (url);
575@@ -1203,10 +1207,7 @@ redir (char *pos, char *status_line)
576 _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"),
577 pos, (display_html ? "</A>" : ""));
578 }
579-
580- break;
581-
582- } /* end while (pos) */
583+ }
584
585 if (++redir_depth > max_depth)
586 die (STATE_WARNING,
587@@ -1332,11 +1333,8 @@ print_help (void)
588 printf (" %s\n", _("(when this option is used the URL is not checked.)\n"));
589 #endif
590
591- printf (" %s\n", "-e, --expect=STRING");
592- printf (" %s\n", _("Comma-delimited list of strings, at least one of them is expected in"));
593- printf (" %s", _("the first (status) line of the server response (default: "));
594- printf ("%s)\n", HTTP_EXPECT);
595- printf (" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
596+ printf (" %s\n", "-e, --expect=INTEGER");
597+ printf (" %s\n", _("Expected HTTP status code, overriding the default logic"));
598 printf (" %s\n", "-s, --string=STRING");
599 printf (" %s\n", _("String to expect in the content"));
600 printf (" %s\n", "-u, --url=PATH");
601--
6021.7.2.5
603
604
605From a35b05d935f975478c90360ab56fb54d2d82e9c6 Mon Sep 17 00:00:00 2001
606From: Ferenc Wagner <wferi@niif.hu>
607Date: Wed, 2 Nov 2011 09:52:19 +0100
608Subject: [PATCH 4/9] check_http: whitespace change to fix up indentation by removing dummy block
609
610
611Signed-off-by: Ferenc Wagner <wferi@niif.hu>
612---
613 plugins/check_http.c | 76 ++++++++++++++++++++++++-------------------------
614 1 files changed, 37 insertions(+), 39 deletions(-)
615
616diff --git a/plugins/check_http.c b/plugins/check_http.c
617index ada7a95..3966ab4 100644
618--- a/plugins/check_http.c
619+++ b/plugins/check_http.c
620@@ -1162,51 +1162,49 @@ redir (char *pos)
621 if (url == NULL)
622 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
623
624- { /* dummy block to reduce patch diff */
625- /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
626- if (sscanf (pos, HD1, type, addr, &i, url) == 4) {
627- url = prepend_slash (url);
628- use_ssl = server_type_check (type);
629- }
630+ /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
631+ if (sscanf (pos, HD1, type, addr, &i, url) == 4) {
632+ url = prepend_slash (url);
633+ use_ssl = server_type_check (type);
634+ }
635
636- /* URI_HTTP URI_HOST URI_PATH */
637- else if (sscanf (pos, HD2, type, addr, url) == 3 ) {
638- url = prepend_slash (url);
639- use_ssl = server_type_check (type);
640- i = server_port_check (use_ssl);
641- }
642+ /* URI_HTTP URI_HOST URI_PATH */
643+ else if (sscanf (pos, HD2, type, addr, url) == 3 ) {
644+ url = prepend_slash (url);
645+ use_ssl = server_type_check (type);
646+ i = server_port_check (use_ssl);
647+ }
648
649- /* URI_HTTP URI_HOST URI_PORT */
650- else if (sscanf (pos, HD3, type, addr, &i) == 3) {
651- strcpy (url, HTTP_URL);
652- use_ssl = server_type_check (type);
653- }
654+ /* URI_HTTP URI_HOST URI_PORT */
655+ else if (sscanf (pos, HD3, type, addr, &i) == 3) {
656+ strcpy (url, HTTP_URL);
657+ use_ssl = server_type_check (type);
658+ }
659
660- /* URI_HTTP URI_HOST */
661- else if (sscanf (pos, HD4, type, addr) == 2) {
662- strcpy (url, HTTP_URL);
663- use_ssl = server_type_check (type);
664- i = server_port_check (use_ssl);
665- }
666+ /* URI_HTTP URI_HOST */
667+ else if (sscanf (pos, HD4, type, addr) == 2) {
668+ strcpy (url, HTTP_URL);
669+ use_ssl = server_type_check (type);
670+ i = server_port_check (use_ssl);
671+ }
672
673- /* URI_PATH */
674- else if (sscanf (pos, HD5, url) == 1) {
675- /* relative url */
676- if ((url[0] != '/')) {
677- if ((x = strrchr(server_url, '/')))
678- *x = '\0';
679- asprintf (&url, "%s/%s", server_url, url);
680- }
681- i = server_port;
682- strcpy (type, server_type);
683- strcpy (addr, host_name ? host_name : server_address);
684+ /* URI_PATH */
685+ else if (sscanf (pos, HD5, url) == 1) {
686+ /* relative url */
687+ if ((url[0] != '/')) {
688+ if ((x = strrchr(server_url, '/')))
689+ *x = '\0';
690+ asprintf (&url, "%s/%s", server_url, url);
691 }
692+ i = server_port;
693+ strcpy (type, server_type);
694+ strcpy (addr, host_name ? host_name : server_address);
695+ }
696
697- else {
698- die (STATE_UNKNOWN,
699- _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"),
700- pos, (display_html ? "</A>" : ""));
701- }
702+ else {
703+ die (STATE_UNKNOWN,
704+ _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"),
705+ pos, (display_html ? "</A>" : ""));
706 }
707
708 if (++redir_depth > max_depth)
709--
7101.7.2.5
711
712
713From 3f410b149eb7cd112466bbb147525c1d497adaa2 Mon Sep 17 00:00:00 2001
714From: Ferenc Wagner <wferi@niif.hu>
715Date: Mon, 31 Oct 2011 17:45:49 +0100
716Subject: [PATCH 5/9] check_http: constify and rename the location argument for redir()
717
718
719Signed-off-by: Ferenc Wagner <wferi@niif.hu>
720---
721 plugins/check_http.c | 18 +++++++++---------
722 1 files changed, 9 insertions(+), 9 deletions(-)
723
724diff --git a/plugins/check_http.c b/plugins/check_http.c
725index 3966ab4..c4586d5 100644
726--- a/plugins/check_http.c
727+++ b/plugins/check_http.c
728@@ -134,7 +134,7 @@ char buffer[MAX_INPUT_BUFFER];
729
730 int process_arguments (int, char **);
731 int check_http (void);
732-void redir (char *pos);
733+void redir (const char *location);
734 int server_type_check(const char *type);
735 int server_port_check(int ssl_flag);
736 char *perfd_time (double microsec);
737@@ -1146,7 +1146,7 @@ check_http (void)
738 #define HD5 URI_PATH
739
740 void
741-redir (char *pos)
742+redir (const char *location)
743 {
744 int i = 0;
745 char *x;
746@@ -1158,38 +1158,38 @@ redir (char *pos)
747 if (addr == NULL)
748 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate addr\n"));
749
750- url = malloc (strlen (pos) + 1);
751+ url = malloc (strlen (location) + 1);
752 if (url == NULL)
753 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
754
755 /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
756- if (sscanf (pos, HD1, type, addr, &i, url) == 4) {
757+ if (sscanf (location, HD1, type, addr, &i, url) == 4) {
758 url = prepend_slash (url);
759 use_ssl = server_type_check (type);
760 }
761
762 /* URI_HTTP URI_HOST URI_PATH */
763- else if (sscanf (pos, HD2, type, addr, url) == 3 ) {
764+ else if (sscanf (location, HD2, type, addr, url) == 3 ) {
765 url = prepend_slash (url);
766 use_ssl = server_type_check (type);
767 i = server_port_check (use_ssl);
768 }
769
770 /* URI_HTTP URI_HOST URI_PORT */
771- else if (sscanf (pos, HD3, type, addr, &i) == 3) {
772+ else if (sscanf (location, HD3, type, addr, &i) == 3) {
773 strcpy (url, HTTP_URL);
774 use_ssl = server_type_check (type);
775 }
776
777 /* URI_HTTP URI_HOST */
778- else if (sscanf (pos, HD4, type, addr) == 2) {
779+ else if (sscanf (location, HD4, type, addr) == 2) {
780 strcpy (url, HTTP_URL);
781 use_ssl = server_type_check (type);
782 i = server_port_check (use_ssl);
783 }
784
785 /* URI_PATH */
786- else if (sscanf (pos, HD5, url) == 1) {
787+ else if (sscanf (location, HD5, url) == 1) {
788 /* relative url */
789 if ((url[0] != '/')) {
790 if ((x = strrchr(server_url, '/')))
791@@ -1204,7 +1204,7 @@ redir (char *pos)
792 else {
793 die (STATE_UNKNOWN,
794 _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"),
795- pos, (display_html ? "</A>" : ""));
796+ location, (display_html ? "</A>" : ""));
797 }
798
799 if (++redir_depth > max_depth)
800--
8011.7.2.5
802
803
804From d1b806941bf6bf94754e86e832a11eabc003a656 Mon Sep 17 00:00:00 2001
805From: Ferenc Wagner <wferi@niif.hu>
806Date: Mon, 31 Oct 2011 17:47:47 +0100
807Subject: [PATCH 6/9] check_http: make list of parsed headers configurable
808
809
810Signed-off-by: Ferenc Wagner <wferi@niif.hu>
811---
812 plugins/check_http.c | 58 +++++++++++++++++++++++++++++++++++++++----------
813 1 files changed, 46 insertions(+), 12 deletions(-)
814
815diff --git a/plugins/check_http.c b/plugins/check_http.c
816index c4586d5..5466e06 100644
817--- a/plugins/check_http.c
818+++ b/plugins/check_http.c
819@@ -49,13 +49,17 @@ const char *email = "nagiosplug-devel@lists.sourceforge.net";
820 #define STICKY_HOST 1
821 #define STICKY_PORT 2
822
823+struct header_data_t {
824+ const char *field;
825+ char *value;
826+};
827+
828 struct parser_data_t {
829 enum http_errno prev_callback; /* use HPE_CB_ macros for identifying callbacks */
830- char *current_header;
831- size_t current_header_length;
832- int parsing_location;
833- char *location;
834- size_t location_length;
835+ char *current_field;
836+ size_t current_length;
837+ struct header_data_t *current_header;
838+ struct header_data_t *headers;
839 };
840
841 enum {
842@@ -758,6 +762,17 @@ prepend_slash (char *path)
843 return newpath;
844 }
845
846+const char *
847+get_value (const struct header_data_t *header, const char *field)
848+{
849+ while (header->field) {
850+ if (!strcasecmp (header->field, field))
851+ return header->value;
852+ header++;
853+ }
854+ return 0;
855+}
856+
857 /*
858 Returns 0 on success, 1 if allocation fails.
859 Works on binary data, but also zero-terminates the result
860@@ -781,13 +796,13 @@ header_field_callback (http_parser *parser, const char *at, size_t length)
861
862 switch (data->prev_callback) {
863 case HPE_CB_header_value:
864- data->current_header_length = 0;
865+ data->current_length = 0;
866 /* fall through */
867 case 0:
868 data->prev_callback = HPE_CB_header_field;
869 /* fall through */
870 case HPE_CB_header_field:
871- return append (&data->current_header, &data->current_header_length, at, length);
872+ return append (&data->current_field, &data->current_length, at, length);
873 default:
874 return 1;
875 }
876@@ -797,15 +812,23 @@ int
877 header_value_callback (http_parser *parser, const char *at, size_t length)
878 {
879 struct parser_data_t *data = parser->data;
880+ struct header_data_t *header;
881
882 switch (data->prev_callback) {
883 case HPE_CB_header_field:
884- data->parsing_location = !strcasecmp (data->current_header, "location");
885+ data->current_header = 0;
886+ data->current_length = 0;
887+ for (header = data->headers; header->field; header++)
888+ if (!strcasecmp (data->current_field, header->field)) {
889+ data->current_header = header;
890+ break;
891+ }
892 data->prev_callback = HPE_CB_header_value;
893 /* fall through */
894 case HPE_CB_header_value:
895- return data->parsing_location &&
896- append (&data->location, &data->location_length, at, length);
897+ return data->current_header &&
898+ append (&(data->current_header->value),
899+ &data->current_length, at, length);
900 default:
901 return 1;
902 }
903@@ -816,6 +839,13 @@ headers_complete_callback (http_parser *parser)
904 {
905 struct parser_data_t *data = parser->data;
906
907+ if (verbose) {
908+ const struct header_data_t *header;
909+ printf ("Parsed headers:\n");
910+ for (header = data->headers; header->field; header++)
911+ printf ("%s: %s\n", header->field, header->value);
912+ }
913+
914 data->prev_callback = HPE_CB_headers_complete;
915
916 if (no_body) /* Terminate parsing (thus reading) if the -N option is set */
917@@ -843,6 +873,8 @@ check_http (void)
918 http_parser_settings settings;
919 http_parser parser;
920 struct parser_data_t parser_data;
921+ struct header_data_t interesting_headers[] =
922+ {{"location", 0}, {"date", 0}, {"last-modified", 0}, {0, 0}};
923
924 /* try to connect to the host at the given port number */
925 if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
926@@ -923,6 +955,7 @@ check_http (void)
927 /* Initialize the HTTP parser */
928 http_parser_init (&parser, HTTP_RESPONSE);
929 memset (&parser_data, 0, sizeof parser_data);
930+ parser_data.headers = interesting_headers;
931 parser.data = &parser_data;
932 memset (&settings, 0, sizeof settings);
933 settings.on_header_field = header_field_callback;
934@@ -1043,8 +1076,9 @@ check_http (void)
935 /* check redirected page if specified */
936 else if (parser.status_code >= 300) {
937 if (onredirect == STATE_DEPENDENT) {
938- if (parser_data.location)
939- redir (parser_data.location);
940+ const char *location = get_value (parser_data.headers, "location");
941+ if (location)
942+ redir (location);
943 else die (STATE_CRITICAL, _("Redirect without Location header\n"));
944 }
945 else
946--
9471.7.2.5
948
949
950From 62e8868bb24c2161ccb7748dba82c6a90618aac3 Mon Sep 17 00:00:00 2001
951From: Ferenc Wagner <wferi@niif.hu>
952Date: Mon, 31 Oct 2011 17:57:11 +0100
953Subject: [PATCH 7/9] check_http: use header parsing machinery in check_document_dates()
954
955
956Signed-off-by: Ferenc Wagner <wferi@niif.hu>
957---
958 plugins/check_http.c | 61 +++----------------------------------------------
959 1 files changed, 4 insertions(+), 57 deletions(-)
960
961diff --git a/plugins/check_http.c b/plugins/check_http.c
962index 5466e06..423bb22 100644
963--- a/plugins/check_http.c
964+++ b/plugins/check_http.c
965@@ -600,63 +600,10 @@ parse_time_string (const char *string)
966 }
967
968 static int
969-check_document_dates (const char *headers, char **msg)
970+check_document_dates (const char *server_date, const char *document_date, char **msg)
971 {
972- const char *s;
973- char *server_date = 0;
974- char *document_date = 0;
975 int date_result = STATE_OK;
976
977- s = headers;
978- while (*s) {
979- const char *field = s;
980- const char *value = 0;
981-
982- /* Find the end of the header field */
983- while (*s && !isspace(*s) && *s != ':')
984- s++;
985-
986- /* Remember the header value, if any. */
987- if (*s == ':')
988- value = ++s;
989-
990- /* Skip to the end of the header, including continuation lines. */
991- while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
992- s++;
993-
994- /* Avoid stepping over end-of-string marker */
995- if (*s)
996- s++;
997-
998- /* Process this header. */
999- if (value && value > field+2) {
1000- char *ff = (char *) malloc (value-field);
1001- char *ss = ff;
1002- while (field < value-1)
1003- *ss++ = tolower(*field++);
1004- *ss++ = 0;
1005-
1006- if (!strcmp (ff, "date") || !strcmp (ff, "last-modified")) {
1007- const char *e;
1008- while (*value && isspace (*value))
1009- value++;
1010- for (e = value; *e && *e != '\r' && *e != '\n'; e++)
1011- ;
1012- ss = (char *) malloc (e - value + 1);
1013- strncpy (ss, value, e - value);
1014- ss[e - value] = 0;
1015- if (!strcmp (ff, "date")) {
1016- if (server_date) free (server_date);
1017- server_date = ss;
1018- } else {
1019- if (document_date) free (document_date);
1020- document_date = ss;
1021- }
1022- }
1023- free (ff);
1024- }
1025- }
1026-
1027 /* Done parsing the body. Now check the dates we (hopefully) parsed. */
1028 if (!server_date || !*server_date) {
1029 asprintf (msg, _("%sServer date unknown, "), *msg);
1030@@ -687,8 +634,6 @@ check_document_dates (const char *headers, char **msg)
1031 date_result = max_state_alt(STATE_CRITICAL, date_result);
1032 }
1033 }
1034- free (server_date);
1035- free (document_date);
1036 }
1037 return date_result;
1038 }
1039@@ -1091,7 +1036,9 @@ check_http (void)
1040 alarm (0);
1041
1042 if (maximum_age >= 0) {
1043- result = max_state_alt(check_document_dates(header, &msg), result);
1044+ result = max_state_alt(check_document_dates(get_value (parser_data.headers, "date"),
1045+ get_value (parser_data.headers, "last-modified"), &msg),
1046+ result);
1047 }
1048
1049 /* Page and Header content checks go here */
1050--
10511.7.2.5
1052
1053
1054From efe4e949ae4ba64f333f402d0f4b54f07b18164c Mon Sep 17 00:00:00 2001
1055From: Ferenc Wagner <wferi@niif.hu>
1056Date: Tue, 1 Nov 2011 16:17:00 +0100
1057Subject: [PATCH 8/9] check_http: also read the response content via http-parse
1058
1059This gets rid of good a bunch of code, and also gives free decoding of
1060Transfer-Encoding: chunked, which all HTTP/1.1 clients must support.
1061
1062Signed-off-by: Ferenc Wagner <wferi@niif.hu>
1063---
1064 plugins/check_http.c | 86 ++++++++++++-------------------------------------
1065 1 files changed, 21 insertions(+), 65 deletions(-)
1066
1067diff --git a/plugins/check_http.c b/plugins/check_http.c
1068index 423bb22..deea38c 100644
1069--- a/plugins/check_http.c
1070+++ b/plugins/check_http.c
1071@@ -60,6 +60,7 @@ struct parser_data_t {
1072 size_t current_length;
1073 struct header_data_t *current_header;
1074 struct header_data_t *headers;
1075+ char *content;
1076 };
1077
1078 enum {
1079@@ -488,26 +489,6 @@ process_arguments (int argc, char **argv)
1080 return TRUE;
1081 }
1082
1083-
1084-
1085-/* Returns 1 if we're done processing the document body; 0 to keep going */
1086-static int
1087-document_headers_done (char *full_page)
1088-{
1089- const char *body;
1090-
1091- for (body = full_page; *body; body++) {
1092- if (!strncmp (body, "\n\n", 2) || !strncmp (body, "\n\r\n", 3))
1093- break;
1094- }
1095-
1096- if (!*body)
1097- return 0; /* haven't read end of headers yet */
1098-
1099- full_page[body - full_page] = 0;
1100- return 1;
1101-}
1102-
1103 static time_t
1104 parse_time_string (const char *string)
1105 {
1106@@ -792,6 +773,7 @@ headers_complete_callback (http_parser *parser)
1107 }
1108
1109 data->prev_callback = HPE_CB_headers_complete;
1110+ data->current_length = 0; /* prepare for the body */
1111
1112 if (no_body) /* Terminate parsing (thus reading) if the -N option is set */
1113 return 2; /* 1 means don't expect body in this callback */
1114@@ -799,16 +781,20 @@ headers_complete_callback (http_parser *parser)
1115 }
1116
1117 int
1118+body_callback (http_parser *parser, const char *at, size_t length)
1119+{
1120+ struct parser_data_t *data = parser->data;
1121+
1122+ return append (&data->content, &data->current_length, at, length);
1123+}
1124+
1125+int
1126 check_http (void)
1127 {
1128 char *msg;
1129- char *header;
1130- char *page;
1131 char *auth;
1132 int i = 0;
1133 size_t pagesize = 0;
1134- char *full_page;
1135- char *full_page_new;
1136 char *buf;
1137 char *pos;
1138 long microsec;
1139@@ -906,31 +892,19 @@ check_http (void)
1140 settings.on_header_field = header_field_callback;
1141 settings.on_header_value = header_value_callback;
1142 settings.on_headers_complete = headers_complete_callback;
1143+ settings.on_body = body_callback;
1144
1145 /* fetch the page */
1146- full_page = strdup("");
1147 while ((i = my_recv (buffer, MAX_INPUT_BUFFER-1)) >= 0) {
1148 int nparsed = http_parser_execute(&parser, &settings, buffer, i);
1149+ pagesize += i;
1150 if (nparsed != i) {
1151 enum http_errno code = HTTP_PARSER_ERRNO (&parser);
1152- if (code == HPE_CB_headers_complete) { /* the -N check fired */
1153- /* break; FIXME this would break the current header code */
1154- } else {
1155- printf ("http_parser_execute returned %d instead of %i: %s\n",
1156- nparsed, i, http_errno_description (code));
1157- }
1158+ if (code == HPE_CB_headers_complete) break; /* the -N check fired */
1159+ else die (STATE_CRITICAL, _("HTTP CRITICAL - error parsing response: %s"),
1160+ http_errno_description (code));
1161 }
1162 if (i == 0) break;
1163- buffer[i] = '\0';
1164- asprintf (&full_page_new, "%s%s", full_page, buffer);
1165- free (full_page);
1166- full_page = full_page_new;
1167- pagesize += i;
1168-
1169- if (no_body && document_headers_done (full_page)) {
1170- i = 0;
1171- break;
1172- }
1173 }
1174
1175 if (i < 0 && errno != ECONNRESET) {
1176@@ -969,34 +943,16 @@ check_http (void)
1177 microsec = deltime (tv);
1178 elapsed_time = (double)microsec / 1.0e6;
1179
1180- /* leave full_page untouched so we can free it later */
1181- page = full_page;
1182-
1183 if (verbose && !no_body)
1184 printf ("%s://%s:%d%s is %d characters\n",
1185 use_ssl ? "https" : "http", server_address,
1186 server_port, server_url, (int)pagesize);
1187
1188- /* skip status line */
1189- page += (size_t) strcspn (page, "\r\n");
1190- page += (size_t) strspn (page, "\r\n");
1191-
1192- /* find header info and null-terminate it */
1193- header = page;
1194- while (strcspn (page, "\r\n") > 0) {
1195- page += (size_t) strcspn (page, "\r\n");
1196- pos = page;
1197- if ((strspn (page, "\r") == 1 && strspn (page, "\r\n") >= 2) ||
1198- (strspn (page, "\n") == 1 && strspn (page, "\r\n") >= 2))
1199- page += (size_t) 2;
1200- else
1201- page += (size_t) 1;
1202+ if (verbose && !no_body) {
1203+ puts ("**** CONTENT ****");
1204+ fwrite (parser_data.content, parser_data.current_length, 1, stdout);
1205+ putchar ('\n');
1206 }
1207- page += (size_t) strspn (page, "\r\n");
1208- header[pos - header] = 0;
1209- if (verbose)
1210- printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header,
1211- (no_body ? " [[ skipped ]]" : page));
1212
1213 if (status_expect != -1) {
1214 if (parser.status_code == status_expect)
1215@@ -1044,7 +1000,7 @@ check_http (void)
1216 /* Page and Header content checks go here */
1217
1218 if (strlen (string_expect)) {
1219- if (!strstr (page, string_expect)) {
1220+ if (!strstr (parser_data.content, string_expect)) {
1221 strncpy(&output_string_search[0],string_expect,sizeof(output_string_search));
1222 if(output_string_search[sizeof(output_string_search)-1]!='\0') {
1223 bcopy("...",&output_string_search[sizeof(output_string_search)-4],4);
1224@@ -1055,7 +1011,7 @@ check_http (void)
1225 }
1226
1227 if (strlen (regexp)) {
1228- errcode = regexec (&preg, page, REGS, pmatch, 0);
1229+ errcode = regexec (&preg, parser_data.content, REGS, pmatch, 0);
1230 if ((errcode == 0 && invert_regex == 0) || (errcode == REG_NOMATCH && invert_regex == 1)) {
1231 /* OK - No-op to avoid changing the logic around it */
1232 result = max_state_alt(STATE_OK, result);
1233--
12341.7.2.5
1235
1236
1237From 256d8d15acf98ee405f79b75a52692531d173f49 Mon Sep 17 00:00:00 2001
1238From: Ferenc Wagner <wferi@niif.hu>
1239Date: Wed, 2 Nov 2011 07:57:30 +0100
1240Subject: [PATCH 9/9] check_http: check content length instead of response length
1241
1242The content length does not depend on the transfer encoding and may
1243be possible to derive without fetching the entire body (cf. -N option).
1244
1245Signed-off-by: Ferenc Wagner <wferi@niif.hu>
1246---
1247 plugins/check_http.c | 93 +++++++++++---------------------------------------
1248 1 files changed, 20 insertions(+), 73 deletions(-)
1249
1250diff --git a/plugins/check_http.c b/plugins/check_http.c
1251index deea38c..27f5cd3 100644
1252--- a/plugins/check_http.c
1253+++ b/plugins/check_http.c
1254@@ -619,59 +619,6 @@ check_document_dates (const char *server_date, const char *document_date, char *
1255 return date_result;
1256 }
1257
1258-int
1259-get_content_length (const char *headers)
1260-{
1261- const char *s;
1262- int content_length = 0;
1263-
1264- s = headers;
1265- while (*s) {
1266- const char *field = s;
1267- const char *value = 0;
1268-
1269- /* Find the end of the header field */
1270- while (*s && !isspace(*s) && *s != ':')
1271- s++;
1272-
1273- /* Remember the header value, if any. */
1274- if (*s == ':')
1275- value = ++s;
1276-
1277- /* Skip to the end of the header, including continuation lines. */
1278- while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
1279- s++;
1280-
1281- /* Avoid stepping over end-of-string marker */
1282- if (*s)
1283- s++;
1284-
1285- /* Process this header. */
1286- if (value && value > field+2) {
1287- char *ff = (char *) malloc (value-field);
1288- char *ss = ff;
1289- while (field < value-1)
1290- *ss++ = tolower(*field++);
1291- *ss++ = 0;
1292-
1293- if (!strcmp (ff, "content-length")) {
1294- const char *e;
1295- while (*value && isspace (*value))
1296- value++;
1297- for (e = value; *e && *e != '\r' && *e != '\n'; e++)
1298- ;
1299- ss = (char *) malloc (e - value + 1);
1300- strncpy (ss, value, e - value);
1301- ss[e - value] = 0;
1302- content_length = atoi(ss);
1303- free (ss);
1304- }
1305- free (ff);
1306- }
1307- }
1308- return (content_length);
1309-}
1310-
1311 char *
1312 prepend_slash (char *path)
1313 {
1314@@ -799,13 +746,13 @@ check_http (void)
1315 char *pos;
1316 long microsec;
1317 double elapsed_time;
1318- int page_len = 0;
1319+ int page_len = -1;
1320 int result = STATE_OK;
1321 http_parser_settings settings;
1322 http_parser parser;
1323 struct parser_data_t parser_data;
1324 struct header_data_t interesting_headers[] =
1325- {{"location", 0}, {"date", 0}, {"last-modified", 0}, {0, 0}};
1326+ {{"location", 0}, {"date", 0}, {"last-modified", 0}, {"content-length", 0}, {0, 0}};
1327
1328 /* try to connect to the host at the given port number */
1329 if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
1330@@ -1031,21 +978,21 @@ check_http (void)
1331 }
1332 }
1333
1334- /* make sure the page is of an appropriate size */
1335- /* page_len = get_content_length(header); */
1336- /* FIXME: Will this work with -N ? IMHO we should use
1337- * get_content_length(header) and always check if it's different than the
1338- * returned pagesize
1339- */
1340- /* FIXME: IIRC pagesize returns headers - shouldn't we make
1341- * it == get_content_length(header) ??
1342- */
1343- page_len = pagesize;
1344- if ((max_page_len > 0) && (page_len > max_page_len)) {
1345- asprintf (&msg, _("%spage size %d too large, "), msg, page_len);
1346- result = max_state_alt(STATE_WARNING, result);
1347- } else if ((min_page_len > 0) && (page_len < min_page_len)) {
1348- asprintf (&msg, _("%spage size %d too small, "), msg, page_len);
1349+ /* make sure the content is of an appropriate size */
1350+ if (no_body) {
1351+ const char *content_length = get_value (parser_data.headers, "content-length");
1352+ if (content_length) page_len = atol (content_length);
1353+ } else page_len = parser_data.current_length;
1354+ if (page_len != -1) {
1355+ if ((max_page_len > 0) && (page_len > max_page_len)) {
1356+ asprintf (&msg, _("%spage size %d too large, "), msg, page_len);
1357+ result = max_state_alt(STATE_WARNING, result);
1358+ } else if ((min_page_len > 0) && (page_len < min_page_len)) {
1359+ asprintf (&msg, _("%spage size %d too small, "), msg, page_len);
1360+ result = max_state_alt(STATE_WARNING, result);
1361+ }
1362+ } else if (max_page_len > 0 || min_page_len > 0) {
1363+ asprintf (&msg, _("%spage size unknown, "), msg);
1364 result = max_state_alt(STATE_WARNING, result);
1365 }
1366
1367@@ -1058,7 +1005,7 @@ check_http (void)
1368 /* check elapsed time */
1369 asprintf (&msg,
1370 _("%s - %d bytes in %.3f second response time %s|%s %s"),
1371- msg, page_len, elapsed_time,
1372+ msg, pagesize, elapsed_time,
1373 (display_html ? "</A>" : ""),
1374 perfd_time (elapsed_time), perfd_size (page_len));
1375
1376@@ -1310,7 +1257,7 @@ print_help (void)
1377 printf (" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the"));
1378 printf (" %s\n", _("specified IP address. stickyport also ensures port stays the same."));
1379 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
1380- printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
1381+ printf (" %s\n", _("Minimum content size required (bytes) : Maximum content size required (bytes)"));
1382
1383 printf (UT_WARN_CRIT);
1384
1385@@ -1361,7 +1308,7 @@ print_usage (void)
1386 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-a auth]\n");
1387 printf (" [-b proxy_auth] [-f <ok|warning|critcal|follow|sticky|stickyport>]\n");
1388 printf (" [-e <expect>] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n");
1389- printf (" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n");
1390+ printf (" [-P string] [-m <min_cnt_size>:<max_cnt_size>] [-4|-6] [-N] [-M <age>]\n");
1391 printf (" [-A string] [-k string] [-S] [--sni] [-C <age>] [-T <content-type>]\n");
1392 printf (" [-j method]\n");
1393 }
1394--
13951.7.2.5
1396