/* cleanup for conn */ static apr_status_t cleanup_conn(void *baton) { serf_connection_t *conn = baton; serf_connection_close(conn); return APR_SUCCESS; }
apr_status_t test_server_teardown(test_baton_t *tb, apr_pool_t *pool) { serf_connection_close(tb->connection); if (tb->serv_ctx) test_server_destroy(tb->serv_ctx, pool); if (tb->proxy_ctx) test_server_destroy(tb->proxy_ctx, pool); return APR_SUCCESS; }
apr_status_t test_server_destroy(test_baton_t *tb, apr_pool_t *pool) { serf_connection_close(tb->connection); apr_socket_close(tb->serv_sock); if (tb->client_sock) { apr_socket_close(tb->client_sock); } return APR_SUCCESS; }
int main(int argc, const char **argv) { apr_status_t status; apr_pool_t *pool; apr_sockaddr_t *address; serf_context_t *context; serf_connection_t *connection; app_baton_t app_ctx; handler_baton_t *handler_ctx; apr_uri_t url; const char *raw_url, *method; int count; apr_getopt_t *opt; char opt_c; char *authn = NULL; const char *opt_arg; /* For the parser threads */ apr_thread_t *thread[3]; apr_threadattr_t *tattr; apr_status_t parser_status; parser_baton_t *parser_ctx; apr_initialize(); atexit(apr_terminate); apr_pool_create(&pool, NULL); apr_atomic_init(pool); /* serf_initialize(); */ /* Default to one round of fetching. */ count = 1; /* Default to GET. */ method = "GET"; apr_getopt_init(&opt, pool, argc, argv); while ((status = apr_getopt(opt, "a:hv", &opt_c, &opt_arg)) == APR_SUCCESS) { int srclen, enclen; switch (opt_c) { case 'a': srclen = strlen(opt_arg); enclen = apr_base64_encode_len(srclen); authn = apr_palloc(pool, enclen + 6); strcpy(authn, "Basic "); (void) apr_base64_encode(&authn[6], opt_arg, srclen); break; case 'h': print_usage(pool); exit(0); break; case 'v': puts("Serf version: " SERF_VERSION_STRING); exit(0); default: break; } } if (opt->ind != opt->argc - 1) { print_usage(pool); exit(-1); } raw_url = argv[opt->ind]; apr_uri_parse(pool, raw_url, &url); if (!url.port) { url.port = apr_uri_port_of_scheme(url.scheme); } if (!url.path) { url.path = "/"; } if (strcasecmp(url.scheme, "https") == 0) { app_ctx.using_ssl = 1; } else { app_ctx.using_ssl = 0; } status = apr_sockaddr_info_get(&address, url.hostname, APR_UNSPEC, url.port, 0, pool); if (status) { printf("Error creating address: %d\n", status); exit(1); } context = serf_context_create(pool); /* ### Connection or Context should have an allocator? */ app_ctx.bkt_alloc = serf_bucket_allocator_create(pool, NULL, NULL); app_ctx.ssl_ctx = NULL; app_ctx.authn = authn; connection = serf_connection_create(context, address, conn_setup, &app_ctx, closed_connection, &app_ctx, pool); handler_ctx = (handler_baton_t*)serf_bucket_mem_alloc(app_ctx.bkt_alloc, sizeof(handler_baton_t)); handler_ctx->allocator = app_ctx.bkt_alloc; handler_ctx->doc_queue = apr_array_make(pool, 1, sizeof(doc_path_t*)); handler_ctx->doc_queue_alloc = app_ctx.bkt_alloc; handler_ctx->requests_outstanding = (apr_uint32_t*)serf_bucket_mem_alloc(app_ctx.bkt_alloc, sizeof(apr_uint32_t)); apr_atomic_set32(handler_ctx->requests_outstanding, 0); handler_ctx->hdr_read = 0; parser_ctx = (void*)serf_bucket_mem_alloc(app_ctx.bkt_alloc, sizeof(parser_baton_t)); parser_ctx->requests_outstanding = handler_ctx->requests_outstanding; parser_ctx->connection = connection; parser_ctx->app_ctx = &app_ctx; parser_ctx->doc_queue = handler_ctx->doc_queue; parser_ctx->doc_queue_alloc = handler_ctx->doc_queue_alloc; /* Restrict ourselves to this host. */ parser_ctx->hostinfo = url.hostinfo; status = apr_thread_mutex_create(&parser_ctx->mutex, APR_THREAD_MUTEX_DEFAULT, pool); if (status) { printf("Couldn't create mutex %d\n", status); return status; } status = apr_thread_cond_create(&parser_ctx->condvar, pool); if (status) { printf("Couldn't create condvar: %d\n", status); return status; } /* Let the handler now which condvar to use. */ handler_ctx->doc_queue_condvar = parser_ctx->condvar; apr_threadattr_create(&tattr, pool); /* Start the parser thread. */ apr_thread_create(&thread[0], tattr, parser_thread, parser_ctx, pool); /* Deliver the first request. */ create_request(url.hostinfo, url.path, NULL, NULL, parser_ctx, pool); /* Go run our normal thread. */ while (1) { int tries = 0; status = serf_context_run(context, SERF_DURATION_FOREVER, pool); if (APR_STATUS_IS_TIMEUP(status)) continue; if (status) { char buf[200]; printf("Error running context: (%d) %s\n", status, apr_strerror(status, buf, sizeof(buf))); exit(1); } /* We run this check to allow our parser threads to add more * requests to our queue. */ for (tries = 0; tries < 3; tries++) { if (!apr_atomic_read32(handler_ctx->requests_outstanding)) { #ifdef SERF_VERBOSE printf("Waiting..."); #endif apr_sleep(100000); #ifdef SERF_VERBOSE printf("Done\n"); #endif } else { break; } } if (tries >= 3) { break; } /* Debugging purposes only! */ serf_debug__closed_conn(app_ctx.bkt_alloc); } printf("Quitting...\n"); serf_connection_close(connection); /* wake up the parser via condvar signal */ apr_thread_cond_signal(parser_ctx->condvar); status = apr_thread_join(&parser_status, thread[0]); if (status) { printf("Error joining thread: %d\n", status); return status; } serf_bucket_mem_free(app_ctx.bkt_alloc, handler_ctx->requests_outstanding); serf_bucket_mem_free(app_ctx.bkt_alloc, parser_ctx); apr_pool_destroy(pool); return 0; }
int main(int argc, const char **argv) { apr_status_t status; apr_pool_t *pool; serf_bucket_alloc_t *bkt_alloc; serf_context_t *context; serf_connection_t **connections; app_baton_t app_ctx; handler_baton_t handler_ctx; serf_bucket_t *req_hdrs = NULL; apr_uri_t url; const char *proxy = NULL; const char *raw_url, *method, *req_body_path = NULL; int count, inflight, conn_count; int i; int print_headers, debug; const char *username = NULL; const char *password = ""; const char *pem_path = NULL, *pem_pwd = NULL; apr_getopt_t *opt; int opt_c; const char *opt_arg; apr_initialize(); atexit(apr_terminate); apr_pool_create(&pool, NULL); /* serf_initialize(); */ bkt_alloc = serf_bucket_allocator_create(pool, NULL, NULL); /* Default to one round of fetching with no limit to max inflight reqs. */ count = 1; inflight = 0; conn_count = 1; /* Default to GET. */ method = "GET"; /* Do not print headers by default. */ print_headers = 0; /* Do not debug by default. */ debug = 0; apr_getopt_init(&opt, pool, argc, argv); while ((status = apr_getopt_long(opt, options, &opt_c, &opt_arg)) == APR_SUCCESS) { switch (opt_c) { case 'U': username = opt_arg; break; case 'P': password = opt_arg; break; case 'd': debug = 1; break; case 'f': req_body_path = opt_arg; break; case 'h': print_usage(pool); exit(0); break; case 'H': print_headers = 1; break; case 'm': method = opt_arg; break; case 'n': errno = 0; count = apr_strtoi64(opt_arg, NULL, 10); if (errno) { printf("Problem converting number of times to fetch URL (%d)\n", errno); return errno; } break; case 'c': errno = 0; conn_count = apr_strtoi64(opt_arg, NULL, 10); if (errno) { printf("Problem converting number of concurrent connections to use (%d)\n", errno); return errno; } if (conn_count <= 0) { printf("Invalid number of concurrent connections to use (%d)\n", conn_count); return 1; } break; case 'x': errno = 0; inflight = apr_strtoi64(opt_arg, NULL, 10); if (errno) { printf("Problem converting number of requests to have outstanding (%d)\n", errno); return errno; } break; case 'p': proxy = opt_arg; break; case 'r': { char *sep; char *hdr_val; if (req_hdrs == NULL) { /* first request header, allocate bucket */ req_hdrs = serf_bucket_headers_create(bkt_alloc); } sep = strchr(opt_arg, ':'); if ((sep == NULL) || (sep == opt_arg) || (strlen(sep) <= 1)) { printf("Invalid request header string (%s)\n", opt_arg); return EINVAL; } hdr_val = sep + 1; while (*hdr_val == ' ') { hdr_val++; } serf_bucket_headers_setx(req_hdrs, opt_arg, (sep - opt_arg), 1, hdr_val, strlen(hdr_val), 1); } break; case CERTFILE: pem_path = opt_arg; break; case CERTPWD: pem_pwd = opt_arg; break; case 'v': puts("Serf version: " SERF_VERSION_STRING); exit(0); default: break; } } if (opt->ind != opt->argc - 1) { print_usage(pool); exit(-1); } raw_url = argv[opt->ind]; apr_uri_parse(pool, raw_url, &url); if (!url.port) { url.port = apr_uri_port_of_scheme(url.scheme); } if (!url.path) { url.path = "/"; } if (strcasecmp(url.scheme, "https") == 0) { app_ctx.using_ssl = 1; } else { app_ctx.using_ssl = 0; } if (strcasecmp(method, "HEAD") == 0) { app_ctx.head_request = 1; } else { app_ctx.head_request = 0; } app_ctx.hostinfo = url.hostinfo; app_ctx.pem_path = pem_path; app_ctx.pem_pwd = pem_pwd; context = serf_context_create(pool); app_ctx.serf_ctx = context; if (proxy) { apr_sockaddr_t *proxy_address = NULL; apr_port_t proxy_port; char *proxy_host; char *proxy_scope; status = apr_parse_addr_port(&proxy_host, &proxy_scope, &proxy_port, proxy, pool); if (status) { printf("Cannot parse proxy hostname/port: %d\n", status); apr_pool_destroy(pool); exit(1); } if (!proxy_host) { printf("Proxy hostname must be specified\n"); apr_pool_destroy(pool); exit(1); } if (!proxy_port) { printf("Proxy port must be specified\n"); apr_pool_destroy(pool); exit(1); } status = apr_sockaddr_info_get(&proxy_address, proxy_host, APR_UNSPEC, proxy_port, 0, pool); if (status) { printf("Cannot resolve proxy address '%s': %d\n", proxy_host, status); apr_pool_destroy(pool); exit(1); } serf_config_proxy(context, proxy_address); } if (username) { serf_config_authn_types(context, SERF_AUTHN_ALL); } else { serf_config_authn_types(context, SERF_AUTHN_NTLM | SERF_AUTHN_NEGOTIATE); } serf_config_credentials_callback(context, credentials_callback); /* Setup debug logging */ if (debug) { serf_log_output_t *output; apr_status_t status; status = serf_logging_create_stream_output(&output, context, SERF_LOG_DEBUG, SERF_LOGCOMP_ALL_MSG, SERF_LOG_DEFAULT_LAYOUT, stderr, pool); if (!status) serf_logging_add_output(context, output); } /* ### Connection or Context should have an allocator? */ app_ctx.bkt_alloc = bkt_alloc; connections = apr_pcalloc(pool, conn_count * sizeof(serf_connection_t*)); for (i = 0; i < conn_count; i++) { conn_baton_t *conn_ctx = apr_pcalloc(pool, sizeof(*conn_ctx)); conn_ctx->app = &app_ctx; conn_ctx->ssl_ctx = NULL; status = serf_connection_create2(&connections[i], context, url, conn_setup, conn_ctx, closed_connection, conn_ctx, pool); if (status) { printf("Error creating connection: %d\n", status); apr_pool_destroy(pool); exit(1); } serf_connection_set_max_outstanding_requests(connections[i], inflight); } handler_ctx.completed_requests = 0; handler_ctx.print_headers = print_headers; #if APR_VERSION_AT_LEAST(1, 3, 0) apr_file_open_flags_stdout(&handler_ctx.output_file, APR_BUFFERED, pool); #else apr_file_open_stdout(&handler_ctx.output_file, pool); #endif handler_ctx.host = url.hostinfo; handler_ctx.method = method; handler_ctx.path = apr_pstrcat(pool, url.path, url.query ? "?" : "", url.query ? url.query : "", NULL); handler_ctx.username = username; handler_ctx.password = password; handler_ctx.auth_attempts = 0; handler_ctx.req_body_path = req_body_path; handler_ctx.acceptor = accept_response; handler_ctx.acceptor_baton = &app_ctx; handler_ctx.handler = handle_response; handler_ctx.req_hdrs = req_hdrs; for (i = 0; i < count; i++) { /* We don't need the returned request here. */ serf_connection_request_create(connections[i % conn_count], setup_request, &handler_ctx); } while (1) { status = serf_context_run(context, SERF_DURATION_FOREVER, pool); if (APR_STATUS_IS_TIMEUP(status)) continue; if (status) { char buf[200]; const char *err_string; err_string = serf_error_string(status); if (!err_string) { err_string = apr_strerror(status, buf, sizeof(buf)); } printf("Error running context: (%d) %s\n", status, err_string); apr_pool_destroy(pool); exit(1); } if (apr_atomic_read32(&handler_ctx.completed_requests) >= count) { break; } /* Debugging purposes only! */ serf_debug__closed_conn(app_ctx.bkt_alloc); } apr_file_close(handler_ctx.output_file); for (i = 0; i < conn_count; i++) { serf_connection_close(connections[i]); } apr_pool_destroy(pool); return 0; }
apr_table_t * default_chxj_serf_head(request_rec *r, apr_pool_t *ppool, const char *url_path, int *response_code) { apr_pool_t *pool; apr_uri_t url; apr_status_t rv; apr_sockaddr_t *address = NULL; serf_context_t *context; serf_connection_t *connection; app_ctx_t app_ctx; handler_ctx_t handler_ctx; char *ret; DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__); s_init(ppool, &pool); apr_uri_parse(pool, url_path, &url); if (!url.port) { url.port = apr_uri_port_of_scheme(url.scheme); } if (!url.port) { url.port = 80; } if (!url.path) { url.path = "/"; } if (!url.hostname) { url.hostname = "localhost"; } if (url.query) { url.path = apr_psprintf(pool, "%s?%s", url.path, url.query); } rv = apr_sockaddr_info_get(&address, url.hostname, APR_UNSPEC, url.port, 0, pool); if (rv != APR_SUCCESS) { char buf[256]; ERR(r, "apr_sockaddr_info_get() failed: rv:[%d|%s]", rv, apr_strerror(rv, buf, 256)); return NULL; } memset(&app_ctx, 0, sizeof(app_ctx_t)); app_ctx.bkt_alloc = serf_bucket_allocator_create(pool, NULL, NULL); if (strcasecmp(url.scheme, "https") == 0) { app_ctx.ssl_flag = 1; } context = serf_context_create(pool); connection = serf_connection_create(context, address, s_connection_setup, &app_ctx, s_connection_closed, &app_ctx, pool); memset(&handler_ctx, 0, sizeof(handler_ctx_t)); handler_ctx.requests_outstanding = 0; handler_ctx.host = url.hostinfo; /*========================================================================================================*/ /* XXX Maybe, libserf doesn't support the HEAD request. Because the part body is waited for with polling. */ /*========================================================================================================*/ handler_ctx.method = "GET"; handler_ctx.path = url.path; handler_ctx.user_agent = (char *)apr_table_get(r->headers_in, CHXJ_HTTP_USER_AGENT); if (! handler_ctx.user_agent) { handler_ctx.user_agent = (char *)apr_table_get(r->headers_in, HTTP_USER_AGENT); } handler_ctx.post_data = NULL; handler_ctx.post_data_len = 0; handler_ctx.acceptor = s_accept_response; handler_ctx.acceptor_ctx = &app_ctx; handler_ctx.handler = s_handle_response; handler_ctx.pool = pool; handler_ctx.r = r; handler_ctx.response_len = 0; handler_ctx.response = NULL; serf_connection_request_create(connection, s_setup_request, &handler_ctx); while (1) { rv = serf_context_run(context, SERF_DURATION_FOREVER, pool); if (APR_STATUS_IS_TIMEUP(rv)) continue; if (rv) { char buf[200]; ERR(r, "Error running context: (%d) %s\n", rv, apr_strerror(rv, buf, sizeof(buf))); break; } if (!apr_atomic_read32(&handler_ctx.requests_outstanding)) { if (handler_ctx.rv != APR_SUCCESS) { char buf[200]; ERR(r, "Error running context: (%d) %s\n", handler_ctx.rv, apr_strerror(handler_ctx.rv, buf, sizeof(buf))); } break; } } DBG(r,"REQ[%X] end of serf request",TO_ADDR(r)); DBG(r,"REQ[%X] response_code:[%d]", TO_ADDR(r),handler_ctx.response_code); DBG(r,"REQ[%X] response:[%s][%" APR_SIZE_T_FMT "]", TO_ADDR(r),handler_ctx.response, handler_ctx.response_len); serf_connection_close(connection); if (handler_ctx.response) { ret = apr_pstrdup(ppool, handler_ctx.response); } else { ret = apr_pstrdup(ppool, ""); } *response_code = handler_ctx.response_code; DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__); return handler_ctx.headers_out; }
char * default_chxj_serf_get(request_rec *r, apr_pool_t *ppool, const char *url_path, int set_headers_flag, apr_size_t *response_len) { apr_pool_t *pool; apr_uri_t url; apr_status_t rv; apr_sockaddr_t *address = NULL; serf_context_t *context; serf_connection_t *connection; app_ctx_t app_ctx; handler_ctx_t handler_ctx; char *ret; s_init(ppool, &pool); apr_uri_parse(pool, url_path, &url); if (!url.port) { url.port = apr_uri_port_of_scheme(url.scheme); } if (!url.port) { url.port = 80; } if (!url.path) { url.path = "/"; } if (!url.hostname) { url.hostname = "localhost"; } if (url.query) { url.path = apr_psprintf(pool, "%s?%s", url.path, url.query); } rv = apr_sockaddr_info_get(&address, url.hostname, APR_UNSPEC, url.port, 0, pool); if (rv != APR_SUCCESS) { char buf[256]; ERR(r, "REQ[%X] %s:%d apr_sockaddr_info_get() failed: rv:[%d|%s] - Please check DNS settings.", (unsigned int)(apr_size_t)r, __FILE__,__LINE__, rv, apr_strerror(rv, buf, 256)); return NULL; } memset(&app_ctx, 0, sizeof(app_ctx_t)); app_ctx.bkt_alloc = serf_bucket_allocator_create(pool, NULL, NULL); if (strcasecmp(url.scheme, "https") == 0) { app_ctx.ssl_flag = 1; } context = serf_context_create(pool); connection = serf_connection_create(context, address, s_connection_setup, &app_ctx, s_connection_closed, &app_ctx, pool); memset(&handler_ctx, 0, sizeof(handler_ctx_t)); handler_ctx.requests_outstanding = 0; handler_ctx.host = url.hostinfo; handler_ctx.method = "GET"; handler_ctx.path = url.path; handler_ctx.user_agent = (char *)apr_table_get(r->headers_in, CHXJ_HTTP_USER_AGENT); if (!handler_ctx.user_agent) { handler_ctx.user_agent = (char *)apr_table_get(r->headers_in, HTTP_USER_AGENT); } handler_ctx.post_data = NULL; handler_ctx.post_data_len = 0; handler_ctx.acceptor = s_accept_response; handler_ctx.acceptor_ctx = &app_ctx; handler_ctx.handler = s_handle_response; handler_ctx.pool = pool; handler_ctx.r = r; handler_ctx.response_len = 0; handler_ctx.response = NULL; serf_connection_request_create(connection, s_setup_request, &handler_ctx); while (1) { rv = serf_context_run(context, SERF_DURATION_FOREVER, pool); if (APR_STATUS_IS_TIMEUP(rv)) continue; if (rv) { char buf[200]; ERR(r, "Error running context: (%d) %s\n", rv, apr_strerror(rv, buf, sizeof(buf))); break; } if (!apr_atomic_read32(&handler_ctx.requests_outstanding)) { if (handler_ctx.rv != APR_SUCCESS) { char buf[200]; ERR(r, "Error running context: (%d) %s\n", handler_ctx.rv, apr_strerror(handler_ctx.rv, buf, sizeof(buf))); } break; } } serf_connection_close(connection); if (handler_ctx.response) { ret = apr_palloc(ppool, handler_ctx.response_len + 1); memset(ret, 0, handler_ctx.response_len + 1); memcpy(ret, handler_ctx.response, handler_ctx.response_len); } else { ret = apr_pstrdup(ppool, ""); } *response_len = handler_ctx.response_len; if (set_headers_flag) { r->headers_out = apr_table_copy(pool, handler_ctx.headers_out); *response_len = handler_ctx.response_len; char *contentType = (char *)apr_table_get(handler_ctx.headers_out, "Content-Type"); if (contentType) { chxj_set_content_type(r, contentType); } } return ret; }