| 451 | | static int serf_complete(eventer_t e, int mask, |
|---|
| 452 | | void *closure, struct timeval *now) { |
|---|
| 453 | | serf_closure_t *ccl = (serf_closure_t *)closure; |
|---|
| 454 | | |
|---|
| 455 | | noitLT(nldeb, now, "serf_complete(%s)\n", ccl->check->target); |
|---|
| 456 | | if(!NOIT_CHECK_DISABLED(ccl->check) && !NOIT_CHECK_KILLED(ccl->check)) { |
|---|
| 457 | | serf_check_info_t *ci = ccl->check->closure; |
|---|
| 458 | | if(ci->finish_time.tv_sec == 0 && ci->finish_time.tv_usec == 0) |
|---|
| 459 | | memcpy(&ci->finish_time, now, sizeof(*now)); |
|---|
| 460 | | generic_log_results(ccl->self, ccl->check); |
|---|
| 461 | | } |
|---|
| 462 | | serf_cleanup(ccl->self, ccl->check); |
|---|
| 463 | | ccl->check->flags &= ~NP_RUNNING; |
|---|
| 464 | | free(ccl); |
|---|
| 465 | | return 0; |
|---|
| 466 | | } |
|---|
| 467 | | |
|---|
| 468 | | static int serf_handler(eventer_t e, int mask, |
|---|
| 469 | | void *closure, struct timeval *now) { |
|---|
| 470 | | apr_pollfd_t desc = { 0 }; |
|---|
| 471 | | serf_closure_t *sct = closure; |
|---|
| 472 | | serf_check_info_t *ci = sct->check->closure; |
|---|
| 473 | | |
|---|
| 474 | | desc.desc_type = APR_POLL_SOCKET; |
|---|
| 475 | | desc.desc.s = sct->skt; |
|---|
| 476 | | |
|---|
| 477 | | desc.rtnevents = 0; |
|---|
| 478 | | if(mask & EVENTER_READ) desc.rtnevents |= APR_POLLIN; |
|---|
| 479 | | if(mask & EVENTER_WRITE) desc.rtnevents |= APR_POLLOUT; |
|---|
| 480 | | if(mask & EVENTER_EXCEPTION) desc.rtnevents |= APR_POLLERR; |
|---|
| 481 | | noitL(nldeb, "serf_handler() => %d, %x [%c%c%c]\n", |
|---|
| 482 | | e->fd, desc.rtnevents, |
|---|
| 483 | | (desc.rtnevents & APR_POLLIN) ? 'I' : '-', |
|---|
| 484 | | (desc.rtnevents & APR_POLLOUT) ? 'O' : '-', |
|---|
| 485 | | (desc.rtnevents & APR_POLLERR) ? 'E' : '-'); |
|---|
| 486 | | serf_event_trigger(ci->context, sct->serf_baton, &desc); |
|---|
| 487 | | serf_context_prerun(ci->context); |
|---|
| 488 | | |
|---|
| 489 | | /* We're about to deschedule and free the event, drop our reference */ |
|---|
| 490 | | if(!e->mask) |
|---|
| 491 | | ci->fd_event = NULL; |
|---|
| 492 | | |
|---|
| 493 | | return e->mask; |
|---|
| 494 | | } |
|---|
| 495 | | |
|---|
| 496 | | static int serf_init(noit_module_t *self) { |
|---|
| 497 | | return 0; |
|---|
| 498 | | } |
|---|
| 499 | | static void closed_connection(serf_connection_t *conn, |
|---|
| 500 | | void *closed_baton, |
|---|
| 501 | | apr_status_t why, |
|---|
| 502 | | apr_pool_t *pool) { |
|---|
| 503 | | } |
|---|
| 504 | | static apr_status_t need_client_cert(void *data, |
|---|
| 505 | | const char **path) { |
|---|
| 506 | | app_baton_t *ctx = data; |
|---|
| 507 | | *path = ctx->certificate_file; |
|---|
| 508 | | return APR_SUCCESS; |
|---|
| 509 | | } |
|---|
| 510 | | static apr_status_t need_server_cert(void *data, |
|---|
| 511 | | int failures, |
|---|
| 512 | | const serf_ssl_certificate_t *cert) { |
|---|
| 513 | | return APR_SUCCESS; |
|---|
| 514 | | } |
|---|
| 515 | | static apr_status_t conn_setup(apr_socket_t *skt, |
|---|
| 516 | | serf_bucket_t **input_bkt, |
|---|
| 517 | | serf_bucket_t **output_bkt, |
|---|
| 518 | | void *setup_baton, |
|---|
| 519 | | apr_pool_t *pool) |
|---|
| 520 | | { |
|---|
| 521 | | serf_bucket_t *c; |
|---|
| 522 | | app_baton_t *ctx = setup_baton; |
|---|
| 523 | | |
|---|
| 524 | | c = serf_bucket_socket_create(skt, ctx->bkt_alloc); |
|---|
| 525 | | if (ctx->using_ssl) { |
|---|
| 526 | | c = serf_bucket_ssl_decrypt_create(c, ctx->ssl_ctx, ctx->bkt_alloc); |
|---|
| 527 | | if (!ctx->ssl_ctx) { |
|---|
| 528 | | serf_ssl_certificate_t *cert; |
|---|
| 529 | | ctx->ssl_ctx = serf_bucket_ssl_decrypt_context_get(c); |
|---|
| 530 | | |
|---|
| 531 | | /* Setup CA chain */ |
|---|
| 532 | | if(ctx->ca_chain_file && |
|---|
| 533 | | serf_ssl_load_cert_file(&cert, ctx->ca_chain_file, |
|---|
| 534 | | pool) != APR_SUCCESS) |
|---|
| 535 | | serf_ssl_trust_cert(ctx->ssl_ctx, cert); |
|---|
| 536 | | else |
|---|
| 537 | | serf_ssl_use_default_certificates(ctx->ssl_ctx); |
|---|
| 538 | | |
|---|
| 539 | | /* Setup client cert */ |
|---|
| 540 | | serf_ssl_client_cert_provider_set(ctx->ssl_ctx, need_client_cert, |
|---|
| 541 | | ctx, pool); |
|---|
| 542 | | } |
|---|
| 543 | | serf_ssl_server_cert_callback_set(ctx->ssl_ctx, need_server_cert, |
|---|
| 544 | | ctx); |
|---|
| 545 | | *output_bkt = serf_bucket_ssl_encrypt_create(*output_bkt, ctx->ssl_ctx, |
|---|
| 546 | | ctx->bkt_alloc); |
|---|
| 547 | | } |
|---|
| 548 | | *input_bkt = c; |
|---|
| 549 | | |
|---|
| 550 | | return APR_SUCCESS; |
|---|
| 551 | | } |
|---|
| 552 | | |
|---|
| 553 | | static serf_bucket_t* accept_response(serf_request_t *request, |
|---|
| 554 | | serf_bucket_t *stream, |
|---|
| 555 | | void *acceptor_baton, |
|---|
| 556 | | apr_pool_t *pool) { |
|---|
| 557 | | serf_bucket_t *c; |
|---|
| 558 | | serf_bucket_alloc_t *bkt_alloc; |
|---|
| 559 | | |
|---|
| 560 | | /* get the per-request bucket allocator */ |
|---|
| 561 | | bkt_alloc = serf_request_get_alloc(request); |
|---|
| 562 | | |
|---|
| 563 | | /* Create a barrier so the response doesn't eat us! */ |
|---|
| 564 | | c = serf_bucket_barrier_create(stream, bkt_alloc); |
|---|
| 565 | | |
|---|
| 566 | | return serf_bucket_response_create(c, bkt_alloc); |
|---|
| 567 | | } |
|---|
| 568 | | |
|---|
| 569 | | static void append_buf(apr_pool_t *p, buf_t *b, |
|---|
| | 464 | |
|---|
| | 465 | |
|---|
| | 466 | static int http_init(noit_module_t *self) { |
|---|
| | 467 | return 0; |
|---|
| | 468 | } |
|---|
| | 469 | |
|---|
| | 470 | static void append_buf(buf_t *b, |
|---|
| 584 | | static apr_status_t handle_response(serf_request_t *request, |
|---|
| 585 | | serf_bucket_t *response, |
|---|
| 586 | | void *handler_baton, |
|---|
| 587 | | apr_pool_t *pool) { |
|---|
| 588 | | const char *data; |
|---|
| 589 | | apr_size_t len; |
|---|
| 590 | | apr_status_t status; |
|---|
| 591 | | handler_baton_t *ctx = handler_baton; |
|---|
| 592 | | serf_check_info_t *ci = ctx->check->closure; |
|---|
| 593 | | |
|---|
| 594 | | if(response == NULL) { |
|---|
| 595 | | /* We were cancelled. */ |
|---|
| 596 | | goto finish; |
|---|
| 597 | | } |
|---|
| 598 | | status = serf_bucket_response_status(response, &ci->status); |
|---|
| 599 | | if (status) { |
|---|
| 600 | | if (APR_STATUS_IS_EAGAIN(status)) { |
|---|
| 601 | | return status; |
|---|
| 602 | | } |
|---|
| 603 | | goto finish; |
|---|
| 604 | | } |
|---|
| 605 | | |
|---|
| 606 | | while (1) { |
|---|
| 607 | | status = serf_bucket_read(response, 1024*32, &data, &len); |
|---|
| 608 | | if (SERF_BUCKET_READ_ERROR(status)) |
|---|
| 609 | | return status; |
|---|
| 610 | | |
|---|
| 611 | | append_buf(ci->pool, &ci->body, data, len); |
|---|
| 612 | | |
|---|
| 613 | | /* are we done yet? */ |
|---|
| 614 | | if (APR_STATUS_IS_EOF(status)) { |
|---|
| 615 | | serf_bucket_t *hdrs; |
|---|
| 616 | | hdrs = serf_bucket_response_get_headers(response); |
|---|
| 617 | | while (1) { |
|---|
| 618 | | status = serf_bucket_read(hdrs, 2048, &data, &len); |
|---|
| 619 | | if (SERF_BUCKET_READ_ERROR(status)) |
|---|
| 620 | | return status; |
|---|
| 621 | | |
|---|
| 622 | | append_buf(ci->pool, &ci->headers, data, len); |
|---|
| 623 | | if (APR_STATUS_IS_EOF(status)) { |
|---|
| 624 | | break; |
|---|
| | 479 | #define BODY_MAX_SIZE 1024 * 512 |
|---|
| | 480 | |
|---|
| | 481 | static size_t http_write_data( void *ptr, size_t size, size_t nmemb, void *baton) |
|---|
| | 482 | { |
|---|
| | 483 | http_check_info_t *ci = baton; |
|---|
| | 484 | size_t len = size * nmemb; |
|---|
| | 485 | size_t used = MIN(BODY_MAX_SIZE - ci->body.l, len); |
|---|
| | 486 | noitL(nldeb, "http_write_data(%p, %d)\n", ci, (int)used); |
|---|
| | 487 | if (used != 0) { |
|---|
| | 488 | append_buf(&ci->body, ptr, used); |
|---|
| | 489 | } |
|---|
| | 490 | return used; |
|---|
| | 491 | } |
|---|
| | 492 | |
|---|
| | 493 | |
|---|
| | 494 | static size_t http_write_headers( void *ptr, size_t size, size_t nmemb, void *baton) |
|---|
| | 495 | { |
|---|
| | 496 | http_check_info_t *ci = baton; |
|---|
| | 497 | size_t len = size * nmemb; |
|---|
| | 498 | size_t used = MIN(BODY_MAX_SIZE - ci->headers.l, len); |
|---|
| | 499 | noitL(nldeb, "http_write_headers(%p, %d)\n", ci, (int)used); |
|---|
| | 500 | if (used != 0) { |
|---|
| | 501 | append_buf(&ci->headers, ptr, used); |
|---|
| | 502 | } |
|---|
| | 503 | |
|---|
| | 504 | if (ci->status.code == 0) { |
|---|
| | 505 | /* HTTP/1.1 200 OK */ |
|---|
| | 506 | if (ci->headers.l > strlen("HTTP/#.# ###")) { |
|---|
| | 507 | char *p = NULL; |
|---|
| | 508 | ci->status.version = HTTP_VERSION(ci->headers.b[5] - '0', ci->headers.b[7] - '0'); |
|---|
| | 509 | if (ci->status.version != HTTP_11 && ci->status.version != HTTP_10) { |
|---|
| | 510 | /* TODO: log error*/ |
|---|
| | 511 | noitL(nldeb, "http_write_headers(%p) -- Invalid HTTP Version: %d\n", ci, ci->status.version); |
|---|
| | 512 | return 0; |
|---|
| | 513 | } |
|---|
| | 514 | |
|---|
| | 515 | ci->status.code = strtol(ci->headers.b + 8, &p, 10); |
|---|
| | 516 | if (ci->status.code != 0 && p) { |
|---|
| | 517 | while (*p && isspace(*p)) p++; |
|---|
| | 518 | if (*p) { |
|---|
| | 519 | ci->status.reason = strdup(p); |
|---|
| 627 | | |
|---|
| 628 | | goto finish; |
|---|
| 629 | | } |
|---|
| 630 | | |
|---|
| 631 | | /* have we drained the response so far? */ |
|---|
| 632 | | if (APR_STATUS_IS_EAGAIN(status)) |
|---|
| 633 | | return status; |
|---|
| 634 | | |
|---|
| 635 | | /* loop to read some more. */ |
|---|
| 636 | | } |
|---|
| 637 | | finish: |
|---|
| 638 | | gettimeofday(&ci->finish_time, NULL); |
|---|
| 639 | | noitL(nldeb, "serf finished request (%s) [%ld.%06d]\n", ctx->check->target, |
|---|
| 640 | | (long int)ci->finish_time.tv_sec, (int)ci->finish_time.tv_usec); |
|---|
| 641 | | if(ci->timeout_event) { |
|---|
| 642 | | eventer_remove(ci->timeout_event); |
|---|
| 643 | | ci->timed_out = 0; |
|---|
| 644 | | memcpy(&ci->timeout_event->whence, &ci->finish_time, |
|---|
| 645 | | sizeof(ci->finish_time)); |
|---|
| 646 | | eventer_add(ci->timeout_event); |
|---|
| 647 | | } |
|---|
| 648 | | return APR_EOF; |
|---|
| 649 | | } |
|---|
| 650 | | |
|---|
| 651 | | static apr_status_t setup_request(serf_request_t *request, |
|---|
| 652 | | void *setup_baton, |
|---|
| 653 | | serf_bucket_t **req_bkt, |
|---|
| 654 | | serf_response_acceptor_t *acceptor, void **acceptor_baton, |
|---|
| 655 | | serf_response_handler_t *handler, |
|---|
| 656 | | void **handler_baton, |
|---|
| 657 | | apr_pool_t *pool) { |
|---|
| 658 | | handler_baton_t *ctx = setup_baton; |
|---|
| 659 | | serf_bucket_t *hdrs_bkt; |
|---|
| 660 | | serf_bucket_t *body_bkt; |
|---|
| 661 | | |
|---|
| 662 | | body_bkt = NULL; |
|---|
| 663 | | |
|---|
| 664 | | *req_bkt = serf_bucket_request_create(ctx->method, ctx->path, body_bkt, |
|---|
| 665 | | serf_request_get_alloc(request)); |
|---|
| 666 | | |
|---|
| 667 | | hdrs_bkt = serf_bucket_request_get_headers(*req_bkt); |
|---|
| 668 | | |
|---|
| 669 | | serf_bucket_headers_setn(hdrs_bkt, "Host", ctx->host); |
|---|
| 670 | | serf_bucket_headers_setn(hdrs_bkt, "User-Agent", |
|---|
| 671 | | "Noit/" NOIT_HTTP_VERSION_STRING); |
|---|
| 672 | | /* Shouldn't serf do this for us? */ |
|---|
| 673 | | serf_bucket_headers_setn(hdrs_bkt, "Accept-Encoding", "gzip"); |
|---|
| 674 | | |
|---|
| 675 | | if (ctx->authn != NULL) { |
|---|
| 676 | | serf_bucket_headers_setn(hdrs_bkt, "Authorization", ctx->authn); |
|---|
| 677 | | } |
|---|
| 678 | | |
|---|
| 679 | | *acceptor = ctx->acceptor; |
|---|
| 680 | | *acceptor_baton = ctx->acceptor_baton; |
|---|
| 681 | | *handler = ctx->handler; |
|---|
| 682 | | *handler_baton = ctx; |
|---|
| 683 | | |
|---|
| 684 | | return APR_SUCCESS; |
|---|
| 685 | | } |
|---|
| 686 | | |
|---|
| 687 | | static apr_status_t serf_eventer_add(void *user_baton, |
|---|
| 688 | | apr_pollfd_t *pfd, |
|---|
| 689 | | void *serf_baton) { |
|---|
| 690 | | eventer_t e, newe = NULL; |
|---|
| 691 | | serf_closure_t *sct = user_baton, *newsct; |
|---|
| 692 | | assert(pfd->desc_type == APR_POLL_SOCKET); |
|---|
| 693 | | apr_os_sock_t fd; |
|---|
| 694 | | apr_os_sock_get(&fd, pfd->desc.s); |
|---|
| 695 | | |
|---|
| 696 | | noitL(nldeb, "serf_eventer_add() => %d, %x [%c%c%c]\n", |
|---|
| 697 | | fd, pfd->reqevents, |
|---|
| 698 | | (pfd->reqevents & APR_POLLIN) ? 'I' : '-', |
|---|
| 699 | | (pfd->reqevents & APR_POLLOUT) ? 'O' : '-', |
|---|
| 700 | | (pfd->reqevents & APR_POLLERR) ? 'E' : '-'); |
|---|
| | 522 | } |
|---|
| | 523 | } |
|---|
| | 524 | return used; |
|---|
| | 525 | } |
|---|
| | 526 | |
|---|
| | 527 | static int http_handler(eventer_t e, int mask, |
|---|
| | 528 | void *closure, struct timeval *now) |
|---|
| | 529 | { |
|---|
| | 530 | int cmask = 0; |
|---|
| | 531 | int handles = 0; |
|---|
| | 532 | http_check_info_t *ci = closure; |
|---|
| | 533 | |
|---|
| | 534 | if (!ci->curl) { |
|---|
| | 535 | return 0; |
|---|
| | 536 | } |
|---|
| | 537 | |
|---|
| | 538 | if(mask & EVENTER_READ) cmask |= CURL_CSELECT_IN; |
|---|
| | 539 | if(mask & EVENTER_WRITE) cmask|= CURL_CSELECT_OUT; |
|---|
| | 540 | if(mask & EVENTER_EXCEPTION) cmask |= CURL_CSELECT_ERR; |
|---|
| | 541 | |
|---|
| | 542 | ci->inside_handler = 1; |
|---|
| | 543 | //noitL(nldeb, "http_handler(%p, emask=%d, cmask=%d)\n", ci, mask, cmask); |
|---|
| | 544 | curl_multi_socket_action(ci->mcurl, e->fd, cmask, &handles); |
|---|
| | 545 | ci->inside_handler = 0; |
|---|
| | 546 | |
|---|
| | 547 | return e->mask; |
|---|
| | 548 | } |
|---|
| | 549 | |
|---|
| | 550 | static int http_socket_cb(CURL *_curl, curl_socket_t fd, int action, |
|---|
| | 551 | void *userp, |
|---|
| | 552 | void *socketp) |
|---|
| | 553 | { |
|---|
| | 554 | eventer_t e; |
|---|
| | 555 | http_check_info_t *ci = (http_check_info_t *)userp; |
|---|
| | 556 | |
|---|
| 702 | | if(!e) { |
|---|
| 703 | | newe = e = eventer_alloc(); |
|---|
| 704 | | e->fd = fd; |
|---|
| 705 | | e->callback = serf_handler; |
|---|
| 706 | | } |
|---|
| 707 | | if(!e->closure) |
|---|
| 708 | | e->closure = calloc(1, sizeof(serf_closure_t)); |
|---|
| 709 | | newsct = e->closure; |
|---|
| 710 | | newsct->self = sct->self; |
|---|
| 711 | | newsct->check = sct->check; |
|---|
| 712 | | newsct->serf_baton = serf_baton; |
|---|
| 713 | | newsct->skt = pfd->desc.s; |
|---|
| 714 | | e->mask = 0; |
|---|
| 715 | | if(pfd->reqevents & APR_POLLIN) e->mask |= EVENTER_READ; |
|---|
| 716 | | if(pfd->reqevents & APR_POLLOUT) e->mask |= EVENTER_WRITE; |
|---|
| 717 | | if(pfd->reqevents & APR_POLLERR) e->mask |= EVENTER_EXCEPTION; |
|---|
| 718 | | if(newe) { |
|---|
| 719 | | serf_check_info_t *ci = sct->check->closure; |
|---|
| 720 | | eventer_add(newe); |
|---|
| 721 | | ci->fd_event = newe; |
|---|
| 722 | | } |
|---|
| 723 | | /* ** Unneeded as this is called recursively ** |
|---|
| 724 | | else |
|---|
| 725 | | eventer_update(e); |
|---|
| 726 | | */ |
|---|
| 727 | | return APR_SUCCESS; |
|---|
| 728 | | } |
|---|
| 729 | | static apr_status_t serf_eventer_remove(void *user_baton, |
|---|
| 730 | | apr_pollfd_t *pfd, |
|---|
| 731 | | void *serf_baton) { |
|---|
| 732 | | serf_closure_t *sct = user_baton; |
|---|
| 733 | | serf_check_info_t *ci; |
|---|
| 734 | | eventer_t e; |
|---|
| 735 | | |
|---|
| 736 | | ci = sct->check->closure; |
|---|
| 737 | | assert(pfd->desc_type == APR_POLL_SOCKET); |
|---|
| 738 | | apr_os_sock_t fd; |
|---|
| 739 | | apr_os_sock_get(&fd, pfd->desc.s); |
|---|
| 740 | | |
|---|
| 741 | | noitL(nldeb, "serf_eventer_remove() => %d\n", fd); |
|---|
| 742 | | e = eventer_find_fd(fd); |
|---|
| 743 | | if(e) { |
|---|
| 744 | | free(e->closure); |
|---|
| 745 | | e->closure = NULL; |
|---|
| 746 | | e->mask = 0; |
|---|
| 747 | | } |
|---|
| 748 | | return 0; |
|---|
| 749 | | } |
|---|
| 750 | | |
|---|
| 751 | | static int serf_initiate(noit_module_t *self, noit_check_t *check) { |
|---|
| 752 | | serf_closure_t *ccl; |
|---|
| 753 | | serf_check_info_t *ci; |
|---|
| | 558 | switch (action) { |
|---|
| | 559 | case CURL_POLL_INOUT: |
|---|
| | 560 | case CURL_POLL_OUT: |
|---|
| | 561 | case CURL_POLL_IN: |
|---|
| | 562 | if(!e) { |
|---|
| | 563 | ci->fd_event = e = eventer_alloc(); |
|---|
| | 564 | e->fd = fd; |
|---|
| | 565 | e->callback = http_handler; |
|---|
| | 566 | e->closure = ci; |
|---|
| | 567 | } |
|---|
| | 568 | |
|---|
| | 569 | /* curl API don't have a command to look for err, but it actually |
|---|
| | 570 | * does want to know if there is one! |
|---|
| | 571 | */ |
|---|
| | 572 | e->mask |= EVENTER_EXCEPTION; |
|---|
| | 573 | if (action == CURL_POLL_INOUT) e->mask |= EVENTER_READ|EVENTER_WRITE; |
|---|
| | 574 | if (action == CURL_POLL_OUT) e->mask |= EVENTER_WRITE; |
|---|
| | 575 | if (action == CURL_POLL_IN) e->mask |= EVENTER_READ; |
|---|
| | 576 | noitL(nldeb, "http_socket_cb(add) => %d, %x [%c%c%c]\n", |
|---|
| | 577 | fd, action, |
|---|
| | 578 | (e->mask & EVENTER_READ) ? 'I' : '-', |
|---|
| | 579 | (e->mask & EVENTER_WRITE) ? 'O' : '-', |
|---|
| | 580 | (e->mask & EVENTER_EXCEPTION) ? 'E' : '-'); |
|---|
| | 581 | eventer_add(e); |
|---|
| | 582 | break; |
|---|
| | 583 | case CURL_POLL_REMOVE: |
|---|
| | 584 | noitL(nldeb, "http_socket_cb(remove) => %d\n", fd); |
|---|
| | 585 | if (e) { |
|---|
| | 586 | e->closure = NULL; |
|---|
| | 587 | e->mask = 0; |
|---|
| | 588 | if (ci->fd_event) { |
|---|
| | 589 | eventer_t te = eventer_remove_fd(ci->fd_event->fd); |
|---|
| | 590 | if (te && ci->inside_handler == 0) { |
|---|
| | 591 | http_eventer_free(te, ci); |
|---|
| | 592 | } |
|---|
| | 593 | else { |
|---|
| | 594 | te->mask = 0; |
|---|
| | 595 | } |
|---|
| | 596 | ci->fd_event = NULL; |
|---|
| | 597 | } |
|---|
| | 598 | } |
|---|
| | 599 | break; |
|---|
| | 600 | default: |
|---|
| | 601 | abort(); |
|---|
| | 602 | } |
|---|
| | 603 | |
|---|
| | 604 | return 0; |
|---|
| | 605 | } |
|---|
| | 606 | |
|---|
| | 607 | |
|---|
| | 608 | static int http_all_done(eventer_t e, int mask, |
|---|
| | 609 | void *closure, struct timeval *now) |
|---|
| | 610 | { |
|---|
| | 611 | http_check_info_t *ci = closure; |
|---|
| | 612 | noitL(nldeb, "http_all_done(%p)\n", ci); |
|---|
| | 613 | generic_log_results(ci->self, ci->check); |
|---|
| | 614 | http_cleanup_check(ci->self, ci->check); |
|---|
| | 615 | return 0; |
|---|
| | 616 | } |
|---|
| | 617 | |
|---|
| | 618 | static int http_consume_messages(http_check_info_t *ci) |
|---|
| | 619 | { |
|---|
| | 620 | CURLMsg *msg; |
|---|
| | 621 | int count; |
|---|
| | 622 | |
|---|
| | 623 | while ((msg = curl_multi_info_read(ci->mcurl, &count)) != NULL) { |
|---|
| | 624 | if (msg->msg == CURLMSG_DONE) { |
|---|
| | 625 | struct timeval when; |
|---|
| | 626 | long ret; |
|---|
| | 627 | |
|---|
| | 628 | noitL(nldeb, "http_consume_messages(%p) => DONE\n", ci); |
|---|
| | 629 | gettimeofday(&when, NULL); |
|---|
| | 630 | memcpy(&ci->finish_time, &when, sizeof(when)); |
|---|
| | 631 | curl_easy_getinfo(ci->curl, CURLINFO_RESPONSE_CODE, &ret); |
|---|
| | 632 | if (ret == 0) { |
|---|
| | 633 | /* no HTTP transfer took place! */ |
|---|
| | 634 | ci->timed_out = 1; |
|---|
| | 635 | } |
|---|
| | 636 | else { |
|---|
| | 637 | ci->timed_out = 0; |
|---|
| | 638 | } |
|---|
| | 639 | |
|---|
| | 640 | ci->done_event = eventer_alloc();; |
|---|
| | 641 | ci->done_event->mask = EVENTER_TIMER; |
|---|
| | 642 | memcpy(&ci->done_event->whence, &when, sizeof(when)); |
|---|
| | 643 | ci->done_event->closure = ci; |
|---|
| | 644 | ci->done_event->callback = http_all_done; |
|---|
| | 645 | eventer_add(ci->done_event); |
|---|
| | 646 | } |
|---|
| | 647 | } |
|---|
| | 648 | |
|---|
| | 649 | return 0; |
|---|
| | 650 | } |
|---|
| | 651 | |
|---|
| | 652 | |
|---|
| | 653 | static int http_recurrent(eventer_t e, int mask, |
|---|
| | 654 | void *closure, struct timeval *now) |
|---|
| | 655 | { |
|---|
| | 656 | http_check_info_t *ci = closure; |
|---|
| | 657 | http_consume_messages(ci); |
|---|
| | 658 | return e->mask; |
|---|
| | 659 | } |
|---|
| | 660 | |
|---|
| | 661 | static int http_timeout(eventer_t e, int mask, |
|---|
| | 662 | void *closure, struct timeval *now) |
|---|
| | 663 | { |
|---|
| | 664 | int cc; |
|---|
| | 665 | int handles = 0; |
|---|
| | 666 | http_check_info_t *ci = closure; |
|---|
| | 667 | |
|---|
| | 668 | if (ci->mcurl == NULL) { |
|---|
| | 669 | ci->timeout_event = NULL; |
|---|
| | 670 | return 0; |
|---|
| | 671 | } |
|---|
| | 672 | |
|---|
| | 673 | noitL(nldeb, "http_timeout(%p)\n", ci); |
|---|
| | 674 | |
|---|
| | 675 | do { |
|---|
| | 676 | cc = curl_multi_socket(ci->mcurl, CURL_SOCKET_TIMEOUT, &handles); |
|---|
| | 677 | } while(cc == CURLM_CALL_MULTI_PERFORM && handles != 0); |
|---|
| | 678 | |
|---|
| | 679 | ci->timeout_event = NULL; |
|---|
| | 680 | return 0; |
|---|
| | 681 | } |
|---|
| | 682 | |
|---|
| | 683 | static int http_set_timeout_cb(CURLM *_curlm, long timeoutms, void *closure) |
|---|
| | 684 | { |
|---|
| 824 | | } |
|---|
| 825 | | else { |
|---|
| 826 | | ci->app_ctx.using_ssl = 0; |
|---|
| 827 | | } |
|---|
| 828 | | |
|---|
| 829 | | status = apr_sockaddr_info_get(&ci->address, |
|---|
| 830 | | check->target, APR_UNSPEC, ci->url.port, 0, |
|---|
| 831 | | ci->pool); |
|---|
| 832 | | if (status) { |
|---|
| 833 | | /* Handle error -- log failure */ |
|---|
| 834 | | apr_pool_destroy(ci->pool); |
|---|
| 835 | | memset(ci, 0, sizeof(*ci)); |
|---|
| 836 | | check->flags &= ~NP_RUNNING; |
|---|
| 837 | | return 0; |
|---|
| 838 | | } |
|---|
| 839 | | |
|---|
| 840 | | ci->context = serf_context_create_ex(ccl, serf_eventer_add, |
|---|
| 841 | | serf_eventer_remove, ci->pool); |
|---|
| 842 | | |
|---|
| 843 | | ci->app_ctx.bkt_alloc = serf_bucket_allocator_create(ci->pool, NULL, NULL); |
|---|
| 844 | | ci->app_ctx.ssl_ctx = NULL; |
|---|
| 845 | | |
|---|
| 846 | | ci->connection = serf_connection_create(ci->context, ci->address, |
|---|
| 847 | | conn_setup, &ci->app_ctx, |
|---|
| 848 | | closed_connection, &ci->app_ctx, |
|---|
| 849 | | ci->pool); |
|---|
| 850 | | |
|---|
| 851 | | ci->handler_ctx.method = apr_pstrdup(ci->pool, "GET"); |
|---|
| 852 | | ci->handler_ctx.host = apr_pstrdup(ci->pool, ci->url.hostname); |
|---|
| 853 | | ci->handler_ctx.path = ci->url.path; |
|---|
| 854 | | ci->handler_ctx.authn = NULL; |
|---|
| 855 | | |
|---|
| 856 | | ci->handler_ctx.acceptor = accept_response; |
|---|
| 857 | | ci->handler_ctx.acceptor_baton = &ci->app_ctx; |
|---|
| 858 | | ci->handler_ctx.handler = handle_response; |
|---|
| 859 | | ci->handler_ctx.self = self; |
|---|
| 860 | | ci->handler_ctx.check = check; |
|---|
| 861 | | |
|---|
| 862 | | ci->request = serf_connection_request_create(ci->connection, setup_request, |
|---|
| 863 | | &ci->handler_ctx); |
|---|
| 864 | | serf_context_prerun(ci->context); |
|---|
| 865 | | |
|---|
| 866 | | newe = eventer_alloc(); |
|---|
| 867 | | newe->mask = EVENTER_TIMER; |
|---|
| 868 | | gettimeofday(&when, NULL); |
|---|
| 869 | | p_int.tv_sec = check->timeout / 1000; |
|---|
| 870 | | p_int.tv_usec = (check->timeout % 1000) * 1000; |
|---|
| 871 | | add_timeval(when, p_int, &newe->whence); |
|---|
| 872 | | ccl = calloc(1, sizeof(*ccl)); |
|---|
| 873 | | ccl->self = self; |
|---|
| 874 | | ccl->check = check; |
|---|
| 875 | | newe->closure = ccl; |
|---|
| 876 | | newe->callback = serf_complete; |
|---|
| 877 | | eventer_add(newe); |
|---|
| 878 | | ci->timeout_event = newe; |
|---|
| 879 | | return 0; |
|---|
| 880 | | } |
|---|
| 881 | | static int serf_initiate_check(noit_module_t *self, noit_check_t *check, |
|---|
| | 791 | #endif |
|---|
| | 792 | } |
|---|
| | 793 | |
|---|
| | 794 | snprintf(buf, sizeof(buf), "Host: %s", ci->url->server); |
|---|
| | 795 | ci->cheaders = curl_slist_append(ci->cheaders, buf); |
|---|
| | 796 | ci->cheaders = curl_slist_append(ci->cheaders, "Accept-Encoding: deflate,gzip"); |
|---|
| | 797 | |
|---|
| | 798 | ci->curl = curl_easy_init(); |
|---|
| | 799 | |
|---|
| | 800 | curl_easy_setopt(ci->curl, CURLOPT_NOSIGNAL, 0); |
|---|
| | 801 | curl_easy_setopt(ci->curl, CURLOPT_WRITEFUNCTION, http_write_data); |
|---|
| | 802 | curl_easy_setopt(ci->curl, CURLOPT_WRITEDATA, ci); |
|---|
| | 803 | curl_easy_setopt(ci->curl, CURLOPT_HEADERFUNCTION, http_write_headers); |
|---|
| | 804 | curl_easy_setopt(ci->curl, CURLOPT_HEADERDATA, ci); |
|---|
| | 805 | |
|---|
| | 806 | free(ci->url->server); |
|---|
| | 807 | ci->url->server = strdup(check->target); |
|---|
| | 808 | urlstr = (char *)xmlSaveUri(ci->url); |
|---|
| | 809 | curl_easy_setopt(ci->curl, CURLOPT_URL, urlstr); |
|---|
| | 810 | noitL(nldeb, "http_initiate(%p,%s,url=%s)\n", |
|---|
| | 811 | ci, check->target, urlstr); |
|---|
| | 812 | xmlFreeURI(ci->url); |
|---|
| | 813 | free(urlstr); |
|---|
| | 814 | ci->url = NULL; |
|---|
| | 815 | |
|---|
| | 816 | |
|---|
| | 817 | curl_easy_setopt(ci->curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS); |
|---|
| | 818 | curl_easy_setopt(ci->curl, CURLOPT_FOLLOWLOCATION, 0); |
|---|
| | 819 | curl_easy_setopt(ci->curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP); |
|---|
| | 820 | |
|---|
| | 821 | curl_easy_setopt(ci->curl, CURLOPT_USERAGENT, "Noit/" NOIT_HTTP_VERSION_STRING); |
|---|
| | 822 | curl_easy_setopt(ci->curl, CURLOPT_HTTPHEADER, ci->cheaders); |
|---|
| | 823 | |
|---|
| | 824 | curl_easy_setopt(ci->curl, CURLOPT_FRESH_CONNECT, 1); |
|---|
| | 825 | curl_easy_setopt(ci->curl, CURLOPT_FORBID_REUSE, 1); |
|---|
| | 826 | |
|---|
| | 827 | /* TODO: more SSL options */ |
|---|
| | 828 | curl_easy_setopt(ci->curl, CURLOPT_SSL_VERIFYPEER, 0); |
|---|
| | 829 | curl_easy_setopt(ci->curl, CURLOPT_SSL_VERIFYHOST, 0); |
|---|
| | 830 | curl_easy_setopt(ci->curl, CURLOPT_TIMEOUT_MS, check->timeout); |
|---|
| | 831 | curl_easy_setopt(ci->curl, CURLOPT_CONNECTTIMEOUT_MS, check->timeout); |
|---|
| | 832 | |
|---|
| | 833 | /* TODO: Consider re-using the multi-init */ |
|---|
| | 834 | ci->mcurl = curl_multi_init(); |
|---|
| | 835 | curl_multi_setopt(ci->mcurl, CURLMOPT_SOCKETFUNCTION, http_socket_cb); |
|---|
| | 836 | curl_multi_setopt(ci->mcurl, CURLMOPT_SOCKETDATA, ci); |
|---|
| | 837 | curl_multi_setopt(ci->mcurl, CURLMOPT_PIPELINING, 0); |
|---|
| | 838 | |
|---|
| | 839 | curl_multi_setopt(ci->mcurl, CURLMOPT_TIMERFUNCTION, http_set_timeout_cb); |
|---|
| | 840 | curl_multi_setopt(ci->mcurl, CURLMOPT_TIMERDATA, ci); |
|---|
| | 841 | |
|---|
| | 842 | curl_multi_add_handle(ci->mcurl, ci->curl); |
|---|
| | 843 | |
|---|
| | 844 | { |
|---|
| | 845 | int running_handles = 0; |
|---|
| | 846 | while (curl_multi_perform(ci->mcurl, &running_handles) == CURLM_CALL_MULTI_PERFORM); |
|---|
| | 847 | } |
|---|
| | 848 | |
|---|
| | 849 | ci->process_event = eventer_alloc(); |
|---|
| | 850 | ci->process_event->closure = ci; |
|---|
| | 851 | ci->process_event->mask = EVENTER_RECURRENT; |
|---|
| | 852 | ci->process_event->callback = http_recurrent; |
|---|
| | 853 | |
|---|
| | 854 | eventer_add_recurrent(ci->process_event); |
|---|
| | 855 | |
|---|
| | 856 | return 0; |
|---|
| | 857 | } |
|---|
| | 858 | static int http_initiate_check(noit_module_t *self, noit_check_t *check, |
|---|