void serf_bucket_headers_setn( serf_bucket_t *headers_bucket, const char *header, const char *value) { serf_bucket_headers_setx(headers_bucket, header, strlen(header), 0, value, strlen(value), 0); }
/* This code should be replaced with header buckets. */ static apr_status_t fetch_headers(serf_bucket_t *bkt, response_context_t *ctx) { apr_status_t status; /* RFC 2616 says that CRLF is the only line ending, but we can easily * accept any kind of line ending. */ status = fetch_line(ctx, SERF_NEWLINE_ANY); if (SERF_BUCKET_READ_ERROR(status)) { return status; } /* Something was read. Process it. */ if (ctx->linebuf.state == SERF_LINEBUF_READY && ctx->linebuf.used) { const char *end_key; const char *c; end_key = c = memchr(ctx->linebuf.line, ':', ctx->linebuf.used); if (!c) { /* Bad headers? */ return SERF_ERROR_BAD_HTTP_RESPONSE; } /* Skip over initial ':' */ c++; /* And skip all whitespaces. */ for(; c < ctx->linebuf.line + ctx->linebuf.used; c++) { if (!apr_isspace(*c)) { break; } } /* Always copy the headers (from the linebuf into new mem). */ /* ### we should be able to optimize some mem copies */ serf_bucket_headers_setx( ctx->headers, ctx->linebuf.line, end_key - ctx->linebuf.line, 1, c, ctx->linebuf.line + ctx->linebuf.used - c, 1); } return status; }
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; }