summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins/check_curl.c133
-rwxr-xr-xplugins/tests/check_curl.t8
2 files changed, 103 insertions, 38 deletions
diff --git a/plugins/check_curl.c b/plugins/check_curl.c
index 103937c9..5d3df9ee 100644
--- a/plugins/check_curl.c
+++ b/plugins/check_curl.c
@@ -67,7 +67,14 @@ typedef struct {
67 char *buf; 67 char *buf;
68 size_t buflen; 68 size_t buflen;
69 size_t bufsize; 69 size_t bufsize;
70} curlhelp_curlbuf; 70} curlhelp_write_curlbuf;
71
72/* for buffering the data sent in PUT */
73typedef struct {
74 char *buf;
75 size_t buflen;
76 off_t pos;
77} curlhelp_read_curlbuf;
71 78
72/* for parsing the HTTP status line */ 79/* for parsing the HTTP status line */
73typedef struct { 80typedef struct {
@@ -115,9 +122,10 @@ char *http_post_data = NULL;
115char *http_content_type = NULL; 122char *http_content_type = NULL;
116CURL *curl; 123CURL *curl;
117struct curl_slist *header_list = NULL; 124struct curl_slist *header_list = NULL;
118curlhelp_curlbuf body_buf; 125curlhelp_write_curlbuf body_buf;
119curlhelp_curlbuf header_buf; 126curlhelp_write_curlbuf header_buf;
120curlhelp_statusline status_line; 127curlhelp_statusline status_line;
128curlhelp_read_curlbuf put_buf;
121char http_header[DEFAULT_BUFFER_SIZE]; 129char http_header[DEFAULT_BUFFER_SIZE];
122long code; 130long code;
123long socket_timeout = DEFAULT_SOCKET_TIMEOUT; 131long socket_timeout = DEFAULT_SOCKET_TIMEOUT;
@@ -155,16 +163,19 @@ int check_http (void);
155void print_help (void); 163void print_help (void);
156void print_usage (void); 164void print_usage (void);
157void print_curl_version (void); 165void print_curl_version (void);
158int curlhelp_initbuffer (curlhelp_curlbuf*); 166int curlhelp_initwritebuffer (curlhelp_write_curlbuf*);
159int curlhelp_buffer_callback (void*, size_t , size_t , void*); 167int curlhelp_buffer_write_callback (void*, size_t , size_t , void*);
160void curlhelp_freebuffer (curlhelp_curlbuf*); 168void curlhelp_freewritebuffer (curlhelp_write_curlbuf*);
169int curlhelp_initreadbuffer (curlhelp_read_curlbuf *, const char *, size_t);
170int curlhelp_buffer_read_callback (void *, size_t , size_t , void *);
171void curlhelp_freereadbuffer (curlhelp_read_curlbuf *);
161 172
162int curlhelp_parse_statusline (const char*, curlhelp_statusline *); 173int curlhelp_parse_statusline (const char*, curlhelp_statusline *);
163void curlhelp_free_statusline (curlhelp_statusline *); 174void curlhelp_free_statusline (curlhelp_statusline *);
164char *perfd_time_ssl (double microsec); 175char *perfd_time_ssl (double microsec);
165char *get_header_value (const struct phr_header* headers, const size_t nof_headers, const char* header); 176char *get_header_value (const struct phr_header* headers, const size_t nof_headers, const char* header);
166static time_t parse_time_string (const char *string); 177static time_t parse_time_string (const char *string);
167int check_document_dates (const curlhelp_curlbuf *, char (*msg)[DEFAULT_BUFFER_SIZE]); 178int check_document_dates (const curlhelp_write_curlbuf *, char (*msg)[DEFAULT_BUFFER_SIZE]);
168 179
169void remove_newlines (char *); 180void remove_newlines (char *);
170void test_file (char *); 181void test_file (char *);
@@ -251,15 +262,15 @@ check_http (void)
251 curl_easy_setopt(curl, CURLOPT_STDERR, stdout); 262 curl_easy_setopt(curl, CURLOPT_STDERR, stdout);
252 263
253 /* initialize buffer for body of the answer */ 264 /* initialize buffer for body of the answer */
254 if (curlhelp_initbuffer(&body_buf) < 0) 265 if (curlhelp_initwritebuffer(&body_buf) < 0)
255 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n"); 266 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n");
256 curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)curlhelp_buffer_callback); 267 curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback);
257 curl_easy_setopt (curl, CURLOPT_WRITEDATA, (void *)&body_buf); 268 curl_easy_setopt (curl, CURLOPT_WRITEDATA, (void *)&body_buf);
258 269
259 /* initialize buffer for header of the answer */ 270 /* initialize buffer for header of the answer */
260 if (curlhelp_initbuffer( &header_buf ) < 0) 271 if (curlhelp_initwritebuffer( &header_buf ) < 0)
261 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n" ); 272 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n" );
262 curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)curlhelp_buffer_callback); 273 curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback);
263 curl_easy_setopt (curl, CURLOPT_WRITEHEADER, (void *)&header_buf); 274 curl_easy_setopt (curl, CURLOPT_WRITEHEADER, (void *)&header_buf);
264 275
265 /* set the error buffer */ 276 /* set the error buffer */
@@ -282,7 +293,11 @@ check_http (void)
282 if (!strcmp(http_method, "POST")) 293 if (!strcmp(http_method, "POST"))
283 curl_easy_setopt (curl, CURLOPT_POST, 1); 294 curl_easy_setopt (curl, CURLOPT_POST, 1);
284 else if (!strcmp(http_method, "PUT")) 295 else if (!strcmp(http_method, "PUT"))
296#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 12, 1)
297 curl_easy_setopt (curl, CURLOPT_UPLOAD, 1);
298#else
285 curl_easy_setopt (curl, CURLOPT_PUT, 1); 299 curl_easy_setopt (curl, CURLOPT_PUT, 1);
300#endif
286 else 301 else
287 curl_easy_setopt (curl, CURLOPT_CUSTOMREQUEST, http_method); 302 curl_easy_setopt (curl, CURLOPT_CUSTOMREQUEST, http_method);
288 } 303 }
@@ -385,12 +400,25 @@ check_http (void)
385 curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6); 400 curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
386 401
387 /* either send http POST data (any data, not only POST)*/ 402 /* either send http POST data (any data, not only POST)*/
388 if (http_post_data) { 403 if (!strcmp(http_method, "POST") ||!strcmp(http_method, "PUT")) {
404 /* set content of payload for POST and PUT */
389 if (http_content_type) { 405 if (http_content_type) {
390 snprintf (http_header, DEFAULT_BUFFER_SIZE, "Content-Type: %s", http_content_type); 406 snprintf (http_header, DEFAULT_BUFFER_SIZE, "Content-Type: %s", http_content_type);
391 header_list = curl_slist_append (header_list, http_header); 407 header_list = curl_slist_append (header_list, http_header);
392 } 408 }
393 curl_easy_setopt (curl, CURLOPT_POSTFIELDS, http_post_data); 409 /* NULL indicates "HTTP Continue" in libcurl, provide an empty string
410 * in case of no POST/PUT data */
411 if (!http_post_data)
412 http_post_data = "";
413 if (!strcmp(http_method, "POST")) {
414 /* POST method, set payload with CURLOPT_POSTFIELDS */
415 curl_easy_setopt (curl, CURLOPT_POSTFIELDS, http_post_data);
416 } else if (!strcmp(http_method, "PUT")) {
417 curl_easy_setopt (curl, CURLOPT_READFUNCTION, (curl_read_callback)curlhelp_buffer_read_callback);
418 curlhelp_initreadbuffer (&put_buf, http_post_data, strlen (http_post_data));
419 curl_easy_setopt (curl, CURLOPT_READDATA, (void *)&put_buf);
420 curl_easy_setopt (curl, CURLOPT_INFILESIZE, (curl_off_t)strlen (http_post_data));
421 }
394 } 422 }
395 423
396 /* do the request */ 424 /* do the request */
@@ -472,13 +500,13 @@ check_http (void)
472 } 500 }
473 501
474 /* make sure the status line matches the response we are looking for */ 502 /* make sure the status line matches the response we are looking for */
475 if (!expected_statuscode(header_buf.buf, server_expect)) { 503 if (!expected_statuscode(status_line.first_line, server_expect)) {
476 /* TODO: fix first_line being cut off */ 504 /* TODO: fix first_line being cut off */
477 if (server_port == HTTP_PORT) 505 if (server_port == HTTP_PORT)
478 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host: %s\n"), status_line.first_line); 506 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host: %s\n"), status_line.first_line);
479 else 507 else
480 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host on port %d: %s\n"), server_port, status_line.first_line); 508 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host on port %d: %s\n"), server_port, status_line.first_line);
481 die (STATE_CRITICAL, "HTTP CRITICAL - %s", msg); 509 die (STATE_CRITICAL, "HTTP CRITICAL - %s", msg);
482 } 510 }
483 511
484 /* TODO: implement -d header tests */ 512 /* TODO: implement -d header tests */
@@ -604,8 +632,11 @@ check_http (void)
604 curlhelp_free_statusline(&status_line); 632 curlhelp_free_statusline(&status_line);
605 curl_easy_cleanup (curl); 633 curl_easy_cleanup (curl);
606 curl_global_cleanup (); 634 curl_global_cleanup ();
607 curlhelp_freebuffer(&body_buf); 635 curlhelp_freewritebuffer(&body_buf);
608 curlhelp_freebuffer(&header_buf); 636 curlhelp_freewritebuffer(&header_buf);
637 if (!strcmp (http_method, "PUT")) {
638 curlhelp_freereadbuffer (&put_buf);
639 }
609 640
610 return result; 641 return result;
611} 642}
@@ -1250,7 +1281,7 @@ print_curl_version (void)
1250} 1281}
1251 1282
1252int 1283int
1253curlhelp_initbuffer (curlhelp_curlbuf *buf) 1284curlhelp_initwritebuffer (curlhelp_write_curlbuf *buf)
1254{ 1285{
1255 buf->bufsize = DEFAULT_BUFFER_SIZE; 1286 buf->bufsize = DEFAULT_BUFFER_SIZE;
1256 buf->buflen = 0; 1287 buf->buflen = 0;
@@ -1260,9 +1291,9 @@ curlhelp_initbuffer (curlhelp_curlbuf *buf)
1260} 1291}
1261 1292
1262int 1293int
1263curlhelp_buffer_callback (void *buffer, size_t size, size_t nmemb, void *stream) 1294curlhelp_buffer_write_callback (void *buffer, size_t size, size_t nmemb, void *stream)
1264{ 1295{
1265 curlhelp_curlbuf *buf = (curlhelp_curlbuf *)stream; 1296 curlhelp_write_curlbuf *buf = (curlhelp_write_curlbuf *)stream;
1266 1297
1267 while (buf->bufsize < buf->buflen + size * nmemb + 1) { 1298 while (buf->bufsize < buf->buflen + size * nmemb + 1) {
1268 buf->bufsize *= buf->bufsize * 2; 1299 buf->bufsize *= buf->bufsize * 2;
@@ -1277,8 +1308,39 @@ curlhelp_buffer_callback (void *buffer, size_t size, size_t nmemb, void *stream)
1277 return (int)(size * nmemb); 1308 return (int)(size * nmemb);
1278} 1309}
1279 1310
1311int
1312curlhelp_buffer_read_callback (void *buffer, size_t size, size_t nmemb, void *stream)
1313{
1314 curlhelp_read_curlbuf *buf = (curlhelp_read_curlbuf *)stream;
1315
1316 size_t n = min (nmemb * size, buf->buflen - buf->pos);
1317
1318 memcpy (buffer, buf->buf + buf->pos, n);
1319 buf->pos += n;
1320
1321 return (int)n;
1322}
1323
1280void 1324void
1281curlhelp_freebuffer (curlhelp_curlbuf *buf) 1325curlhelp_freewritebuffer (curlhelp_write_curlbuf *buf)
1326{
1327 free (buf->buf);
1328 buf->buf = NULL;
1329}
1330
1331int
1332curlhelp_initreadbuffer (curlhelp_read_curlbuf *buf, const char *data, size_t datalen)
1333{
1334 buf->buflen = datalen;
1335 buf->buf = (char *)malloc ((size_t)buf->buflen);
1336 if (buf->buf == NULL) return -1;
1337 memcpy (buf->buf, data, datalen);
1338 buf->pos = 0;
1339 return 0;
1340}
1341
1342void
1343curlhelp_freereadbuffer (curlhelp_read_curlbuf *buf)
1282{ 1344{
1283 free (buf->buf); 1345 free (buf->buf);
1284 buf->buf = NULL; 1346 buf->buf = NULL;
@@ -1328,6 +1390,7 @@ curlhelp_parse_statusline (const char *buf, curlhelp_statusline *status_line)
1328 size_t first_line_len; 1390 size_t first_line_len;
1329 char *pp; 1391 char *pp;
1330 const char *start; 1392 const char *start;
1393 char *first_line_buf;
1331 1394
1332 /* find last start of a new header */ 1395 /* find last start of a new header */
1333 start = strrstr2 (buf, "\r\nHTTP"); 1396 start = strrstr2 (buf, "\r\nHTTP");
@@ -1344,47 +1407,49 @@ curlhelp_parse_statusline (const char *buf, curlhelp_statusline *status_line)
1344 if (status_line->first_line == NULL) return -1; 1407 if (status_line->first_line == NULL) return -1;
1345 memcpy (status_line->first_line, buf, first_line_len); 1408 memcpy (status_line->first_line, buf, first_line_len);
1346 status_line->first_line[first_line_len] = '\0'; 1409 status_line->first_line[first_line_len] = '\0';
1410 first_line_buf = strdup( status_line->first_line );
1347 1411
1348 /* protocol and version: "HTTP/x.x" SP */ 1412 /* protocol and version: "HTTP/x.x" SP */
1349 1413
1350 p = strtok(status_line->first_line, "/"); 1414 p = strtok(first_line_buf, "/");
1351 if( p == NULL ) { free( status_line->first_line ); return -1; } 1415 if( p == NULL ) { free( first_line_buf ); return -1; }
1352 if( strcmp( p, "HTTP" ) != 0 ) { free( status_line->first_line ); return -1; } 1416 if( strcmp( p, "HTTP" ) != 0 ) { free( first_line_buf ); return -1; }
1353 1417
1354 p = strtok( NULL, "." ); 1418 p = strtok( NULL, "." );
1355 if( p == NULL ) { free( status_line->first_line ); return -1; } 1419 if( p == NULL ) { free( first_line_buf ); return -1; }
1356 status_line->http_major = (int)strtol( p, &pp, 10 ); 1420 status_line->http_major = (int)strtol( p, &pp, 10 );
1357 if( *pp != '\0' ) { free( status_line->first_line ); return -1; } 1421 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
1358 1422
1359 p = strtok( NULL, " " ); 1423 p = strtok( NULL, " " );
1360 if( p == NULL ) { free( status_line->first_line ); return -1; } 1424 if( p == NULL ) { free( first_line_buf ); return -1; }
1361 status_line->http_minor = (int)strtol( p, &pp, 10 ); 1425 status_line->http_minor = (int)strtol( p, &pp, 10 );
1362 if( *pp != '\0' ) { free( status_line->first_line ); return -1; } 1426 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
1363 1427
1364 /* status code: "404" or "404.1", then SP */ 1428 /* status code: "404" or "404.1", then SP */
1365 1429
1366 p = strtok( NULL, " ." ); 1430 p = strtok( NULL, " ." );
1367 if( p == NULL ) { free( status_line->first_line ); return -1; } 1431 if( p == NULL ) { free( first_line_buf ); return -1; }
1368 if( strchr( p, '.' ) != NULL ) { 1432 if( strchr( p, '.' ) != NULL ) {
1369 char *ppp; 1433 char *ppp;
1370 ppp = strtok( p, "." ); 1434 ppp = strtok( p, "." );
1371 status_line->http_code = (int)strtol( ppp, &pp, 10 ); 1435 status_line->http_code = (int)strtol( ppp, &pp, 10 );
1372 if( *pp != '\0' ) { free( status_line->first_line ); return -1; } 1436 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
1373 1437
1374 ppp = strtok( NULL, "" ); 1438 ppp = strtok( NULL, "" );
1375 status_line->http_subcode = (int)strtol( ppp, &pp, 10 ); 1439 status_line->http_subcode = (int)strtol( ppp, &pp, 10 );
1376 if( *pp != '\0' ) { free( status_line->first_line ); return -1; } 1440 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
1377 } else { 1441 } else {
1378 status_line->http_code = (int)strtol( p, &pp, 10 ); 1442 status_line->http_code = (int)strtol( p, &pp, 10 );
1379 status_line->http_subcode = -1; 1443 status_line->http_subcode = -1;
1380 if( *pp != '\0' ) { free( status_line->first_line ); return -1; } 1444 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
1381 } 1445 }
1382 1446
1383 /* Human readable message: "Not Found" CRLF */ 1447 /* Human readable message: "Not Found" CRLF */
1384 1448
1449 free( first_line_buf );
1385 p = strtok( NULL, "" ); 1450 p = strtok( NULL, "" );
1386 if( p == NULL ) { free( status_line->first_line ); return -1; } 1451 if( p == NULL ) { free( status_line->first_line ); return -1; }
1387 status_line->msg = p; 1452 status_line->msg = status_line->first_line + ( p - first_line_buf );
1388 1453
1389 return 0; 1454 return 0;
1390} 1455}
@@ -1515,7 +1580,7 @@ parse_time_string (const char *string)
1515} 1580}
1516 1581
1517int 1582int
1518check_document_dates (const curlhelp_curlbuf *header_buf, char (*msg)[DEFAULT_BUFFER_SIZE]) 1583check_document_dates (const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFAULT_BUFFER_SIZE])
1519{ 1584{
1520 char *server_date = NULL; 1585 char *server_date = NULL;
1521 char *document_date = NULL; 1586 char *document_date = NULL;
diff --git a/plugins/tests/check_curl.t b/plugins/tests/check_curl.t
index dd567069..702edb87 100755
--- a/plugins/tests/check_curl.t
+++ b/plugins/tests/check_curl.t
@@ -257,7 +257,7 @@ sub run_common_tests {
257 $cmd = "$command -u /statuscode/200 -e 200"; 257 $cmd = "$command -u /statuscode/200 -e 200";
258 $result = NPTest->testCmd( $cmd ); 258 $result = NPTest->testCmd( $cmd );
259 is( $result->return_code, 0, $cmd); 259 is( $result->return_code, 0, $cmd);
260 like( $result->output, '/^HTTP OK: Status line output matched "200" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 260 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - Status line output matched "200" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
261 261
262 $cmd = "$command -u /statuscode/201"; 262 $cmd = "$command -u /statuscode/201";
263 $result = NPTest->testCmd( $cmd ); 263 $result = NPTest->testCmd( $cmd );
@@ -267,7 +267,7 @@ sub run_common_tests {
267 $cmd = "$command -u /statuscode/201 -e 201"; 267 $cmd = "$command -u /statuscode/201 -e 201";
268 $result = NPTest->testCmd( $cmd ); 268 $result = NPTest->testCmd( $cmd );
269 is( $result->return_code, 0, $cmd); 269 is( $result->return_code, 0, $cmd);
270 like( $result->output, '/^HTTP OK: Status line output matched "201" - \d+ bytes in [\d\.]+ second /', "Output correct: ".$result->output ); 270 like( $result->output, '/^HTTP OK: HTTP/1.1 201 Created - Status line output matched "201" - \d+ bytes in [\d\.]+ second /', "Output correct: ".$result->output );
271 271
272 $cmd = "$command -u /statuscode/201 -e 200"; 272 $cmd = "$command -u /statuscode/201 -e 200";
273 $result = NPTest->testCmd( $cmd ); 273 $result = NPTest->testCmd( $cmd );
@@ -277,12 +277,12 @@ sub run_common_tests {
277 $cmd = "$command -u /statuscode/200 -e 200,201,202"; 277 $cmd = "$command -u /statuscode/200 -e 200,201,202";
278 $result = NPTest->testCmd( $cmd ); 278 $result = NPTest->testCmd( $cmd );
279 is( $result->return_code, 0, $cmd); 279 is( $result->return_code, 0, $cmd);
280 like( $result->output, '/^HTTP OK: Status line output matched "200,201,202" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 280 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - Status line output matched "200,201,202" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
281 281
282 $cmd = "$command -u /statuscode/201 -e 200,201,202"; 282 $cmd = "$command -u /statuscode/201 -e 200,201,202";
283 $result = NPTest->testCmd( $cmd ); 283 $result = NPTest->testCmd( $cmd );
284 is( $result->return_code, 0, $cmd); 284 is( $result->return_code, 0, $cmd);
285 like( $result->output, '/^HTTP OK: Status line output matched "200,201,202" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 285 like( $result->output, '/^HTTP OK: HTTP/1.1 201 Created - Status line output matched "200,201,202" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
286 286
287 $cmd = "$command -u /statuscode/203 -e 200,201,202"; 287 $cmd = "$command -u /statuscode/203 -e 200,201,202";
288 $result = NPTest->testCmd( $cmd ); 288 $result = NPTest->testCmd( $cmd );