Author: rhuijben
Date: Mon Nov 16 21:46:50 2015
New Revision: 1714682
URL: http://svn.apache.org/viewvc?rev=1714682&view=rev
Log:
Combine the serf_get and serf_server test applications to a simple
serf_httpd application. This is an initial checkpoint.
* SConstruct
(TEST_PROGRAMS): Add serf_httpd.
* test/serf_httpd.c
New file.
Added:
serf/trunk/test/serf_httpd.c
- copied, changed from r1714545, serf/trunk/test/serf_server.c
Modified:
serf/trunk/SConstruct
Modified: serf/trunk/SConstruct
URL:
http://svn.apache.org/viewvc/serf/trunk/SConstruct?rev=1714682&r1=1714681&r2=1714682&view=diff
==============================================================================
--- serf/trunk/SConstruct (original)
+++ serf/trunk/SConstruct Mon Nov 16 21:46:50 2015
@@ -488,6 +488,7 @@ tenv.Replace(CFLAGS = [f.replace('-std=c
tenv.Append(CPPDEFINES=['MOCKHTTP_OPENSSL'])
TEST_PROGRAMS = [ 'serf_get', 'serf_response', 'serf_request', 'serf_spider',
+ 'serf_httpd',
'test_all', 'serf_bwtp' ]
if sys.platform == 'win32':
TEST_EXES = [ os.path.join('test', '%s.exe' % (prog)) for prog in
TEST_PROGRAMS ]
Copied: serf/trunk/test/serf_httpd.c (from r1714545,
serf/trunk/test/serf_server.c)
URL:
http://svn.apache.org/viewvc/serf/trunk/test/serf_httpd.c?p2=serf/trunk/test/serf_httpd.c&p1=serf/trunk/test/serf_server.c&r1=1714545&r2=1714682&rev=1714682&view=diff
==============================================================================
--- serf/trunk/test/serf_server.c (original)
+++ serf/trunk/test/serf_httpd.c Mon Nov 16 21:46:50 2015
@@ -30,87 +30,286 @@
#include "serf.h"
-typedef struct app_baton_t {
+typedef struct app_ctx_t {
int foo;
-} app_baton_t;
+ apr_pool_t *pool;
+} app_ctx_t;
+
+typedef struct listener_ctx_t {
+ app_ctx_t *app;
+ const char *proto;
+} listener_ctx_t;
+
+typedef struct client_ctx_t {
+ listener_ctx_t *listener;
+ apr_pool_t *pool;
+ serf_bucket_alloc_t *alloc;
+} client_ctx_t;
-static apr_status_t incoming_request(serf_context_t *ctx,
- serf_incoming_request_t *req,
- void *request_baton,
- apr_pool_t *pool)
+typedef struct request_ctx_t {
+ client_ctx_t *client;
+ apr_pool_t *pool;
+ serf_bucket_t *headers;
+ const char *method;
+ const char *path;
+ int http_version;
+} request_ctx_t;
+
+static apr_status_t client_setup(apr_socket_t *skt,
+ serf_bucket_t **read_bkt,
+ serf_bucket_t **write_bkt,
+ void *setup_baton,
+ apr_pool_t *pool)
{
- printf("INCOMING REQUEST\n");
+ client_ctx_t *cctx = setup_baton;
+ if (cctx->alloc == NULL)
+ cctx->alloc = serf_bucket_allocator_create(cctx->pool, NULL, NULL);
+
+ *read_bkt = serf_bucket_socket_create(skt, cctx->alloc);
return APR_SUCCESS;
}
+static apr_status_t client_closed(serf_incoming_t *incoming,
+ void *closed_baton,
+ apr_status_t why,
+ apr_pool_t *pool)
+{
+ client_ctx_t *cctx = closed_baton;
+ apr_pool_destroy(cctx->pool);
+ return APR_SUCCESS;
+}
+
+static apr_status_t request_handler(serf_incoming_request_t *req,
+ serf_bucket_t *request,
+ void *handler_baton,
+ apr_pool_t *pool)
+{
+ request_ctx_t *rctx = handler_baton;
+ apr_status_t status;
+
+ if (!rctx->method) {
+ status = serf_bucket_incoming_request_read(&rctx->headers,
+ &rctx->method,
+ &rctx->path,
+ &rctx->http_version,
+ request);
+ if (status) {
+ rctx->method = NULL;
+ return status;
+ }
+ }
+
+ status = serf_bucket_incoming_request_wait_for_headers(request);
+ if (status)
+ return status;
+
+ status = serf_incoming_response_create(req);
+ if (status)
+ return status;
+
+ do
+ {
+ const char *data;
+ apr_size_t len;
-static apr_status_t accept_fn(serf_context_t *ctx,
- serf_listener_t *l,
- void *baton,
- apr_socket_t *insock,
- apr_pool_t *pool)
-{
- serf_incoming_t *client = NULL;
- printf("new connection from \n");
- return serf_incoming_create(&client, ctx, insock, baton, incoming_request,
pool);
+ status = serf_bucket_read(request, SERF_READ_ALL_AVAIL, &data, &len);
+ } while (status == APR_SUCCESS);
+
+ return status;
}
-
-static void print_usage(apr_pool_t *pool)
+
+static apr_status_t request_generate_response(serf_bucket_t **resp_bkt,
+ serf_incoming_request_t *req,
+ void *setup_baton,
+ serf_bucket_alloc_t *alloc,
+ apr_pool_t *pool)
{
- puts("serf_server [options] listen_address:listen_port");
- puts("-h\tDisplay this help");
- puts("-v\tDisplay version");
+ request_ctx_t *rctx = setup_baton;
+ serf_bucket_t *agg = serf_bucket_aggregate_create(alloc);
+ serf_bucket_t *body;
+ serf_bucket_t *tmp;
+#define CRLF "\r\n"
+
+ tmp = SERF_BUCKET_SIMPLE_STRING("HTTP/1.1 200 OK" CRLF, alloc);
+ serf_bucket_aggregate_append(agg, tmp);
+
+ tmp = SERF_BUCKET_SIMPLE_STRING("Transfer-Encoding: chunked" CRLF, alloc);
+ serf_bucket_aggregate_append(agg, tmp);
+
+ tmp = SERF_BUCKET_SIMPLE_STRING("Content-Type: text/plain" CRLF, alloc);
+ serf_bucket_aggregate_append(agg, tmp);
+
+ tmp = SERF_BUCKET_SIMPLE_STRING(CRLF, alloc);
+ serf_bucket_aggregate_append(agg, tmp);
+
+ body = serf_bucket_aggregate_create(alloc);
+
+ if (rctx->method)
+ {
+ tmp = SERF_BUCKET_SIMPLE_STRING("Method: ", alloc);
+ serf_bucket_aggregate_append(body, tmp);
+
+ tmp = serf_bucket_simple_copy_create(rctx->method,
strlen(rctx->method), alloc);
+ serf_bucket_aggregate_append(body, tmp);
+
+ tmp = SERF_BUCKET_SIMPLE_STRING(CRLF "Path: ", alloc);
+ serf_bucket_aggregate_append(body, tmp);
+
+ tmp = serf_bucket_simple_copy_create(rctx->path, strlen(rctx->path),
alloc);
+ serf_bucket_aggregate_append(body, tmp);
+
+ tmp = SERF_BUCKET_SIMPLE_STRING(CRLF, alloc);
+ serf_bucket_aggregate_append(body, tmp);
+ }
+
+ tmp = SERF_BUCKET_SIMPLE_STRING(CRLF, alloc);
+ serf_bucket_aggregate_append(body, tmp);
+
+ tmp = serf_bucket_chunk_create(body, alloc);
+ serf_bucket_aggregate_append(agg, tmp);
+
+ tmp = SERF_BUCKET_SIMPLE_STRING(CRLF, alloc);
+ serf_bucket_aggregate_append(agg, tmp);
+
+ *resp_bkt = agg;
+ return APR_SUCCESS;
}
-int main(int argc, const char **argv)
+static apr_status_t client_request_acceptor(serf_bucket_t **req_bkt,
+ serf_bucket_t *stream,
+ serf_incoming_request_t *req,
+ void *request_baton,
+ serf_incoming_request_handler_t
*handler,
+ void **handler_baton,
+ serf_incoming_response_setup_t
*response_setup,
+ void **response_setup_baton,
+ apr_pool_t *pool)
{
- apr_status_t rv;
- apr_pool_t *pool;
- serf_context_t *context;
- serf_listener_t *listener;
- app_baton_t app_ctx;
- const char *listen_spec;
- char *addr = NULL;
- char *scope_id = NULL;
- apr_port_t port;
- apr_getopt_t *opt;
- char opt_c;
- const char *opt_arg;
+ client_ctx_t *cctx = request_baton;
+ apr_pool_t *request_pool;
+ request_ctx_t *rctx;
- apr_initialize();
- atexit(apr_terminate);
+ *req_bkt = serf_bucket_incoming_request_create(stream, stream->allocator);
- apr_pool_create(&pool, NULL);
+ apr_pool_create(&request_pool, cctx->pool);
- apr_getopt_init(&opt, pool, argc, argv);
+ rctx = apr_pcalloc(request_pool, sizeof(*rctx));
+ rctx->client = cctx;
- while ((rv = apr_getopt(opt, "hv", &opt_c, &opt_arg)) ==
- APR_SUCCESS) {
- switch (opt_c) {
- case 'h':
- print_usage(pool);
- exit(0);
- break;
- case 'v':
- puts("Serf version: " SERF_VERSION_STRING);
- exit(0);
- default:
- break;
+ *handler = request_handler;
+ *handler_baton = rctx;
+
+ *response_setup = request_generate_response;
+ *response_setup_baton = rctx;
+
+ return APR_SUCCESS;
+}
+
+
+static apr_status_t client_accept(serf_context_t *ctx,
+ serf_listener_t *l,
+ void *accept_baton,
+ apr_socket_t *insock,
+ apr_pool_t *pool)
+{
+ serf_incoming_t *incoming;
+ listener_ctx_t *lctx = accept_baton;
+ apr_pool_t *cctx_pool;
+ client_ctx_t *cctx;
+
+ apr_pool_create(&cctx_pool, pool);
+ cctx = apr_pcalloc(cctx_pool, sizeof(*cctx));
+ cctx->pool = cctx_pool;
+ cctx->listener = lctx;
+
+ return serf_incoming_create2(&incoming, ctx, insock,
+ client_setup, cctx,
+ client_closed, cctx,
+ client_request_acceptor, cctx,
+ pool);
+}
+
+
+/* Value for 'no short code' should be > 255 */
+#define CERTFILE 256
+#define CERTPWD 257
+#define HTTP2FLAG 258
+#define H2DIRECT 259
+
+static const apr_getopt_option_t options[] =
+{
+
+ { "help", 'h', 0, "Display this help" },
+ { NULL, 'v', 0, "Display version" },
+ { "listen", 'l', 1, "<[protocol,][host:]port> Configure listener"},
+/* { NULL, 'H', 0, "Print response headers" },
+ { NULL, 'n', 1, "<count> Fetch URL <count> times" },
+ { NULL, 'c', 1, "<count> Use <count> concurrent connections" },
+ { NULL, 'x', 1, "<count> Number of maximum outstanding requests
inflight" },
+ { "user", 'U', 1, "<user> Username for Basic/Digest authentication" },
+ { "pwd", 'P', 1, "<password> Password for Basic/Digest authentication"
},
+ { NULL, 'm', 1, "<method> Use the <method> HTTP Method" },
+ { NULL, 'f', 1, "<file> Use the <file> as the request body" },
+ { NULL, 'p', 1, "<hostname:port> Use the <host:port> as proxy server"
},
+ { "cert", CERTFILE, 1, "<file> Use SSL client certificate <file>" },
+ { "certpwd", CERTPWD, 1, "<password> Password for the SSL client
certificate" },
+ { NULL, 'r', 1, "<header:value> Use <header:value> as request header"
},
+ { "debug", 'd', 0, "Enable debugging" },
+ { "http2", HTTP2FLAG, 0, "Enable http2 (https only) (Experimental)" },
+ { "h2direct",H2DIRECT, 0, "Enable h2direct (Experimental)" },*/
+
+ { NULL, 0 }
+};
+
+static void print_usage(apr_pool_t *pool)
+{
+ int i = 0;
+
+ puts("serf_httpd [options] directory\n");
+ puts("Options:");
+
+ while (options[i].optch > 0) {
+ const apr_getopt_option_t* o = &options[i];
+
+ if (o->optch <= 255) {
+ printf(" -%c", o->optch);
+ if (o->name)
+ printf(", ");
+ }
+ else {
+ printf(" ");
}
- }
- if (opt->ind != opt->argc - 1) {
- print_usage(pool);
- exit(-1);
+ printf("%s%s\t%s\n",
+ o->name ? "--" : "\t",
+ o->name ? o->name : "",
+ o->description);
+
+ i++;
}
+}
+
+void configure_listener(serf_context_t *ctx,
+ app_ctx_t *app,
+ const char *arg,
+ apr_pool_t *pool)
+{
+ const char *listen_spec;
+ char *addr = NULL;
+ char *scope_id = NULL;
+ apr_port_t port;
+ apr_status_t status;
+ listener_ctx_t *lctx;
+ serf_listener_t *listener;
- listen_spec = argv[opt->ind];
+ char *comma = strchr(arg, ',');
+ listen_spec = comma ? comma + 1 : arg;
- rv = apr_parse_addr_port(&addr, &scope_id, &port, listen_spec, pool);
- if (rv) {
- printf("Error parsing listen address: %d\n", rv);
+ status = apr_parse_addr_port(&addr, &scope_id, &port, listen_spec, pool);
+ if (status) {
+ printf("Error parsing listen address: %s\n", listen_spec);
exit(1);
}
@@ -122,31 +321,86 @@ int main(int argc, const char **argv)
port = 8080;
}
- context = serf_context_create(pool);
+ lctx = apr_pcalloc(pool, sizeof(*lctx));
+ lctx->app = app;
+
+ if (comma)
+ lctx->proto = apr_pstrmemdup(pool, arg, comma - arg);
- /* TODO.... stuff */
- app_ctx.foo = 1;
- rv = serf_listener_create(&listener, context, addr, port,
- &app_ctx, accept_fn, pool);
- if (rv) {
- printf("Error parsing listener: %d\n", rv);
+ status = serf_listener_create(&listener, ctx, addr, port, lctx,
+ client_accept, pool);
+ if (status) {
+ printf("Error creating listener '%s': %d", listen_spec, status);
exit(1);
}
+}
+
+int main(int argc, const char **argv)
+{
+ apr_status_t status;
+ apr_pool_t *app_pool;
+ apr_pool_t *scratch_pool;
+ serf_context_t *context;
+ app_ctx_t app_ctx;
+ apr_getopt_t *opt;
+ int opt_c;
+ const char *opt_arg;
+ const char *root_dir;
+
+ apr_initialize();
+ atexit(apr_terminate);
+
+ apr_pool_create(&app_pool, NULL);
+ apr_pool_create(&scratch_pool, app_pool);
+
+ apr_getopt_init(&opt, scratch_pool, argc, argv);
+ context = serf_context_create(app_pool);
+
+ apr_getopt_init(&opt, scratch_pool, argc, argv);
+ while ((status = apr_getopt_long(opt, options, &opt_c, &opt_arg)) ==
+ APR_SUCCESS) {
+ switch (opt_c) {
+ case 'h':
+ print_usage(scratch_pool);
+ exit(0);
+ break;
+ case 'v':
+ puts("Serf version: " SERF_VERSION_STRING);
+ exit(0);
+ case 'l':
+ configure_listener(context, &app_ctx, opt_arg, app_pool);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (opt->ind != opt->argc - 1) {
+ print_usage(scratch_pool);
+ exit(-1);
+ }
+
+ root_dir = argv[opt->ind];
while (1) {
- rv = serf_context_run(context, SERF_DURATION_FOREVER, pool);
- if (APR_STATUS_IS_TIMEUP(rv))
+ apr_pool_clear(scratch_pool);
+ status = serf_context_run(context, SERF_DURATION_FOREVER,
scratch_pool);
+ if (APR_STATUS_IS_TIMEUP(status))
continue;
- if (rv) {
+ 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", rv,
- apr_strerror(rv, buf, sizeof(buf)));
- apr_pool_destroy(pool);
+ printf("Error running context: (%d) %s\n", status, err_string);
+ apr_pool_destroy(app_pool);
exit(1);
}
}
- apr_pool_destroy(pool);
+ apr_pool_destroy(app_pool);
return 0;
}