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;
 }


Reply via email to