diff options
| -rw-r--r-- | plugins/check_http.c | 103 |
1 files changed, 102 insertions, 1 deletions
diff --git a/plugins/check_http.c b/plugins/check_http.c index a2c7571b..5710cfe1 100644 --- a/plugins/check_http.c +++ b/plugins/check_http.c | |||
| @@ -146,6 +146,7 @@ char *perfd_time_transfer(double microsec); | |||
| 146 | char *perfd_size(int page_len); | 146 | char *perfd_size(int page_len); |
| 147 | void print_help(void); | 147 | void print_help(void); |
| 148 | void print_usage(void); | 148 | void print_usage(void); |
| 149 | char *unchunk_content(char *content); | ||
| 149 | 150 | ||
| 150 | int main(int argc, char **argv) { | 151 | int main(int argc, char **argv) { |
| 151 | int result = STATE_UNKNOWN; | 152 | int result = STATE_UNKNOWN; |
| @@ -1252,7 +1253,26 @@ int check_http(void) { | |||
| 1252 | } | 1253 | } |
| 1253 | } | 1254 | } |
| 1254 | 1255 | ||
| 1255 | if (strlen(string_expect)) { | 1256 | // At this point we should test if the content is chunked and unchunk it, so |
| 1257 | // it can be searched (and possibly printed) | ||
| 1258 | const char *chunked_header_regex_string = "Transfer-Encoding:\\s*chunked\\s*"CRLF; | ||
| 1259 | regex_t chunked_header_regex; | ||
| 1260 | |||
| 1261 | if (regcomp(&chunked_header_regex, chunked_header_regex_string, 0)) { | ||
| 1262 | die(STATE_UNKNOWN, "HTTP %s: %s\n", state_text(STATE_UNKNOWN), "Failed to compile chunked_header_regex regex"); | ||
| 1263 | } | ||
| 1264 | |||
| 1265 | regmatch_t chre_pmatch[1]; // We actually do not care about this, since we only want to know IF it was found | ||
| 1266 | |||
| 1267 | if (regexec(&chunked_header_regex, header, 1, chre_pmatch, 0) == 0) { | ||
| 1268 | // We actually found the chunked header | ||
| 1269 | char *tmp = unchunk_content(page); | ||
| 1270 | if (tmp == NULL) { | ||
| 1271 | die(STATE_UNKNOWN, "HTTP %s: %s\n", state_text(STATE_UNKNOWN), "Failed to unchunk message body"); | ||
| 1272 | } | ||
| 1273 | } | ||
| 1274 | |||
| 1275 | if (strlen(string_expect) > 0) { | ||
| 1256 | if (!strstr(page, string_expect)) { | 1276 | if (!strstr(page, string_expect)) { |
| 1257 | // We found the string the body, the rest is for building the output | 1277 | // We found the string the body, the rest is for building the output |
| 1258 | char output_string_search[30] = ""; | 1278 | char output_string_search[30] = ""; |
| @@ -1342,6 +1362,87 @@ int check_http(void) { | |||
| 1342 | return STATE_UNKNOWN; | 1362 | return STATE_UNKNOWN; |
| 1343 | } | 1363 | } |
| 1344 | 1364 | ||
| 1365 | /* Receivces a pointer to the beginning of the body of a HTTP message | ||
| 1366 | * which is chunked and returns a pointer to a freshly allocated memory | ||
| 1367 | * region containing the unchunked body or NULL if something failed. | ||
| 1368 | * The result must be freed by the caller. | ||
| 1369 | */ | ||
| 1370 | char *unchunk_content(const char *content) { | ||
| 1371 | // https://en.wikipedia.org/wiki/Chunked_transfer_encoding | ||
| 1372 | // https://www.rfc-editor.org/rfc/rfc7230#section-4.1 | ||
| 1373 | char *result = NULL; | ||
| 1374 | size_t content_length = strlen(content); | ||
| 1375 | char *start_of_chunk, end_of_chunk; | ||
| 1376 | long size_of_chunk; | ||
| 1377 | char *pointer = content; | ||
| 1378 | char *endptr; | ||
| 1379 | long length_of_chunk = 0; | ||
| 1380 | size_t overall_size = 0; | ||
| 1381 | char *result_ptr; | ||
| 1382 | |||
| 1383 | while (true) { | ||
| 1384 | size_of_chunk = strtol(pointer, &endptr, 16); | ||
| 1385 | if (size_of_chunk == LONG_MIN || size_of_chunk == LONG_MAX) { | ||
| 1386 | // Apparently underflow or overflow, should not happen | ||
| 1387 | if (verbose) { | ||
| 1388 | printf("Got an underflow or overflow from strtol at: %u\n", __LINE__); | ||
| 1389 | } | ||
| 1390 | return NULL; | ||
| 1391 | } | ||
| 1392 | if (endptr == pointer) { | ||
| 1393 | // Apparently this was not a number | ||
| 1394 | if (verbose) { | ||
| 1395 | printf("Chunked content did not start with a number at all (Line: %u)\n", __LINE__); | ||
| 1396 | } | ||
| 1397 | return NULL | ||
| 1398 | } | ||
| 1399 | |||
| 1400 | // So, we got the length of the chunk | ||
| 1401 | if (*endptr == ';') { | ||
| 1402 | // Chunk extension starts here | ||
| 1403 | // TODO | ||
| 1404 | while (*endptr != '\r') { | ||
| 1405 | endptr++; | ||
| 1406 | } | ||
| 1407 | } | ||
| 1408 | |||
| 1409 | start_of_chunk = endptr + 2; | ||
| 1410 | end_of_chunk = start_of_chunk + size_of_chunk; | ||
| 1411 | length_of_chunk = end_of_chunk - start_of_chunk; | ||
| 1412 | |||
| 1413 | if (length_of_chunk == 0) { | ||
| 1414 | // Chunk length is 0, so this is the last one | ||
| 1415 | break; | ||
| 1416 | } | ||
| 1417 | |||
| 1418 | overall_size += length_of_chunk; | ||
| 1419 | |||
| 1420 | if (result == NULL) { | ||
| 1421 | result = (char *)calloc(length_of_chunk, sizeof(char)); | ||
| 1422 | if (result == NULL) { | ||
| 1423 | if (verbose) { | ||
| 1424 | printf("Failed to allocate memory for unchunked body\n"); | ||
| 1425 | } | ||
| 1426 | return NULL; | ||
| 1427 | } | ||
| 1428 | result_ptr = result; | ||
| 1429 | } else { | ||
| 1430 | void *tmp = realloc(result, overall_size); | ||
| 1431 | if (tmp == NULL) { | ||
| 1432 | if (verbose) { | ||
| 1433 | printf("Failed to allocate memory for unchunked body\n"); | ||
| 1434 | } | ||
| 1435 | return NULL; | ||
| 1436 | } | ||
| 1437 | } | ||
| 1438 | |||
| 1439 | memcpy(result_ptr, start_of_chunk, size_of_chunk); | ||
| 1440 | result_ptr = result_ptr + size_of_chunk; | ||
| 1441 | } | ||
| 1442 | |||
| 1443 | return result | ||
| 1444 | } | ||
| 1445 | |||
| 1345 | /* per RFC 2396 */ | 1446 | /* per RFC 2396 */ |
| 1346 | #define URI_HTTP "%5[HTPShtps]" | 1447 | #define URI_HTTP "%5[HTPShtps]" |
| 1347 | #define URI_HOST \ | 1448 | #define URI_HOST \ |
