OSDN Git Service

* update libserf-0.1.2 to libserf-0.2.0
authorkonn <konn@1a406e8e-add9-4483-a2c8-d8cac5b7c224>
Sat, 20 Sep 2008 15:20:21 +0000 (15:20 +0000)
committerkonn <konn@1a406e8e-add9-4483-a2c8-d8cac5b7c224>
Sat, 20 Sep 2008 15:20:21 +0000 (15:20 +0000)
git-svn-id: svn+ssh://svn.sourceforge.jp/svnroot/modchxj/mod_chxj/branches/RELEASE_0_12_0@3194 1a406e8e-add9-4483-a2c8-d8cac5b7c224

39 files changed:
src/serf/CHANGES
src/serf/Makefile [deleted file]
src/serf/Makefile.in
src/serf/buckets/aggregate_buckets.c
src/serf/buckets/buckets.c
src/serf/buckets/dechunk_buckets.c
src/serf/buckets/deflate_buckets.c
src/serf/buckets/headers_buckets.c
src/serf/buckets/request_buckets.c
src/serf/buckets/response_buckets.c
src/serf/buckets/simple_buckets.c
src/serf/buckets/socket_buckets.c
src/serf/buckets/ssl_buckets.c
src/serf/build/apr_common.m4
src/serf/build/find_apu.m4
src/serf/config.log [deleted file]
src/serf/config.nice [deleted file]
src/serf/config.status [deleted file]
src/serf/configure
src/serf/context.c
src/serf/serf.h
src/serf/serf.mak
src/serf/serf_bucket_types.h
src/serf/serfmake [changed mode: 0644->0755]
src/serf/test/CuTest-README.txt [new file with mode: 0644]
src/serf/test/CuTest.c [new file with mode: 0644]
src/serf/test/CuTest.h [new file with mode: 0644]
src/serf/test/serf_get.c
src/serf/test/serf_request.c
src/serf/test/serf_response.c
src/serf/test/serf_spider.c
src/serf/test/serftestca.pem [new file with mode: 0644]
src/serf/test/test_all.c [new file with mode: 0644]
src/serf/test/test_buckets.c [new file with mode: 0644]
src/serf/test/test_context.c [new file with mode: 0644]
src/serf/test/test_serf.h [new file with mode: 0644]
src/serf/test/test_ssl.c [new file with mode: 0644]
src/serf/test/test_util.c [new file with mode: 0644]
src/serf/test/testcases/deflate.response [new file with mode: 0644]

index 67ab2f5..af0f81e 100644 (file)
@@ -1,3 +1,23 @@
+Serf 0.2 [2008-06-06, r1188]
+  Enable use of external event loop: serf_create_context_ex.
+  Enable adding new requests at the beginning of the request queue.
+  Handle 'Connection:close' headers.
+  Enable limiting the number of outstanding requests.
+  Add readline function to simple buckets.
+  Concatenate repeated headers using comma as separator, as per RFC 2616,
+   section 4.2. (Issue 29)
+  Add proxy server support.
+  Add progress feedback support. (Issue 11)
+  Provide new API to simplify use of proxy and progress feedback support.
+  Add callback to validate SSL server certificates. (Issue 31)
+  Add new test framework.
+  Send current version string in the test programs (Issue 21)
+  Bugfixes:
+     Fix segfault with epoll when removing a NULL socket.
+     Reset OpenSSL thread-safety callbacks when apr_terminate() called.
+     Do not remove the socket from the pollset on pool cleanup.
+     Do not issue double close on skt w/second one being close(-1) (Issue 33)
+
 Serf 0.1.2 [2007-6-18, r1114]
   Enable thread-safety with OpenSSL (Issue 19)
   Teach serfmake to install headers into include/serf-0.
diff --git a/src/serf/Makefile b/src/serf/Makefile
deleted file mode 100644 (file)
index 07e2ac3..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-#
-# Makefile for Serf
-#
-srcdir = .
-
-
-SERF_MAJOR_VERSION=0
-SERF_DOTTED_VERSION=0.1.2
-
-OBJECTS = buckets/aggregate_buckets.lo buckets/request_buckets.lo context.lo \
-          buckets/buckets.lo buckets/simple_buckets.lo buckets/file_buckets.lo \
-          buckets/mmap_buckets.lo buckets/socket_buckets.lo \
-          buckets/response_buckets.lo buckets/headers_buckets.lo \
-          buckets/allocator.lo buckets/dechunk_buckets.lo \
-          buckets/deflate_buckets.lo buckets/limit_buckets.lo \
-          buckets/ssl_buckets.lo buckets/barrier_buckets.lo \
-          buckets/chunk_buckets.lo
-
-TARGET_LIB=libserf-$(SERF_MAJOR_VERSION).la
-
-TEST_OBJECTS = test/serf_get.lo test/serf_response.lo test/serf_request.lo \
-               test/serf_spider.lo
-PROGRAMS = $(TEST_OBJECTS:.lo=)
-
-TESTCASES = test/testcases/simple.response \
-  test/testcases/chunked-empty.response test/testcases/chunked.response \
-  test/testcases/chunked-trailers.response \
-  test/testcases/deflate.response
-
-HEADERS = serf.h serf_bucket_types.h serf_bucket_util.h serf_declare.h
-
-prefix=/usr/local/serf
-exec_prefix=${prefix}
-libdir=${exec_prefix}/lib
-includedir=${prefix}/include/serf-${SERF_MAJOR_VERSION}
-
-LIBTOOL = /usr/share/apr-1.0/build/libtool --silent
-CC = i486-linux-gnu-gcc
-CFLAGS = -fPIC -pipe -Wall -g -O2 -pthread
-CPPFLAGS =  -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE
-INCLUDES = -I$(srcdir) -I/usr/include/apr-1.0 -I/usr/include/apr-1.0 $(EXTRA_INCLUDES)
-MKDIR = mkdir -p
-INSTALL = /usr/bin/install -c
-
-LDFLAGS =  
-LIBS =  /usr/lib/libaprutil-1.la   /usr/lib/libapr-1.la -luuid -lrt -lcrypt  -lpthread -ldl -lz -lssl -lcrypto
-
-all: $(TARGET_LIB) $(PROGRAMS)
-
-context.lo: context.c $(HEADERS)
-buckets/aggregate_buckets.lo: buckets/aggregate_buckets.c $(HEADERS)
-buckets/request_buckets.lo: buckets/request_buckets.c $(HEADERS)
-buckets/buckets.lo: buckets/buckets.c $(HEADERS)
-buckets/simple_buckets.lo: buckets/simple_buckets.c $(HEADERS)
-buckets/file_buckets.lo: buckets/file_buckets.c $(HEADERS)
-buckets/mmap_buckets.lo: buckets/mmap_buckets.c $(HEADERS)
-buckets/socket_buckets.lo: buckets/socket_buckets.c $(HEADERS)
-buckets/response_buckets.lo: buckets/response_buckets.c $(HEADERS)
-buckets/headers_buckets.lo: buckets/headers_buckets.c $(HEADERS)
-buckets/allocator.lo: buckets/allocator.c $(HEADERS)
-buckets/dechunk_buckets.lo: buckets/dechunk_buckets.c $(HEADERS)
-buckets/deflate_buckets.lo: buckets/deflate_buckets.c $(HEADERS)
-buckets/limit_buckets.lo: buckets/limit_buckets.c $(HEADERS)
-buckets/ssl_buckets.lo: buckets/ssl_buckets.c $(HEADERS)
-buckets/barrier_buckets.lo: buckets/barrier_buckets.c $(HEADERS)
-buckets/chunk_buckets.lo: buckets/chunk_buckets.c $(HEADERS)
-
-test/serf_get.lo: test/serf_get.c $(HEADERS)
-test/serf_response.lo: test/serf_response.c $(HEADERS)
-test/serf_request.lo: test/serf_request.c $(HEADERS)
-test/serf_spider.lo: test/serf_spider.c $(HEADERS)
-
-$(TARGET_LIB): $(OBJECTS)
-       $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -rpath $(libdir) -o $@ $^ $(LIBS)
-
-test/serf_get: $(TARGET_LIB) test/serf_get.lo
-       $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -static -o $@ $^ $(LIBS)
-
-test/serf_response: $(TARGET_LIB) test/serf_response.lo
-       $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -static -o $@ $^ $(LIBS)
-
-test/serf_request: $(TARGET_LIB) test/serf_request.lo
-       $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -static -o $@ $^ $(LIBS)
-
-test/serf_spider: $(TARGET_LIB) test/serf_spider.lo
-       $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -static -o $@ $^ $(LIBS)
-
-
-check: test/serf_response
-       @for i in $(TESTCASES); \
-                do echo "== Testing $$i =="; \
-                ./test/serf_response $$i; \
-       done;
-
-install: $(TARGET_LIB)
-       $(MKDIR) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir)
-       $(LIBTOOL) --mode=install $(INSTALL) -m 644 $(TARGET_LIB) $(DESTDIR)$(libdir)
-       for i in $(srcdir)/*.h; do \
-               $(INSTALL) -m 644 $$i $(DESTDIR)$(includedir); \
-       done
-
-clean:
-       rm -f $(TARGET_LIB) $(OBJECTS) $(OBJECTS:.lo=.o) $(PROGRAMS) $(TEST_OBJECTS) $(TEST_OBJECTS:.lo=.o)
-       for subdir in . buckets test; do \
-               (cd $$subdir && rm -rf .libs) ; \
-       done
-
-distclean: clean
-       rm -f Makefile config.log config.status
-
-.SUFFIXES:
-.SUFFIXES: .c .lo .o
-
-mkdir-vpath:
-       @if [ ! -d buckets ]; then \
-               $(MKDIR) buckets; \
-       fi;
-       @if [ ! -d test ]; then \
-               $(MKDIR) test; \
-       fi;
-
-.c.lo:
-       $(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(CPPFLAGS) $(INCLUDES) -c -o $@ $< && touch $@
index 070202c..0811612 100644 (file)
@@ -20,7 +20,12 @@ TARGET_LIB=libserf-$(SERF_MAJOR_VERSION).la
 
 TEST_OBJECTS = test/serf_get.lo test/serf_response.lo test/serf_request.lo \
                test/serf_spider.lo
-PROGRAMS = $(TEST_OBJECTS:.lo=)
+
+TEST_SUITE_OBJECTS = test/CuTest.lo test/test_all.lo test/test_util.lo \
+                     test/test_buckets.lo test/test_context.lo \
+                     test/test_ssl.lo
+
+PROGRAMS = $(TEST_OBJECTS:.lo=) test/test_all
 
 TESTCASES = test/testcases/simple.response \
   test/testcases/chunked-empty.response test/testcases/chunked.response \
@@ -70,6 +75,13 @@ test/serf_response.lo: test/serf_response.c $(HEADERS)
 test/serf_request.lo: test/serf_request.c $(HEADERS)
 test/serf_spider.lo: test/serf_spider.c $(HEADERS)
 
+test/CuTest.lo: test/CuTest.c $(HEADERS)
+test/test_all.lo: test/test_all.c $(HEADERS)
+test/test_util.lo: test/test_util.c $(HEADERS)
+test/test_buckets.lo: test/test_buckets.c $(HEADERS)
+test/test_context.lo: test/test_context.c $(HEADERS)
+test/test_ssl.lo: test/test_ssl.c $(HEADERS)
+
 $(TARGET_LIB): $(OBJECTS)
        $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -rpath $(libdir) -o $@ $^ $(LIBS)
 
@@ -85,12 +97,16 @@ test/serf_request: $(TARGET_LIB) test/serf_request.lo
 test/serf_spider: $(TARGET_LIB) test/serf_spider.lo
        $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -static -o $@ $^ $(LIBS)
 
+test/test_all: $(TARGET_LIB) $(TEST_SUITE_OBJECTS)
+       $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -static -o $@ $^ $(LIBS)
 
-check: test/serf_response
+check: test/serf_response test/test_all
        @for i in $(TESTCASES); \
                 do echo "== Testing $$i =="; \
                 ./test/serf_response $$i; \
        done;
+       @echo "== Running test_all ==";
+       @./test/test_all
 
 install: $(TARGET_LIB)
        $(MKDIR) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir)
@@ -100,7 +116,7 @@ install: $(TARGET_LIB)
        done
 
 clean:
-       rm -f $(TARGET_LIB) $(OBJECTS) $(OBJECTS:.lo=.o) $(PROGRAMS) $(TEST_OBJECTS) $(TEST_OBJECTS:.lo=.o)
+       rm -f $(TARGET_LIB) $(OBJECTS) $(OBJECTS:.lo=.o) $(PROGRAMS) $(TEST_OBJECTS) $(TEST_OBJECTS:.lo=.o) $(TEST_SUITE_OBJECTS) $(TEST_SUITE_OBJECTS:.lo=.o)
        for subdir in . buckets test; do \
                (cd $$subdir && rm -rf .libs) ; \
        done
index 03690c9..015df43 100644 (file)
@@ -117,7 +117,7 @@ SERF_DECLARE(void) serf_bucket_aggregate_append(
     new_list->bucket = append_bucket;
     new_list->next = NULL;
 
-    /* If we use APR_RING, this is trivial.  So, wait. 
+    /* If we use APR_RING, this is trivial.  So, wait.
     new_list->next = ctx->list;
     ctx->list = new_list;
     */
index 96fd5bf..19b6120 100644 (file)
@@ -13,8 +13,6 @@
  * limitations under the License.
  */
 
-#include <stdlib.h>  /* for abort() */
-
 #include <apr_pools.h>
 
 #include "serf.h"
index 5251914..d78b7f4 100644 (file)
@@ -13,8 +13,6 @@
  * limitations under the License.
  */
 
-#include <stdlib.h>
-
 #include <apr_strings.h>
 
 #include "serf.h"
index b7e739c..a455a6a 100644 (file)
@@ -13,8 +13,6 @@
  * limitations under the License.
  */
 
-#include <stdlib.h>
-
 #include <apr_strings.h>
 
 #include <zlib.h>
@@ -360,16 +358,14 @@ static apr_status_t serf_deflate_read(serf_bucket_t *bucket,
 
 /* ### need to implement */
 #define serf_deflate_readline NULL
-#define serf_deflate_read_iovec NULL
-#define serf_deflate_read_for_sendfile NULL
 #define serf_deflate_peek NULL
 
 SERF_DECLARE_DATA const serf_bucket_type_t serf_bucket_type_deflate = {
     "DEFLATE",
     serf_deflate_read,
     serf_deflate_readline,
-    serf_deflate_read_iovec,
-    serf_deflate_read_for_sendfile,
+    serf_default_read_iovec,
+    serf_default_read_for_sendfile,
     serf_default_read_bucket,
     serf_deflate_peek,
     serf_deflate_destroy_and_data,
index e81dae4..a50ce9c 100644 (file)
@@ -71,9 +71,39 @@ SERF_DECLARE(void) serf_bucket_headers_setx(
     const char *value, apr_size_t value_size, int value_copy)
 {
     headers_context_t *ctx = bkt->data;
-    header_list_t *hdr = serf_bucket_mem_alloc(bkt->allocator, sizeof(*hdr));
+    header_list_t *found = ctx->list;
+    header_list_t *hdr;
 
-    /* ### should check if the header exists before adding. overwrite. */
+    /* Check to see if this header is already present. */
+    while (found) {
+      if (strncasecmp(found->header, header, header_size) == 0)
+            break;
+      found = found->next;
+    }
+
+    if (found) {
+
+        /* The header is already present.  RFC 2616, section 4.2
+           indicates that we should append the new value, separated by
+           a comma.  Reasoning: for headers whose values are known to
+           be comma-separated, that is clearly the correct behavior;
+           for others, the correct behavior is undefined anyway. */
+
+        /* The "+1" is for the comma; serf_bstrmemdup() will also add
+           one slot for the terminating '\0'. */
+        apr_size_t new_size = found->value_size + value_size + 1;
+        char *new_val = serf_bucket_mem_alloc(bkt->allocator, new_size);
+        memcpy(new_val, found->value, found->value_size);
+        new_val[found->value_size] = ',';
+        memcpy(new_val + found->value_size + 1, value, value_size);
+        new_val[new_size] = '\0';
+        found->value = new_val;
+        found->value_size = new_size;
+        found->alloc_flags |= ALLOC_VALUE;
+        return;
+    }
+
+    /* Else the header is not already present.  Add it to the bucket. */
 
 #if 0
     /* ### include this? */
@@ -83,6 +113,7 @@ SERF_DECLARE(void) serf_bucket_headers_setx(
     }
 #endif
 
+    hdr = serf_bucket_mem_alloc(bkt->allocator, sizeof(*hdr));
     hdr->header_size = header_size;
     hdr->value_size = value_size;
     hdr->alloc_flags = 0;
@@ -155,7 +186,7 @@ SERF_DECLARE(const char *) serf_bucket_headers_get(
 
 SERF_DECLARE(void) serf_bucket_headers_do(
     serf_bucket_t *headers_bucket,
-    serf_bucket_headers_do_callback_fn_t func, 
+    serf_bucket_headers_do_callback_fn_t func,
     void *baton)
 {
     headers_context_t *ctx = headers_bucket->data;
@@ -293,7 +324,7 @@ static apr_status_t serf_headers_read(serf_bucket_t *bucket,
     if (requested >= avail) {
         /* return everything from this chunk */
         *len = avail;
-        
+
         /* we consumed this chunk. advance the state. */
         return consume_chunk(ctx);
     }
index 733d090..935ef5d 100644 (file)
@@ -13,8 +13,6 @@
  * limitations under the License.
  */
 
-#include <stdlib.h>
-
 #include <apr_pools.h>
 #include <apr_strings.h>
 
@@ -52,6 +50,27 @@ SERF_DECLARE(serf_bucket_t *) serf_bucket_request_get_headers(
     return ((request_context_t *)bucket->data)->headers;
 }
 
+SERF_DECLARE(void) serf_bucket_request_set_root(
+    serf_bucket_t *bucket,
+    const char *root_url)
+{
+    request_context_t *ctx = (request_context_t *)bucket->data;
+
+    /* If uri is already absolute, don't change it. */
+    if (ctx->uri[0] != '/')
+        return;
+
+    /* If uri is '/' replace it with root_url. */
+    if (ctx->uri[1] == '\0')
+        ctx->uri = root_url;
+    else
+        ctx->uri =
+            apr_pstrcat(serf_bucket_allocator_get_pool(bucket->allocator),
+                        root_url,
+                        ctx->uri,
+                        NULL);
+}
+
 static void serialize_data(serf_bucket_t *bucket)
 {
     request_context_t *ctx = bucket->data;
index d3566a5..e5c8d7b 100644 (file)
@@ -13,8 +13,6 @@
  * limitations under the License.
  */
 
-#include <stdlib.h>
-
 #include <apr_lib.h>
 #include <apr_strings.h>
 #include <apr_date.h>
@@ -401,16 +399,14 @@ static apr_status_t serf_response_readline(serf_bucket_t *bucket,
 }
 
 /* ### need to implement */
-#define serf_response_read_iovec NULL
-#define serf_response_read_for_sendfile NULL
 #define serf_response_peek NULL
 
 SERF_DECLARE_DATA const serf_bucket_type_t serf_bucket_type_response = {
     "RESPONSE",
     serf_response_read,
     serf_response_readline,
-    serf_response_read_iovec,
-    serf_response_read_for_sendfile,
+    serf_default_read_iovec,
+    serf_default_read_for_sendfile,
     serf_default_read_bucket,
     serf_response_peek,
     serf_response_destroy_and_data,
index 60fab05..4c1f5ea 100644 (file)
@@ -92,8 +92,16 @@ static apr_status_t serf_simple_readline(serf_bucket_t *bucket,
                                          int acceptable, int *found,
                                          const char **data, apr_size_t *len)
 {
-    /* ### need our utility function... */
-    return APR_ENOTIMPL;
+    simple_context_t *ctx = bucket->data;
+
+    /* Returned data will be from current position. */
+    *data = ctx->current;
+    serf_util_readline(&ctx->current, &ctx->remaining, acceptable, found);
+
+    /* See how much ctx->current moved forward. */
+    *len = ctx->current - *data;
+
+    return ctx->remaining ? APR_SUCCESS : APR_EOF;
 }
 
 static apr_status_t serf_simple_peek(serf_bucket_t *bucket,
index 8c03062..7dc1fd0 100644 (file)
@@ -25,6 +25,9 @@ typedef struct {
 
     serf_databuf_t databuf;
 
+    /* Progress callback */
+    serf_progress_t progress_func;
+    void *progress_baton;
 } socket_context_t;
 
 
@@ -32,9 +35,15 @@ static apr_status_t socket_reader(void *baton, apr_size_t bufsize,
                                   char *buf, apr_size_t *len)
 {
     socket_context_t *ctx = baton;
+    apr_status_t status;
 
     *len = bufsize;
-    return apr_socket_recv(ctx->skt, buf, len);
+    status = apr_socket_recv(ctx->skt, buf, len);
+
+    if (ctx->progress_func)
+        ctx->progress_func(ctx->progress_baton, *len, 0);
+
+    return status;
 }
 
 SERF_DECLARE(serf_bucket_t *) serf_bucket_socket_create(
@@ -51,9 +60,21 @@ SERF_DECLARE(serf_bucket_t *) serf_bucket_socket_create(
     ctx->databuf.read = socket_reader;
     ctx->databuf.read_baton = ctx;
 
+    ctx->progress_func = ctx->progress_baton = NULL;
     return serf_bucket_create(&serf_bucket_type_socket, allocator, ctx);
 }
 
+SERF_DECLARE(void) serf_bucket_socket_set_read_progress_cb(
+    serf_bucket_t *bucket,
+    const serf_progress_t progress_func,
+    void *progress_baton)
+{
+    socket_context_t *ctx = bucket->data;
+
+    ctx->progress_func = progress_func;
+    ctx->progress_baton = progress_baton;
+}
+
 static apr_status_t serf_socket_read(serf_bucket_t *bucket,
                                      apr_size_t requested,
                                      const char **data, apr_size_t *len)
index 7541e99..1904479 100644 (file)
@@ -148,10 +148,16 @@ struct serf_ssl_context_t {
     apr_pool_t *cert_pw_cache_pool;
     const char *cert_pw_success;
 
+    /* Server cert callbacks */
+    serf_ssl_need_server_cert_t server_cert_callback;
+    void *server_cert_userdata;
+
     const char *cert_path;
 
     X509 *cached_cert;
     EVP_PKEY *cached_cert_pw;
+
+    apr_status_t pending_err;
 };
 
 typedef struct {
@@ -165,6 +171,9 @@ typedef struct {
     serf_bucket_t **our_stream;
 } ssl_context_t;
 
+struct serf_ssl_certificate_t {
+    X509 *ssl_cert;
+};
 
 /* Returns the amount read. */
 static int bio_bucket_read(BIO *bio, char *in, int inlen)
@@ -225,7 +234,6 @@ static int bio_bucket_write(BIO *bio, const char *in, int inl)
 static int bio_file_read(BIO *bio, char *in, int inlen)
 {
     apr_file_t *file = bio->ptr;
-    const char *data;
     apr_status_t status;
     apr_size_t len;
 
@@ -335,6 +343,80 @@ static BIO_METHOD bio_file_method = {
 #endif
 };
 
+static int
+validate_server_certificate(int cert_valid, X509_STORE_CTX *store_ctx)
+{
+    SSL *ssl;
+    serf_ssl_context_t *ctx;
+    X509 *server_cert;
+    int err, depth;
+    int failures = 0;
+
+    ssl = X509_STORE_CTX_get_ex_data(store_ctx,
+                                     SSL_get_ex_data_X509_STORE_CTX_idx());
+    ctx = SSL_get_app_data(ssl);
+
+    server_cert = X509_STORE_CTX_get_current_cert(store_ctx);
+    depth = X509_STORE_CTX_get_error_depth(store_ctx);
+
+    /* If the certification was found invalid, get the error and convert it to
+       something our caller will understand. */
+    if (! cert_valid) {
+        err = X509_STORE_CTX_get_error(store_ctx);
+
+        switch(err) {
+            case X509_V_ERR_CERT_NOT_YET_VALID:
+                    failures |= SERF_SSL_CERT_NOTYETVALID;
+                    break;
+            case X509_V_ERR_CERT_HAS_EXPIRED:
+                    failures |= SERF_SSL_CERT_EXPIRED;
+                    break;
+            case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+            case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+                    failures |= SERF_SSL_CERT_SELF_SIGNED;
+                    break;
+            case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+                    failures |= SERF_SSL_CERT_UNKNOWNCA;
+                    break;
+            default:
+                    failures |= SERF_SSL_CERT_UNKNOWN_FAILURE;
+                    break;
+        }
+    }
+
+    /* Check certificate expiry dates. */
+    if (X509_cmp_current_time(X509_get_notBefore(server_cert)) >= 0) {
+        failures |= SERF_SSL_CERT_NOTYETVALID;
+    }
+    else if (X509_cmp_current_time(X509_get_notAfter(server_cert)) <= 0) {
+        failures |= SERF_SSL_CERT_EXPIRED;
+    }
+
+    if (ctx->server_cert_callback &&
+        (depth == 0 || failures)) {
+        apr_status_t status;
+        serf_ssl_certificate_t *cert;
+        apr_pool_t *subpool;
+
+        apr_pool_create(&subpool, ctx->pool);
+
+        cert = apr_palloc(subpool, sizeof(serf_ssl_certificate_t));
+        cert->ssl_cert = server_cert;
+
+        /* Callback for further verification. */
+        status = ctx->server_cert_callback(ctx->server_cert_userdata,
+                                           failures, cert);
+        if (status == APR_SUCCESS)
+            cert_valid = 1;
+        else
+            /* Pass the error back to the caller through the context-run. */
+            ctx->pending_err = status;
+        apr_pool_destroy(subpool);
+    }
+
+    return cert_valid;
+}
+
 /* This function reads an encrypted stream and returns the decrypted stream. */
 static apr_status_t ssl_decrypt(void *baton, apr_size_t bufsize,
                                 char *buf, apr_size_t *len)
@@ -386,6 +468,11 @@ static apr_status_t ssl_decrypt(void *baton, apr_size_t bufsize,
                 *len = 0;
                 status = APR_EAGAIN;
                 break;
+            case SSL_ERROR_SSL:
+                *len = 0;
+                status = ctx->pending_err;
+                ctx->pending_err = 0;
+                break;
             default:
                 *len = 0;
                 status = APR_EGENERAL;
@@ -571,6 +658,18 @@ static unsigned long ssl_id(void)
     /* FIXME: This is lame and not portable. -aaron */
     return (unsigned long) apr_os_thread_current();
 }
+
+static apr_status_t cleanup_ssl(void *data)
+{
+    CRYPTO_set_locking_callback(NULL);
+    CRYPTO_set_id_callback(NULL);
+    CRYPTO_set_dynlock_create_callback(NULL);
+    CRYPTO_set_dynlock_lock_callback(NULL);
+    CRYPTO_set_dynlock_destroy_callback(NULL);
+
+    return APR_SUCCESS;
+}
+
 #endif
 
 static int have_init_ssl = 0;
@@ -606,6 +705,8 @@ static void init_ssl_libraries(void)
         CRYPTO_set_dynlock_create_callback(ssl_dyn_create);
         CRYPTO_set_dynlock_lock_callback(ssl_dyn_lock);
         CRYPTO_set_dynlock_destroy_callback(ssl_dyn_destroy);
+
+        apr_pool_cleanup_register(ssl_pool, NULL, cleanup_ssl, cleanup_ssl);
 #endif
 
         have_init_ssl = 1;
@@ -769,6 +870,15 @@ serf_ssl_client_cert_password_set(serf_ssl_context_t *context,
     }
 }
 
+SERF_DECLARE(void)
+serf_ssl_server_cert_callback_set(serf_ssl_context_t *context,
+                                  serf_ssl_need_server_cert_t callback,
+                                  void *data)
+{
+    context->server_cert_callback = callback;
+    context->server_cert_userdata = data;
+}
+
 static serf_ssl_context_t *ssl_init_context(void)
 {
     serf_ssl_context_t *ssl_ctx;
@@ -792,6 +902,8 @@ static serf_ssl_context_t *ssl_init_context(void)
     ssl_ctx->cached_cert = 0;
     ssl_ctx->cached_cert_pw = 0;
 
+    SSL_CTX_set_verify(ssl_ctx->ctx, SSL_VERIFY_PEER,
+                       validate_server_certificate);
     SSL_CTX_set_options(ssl_ctx->ctx, SSL_OP_ALL);
 
     ssl_ctx->ssl = SSL_new(ssl_ctx->ctx);
@@ -866,6 +978,47 @@ static serf_bucket_t * serf_bucket_ssl_create(
     return serf_bucket_create(type, allocator, ctx);
 }
 
+SERF_DECLARE(apr_status_t)
+serf_ssl_use_default_certificates(serf_ssl_context_t *ssl_ctx)
+{
+    X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx->ctx);
+
+    int result = X509_STORE_set_default_paths(store);
+
+    return result ? APR_SUCCESS : APR_EGENERAL;
+}
+
+SERF_DECLARE(apr_status_t)
+serf_ssl_load_cert_file(serf_ssl_certificate_t **cert, const char *file_path,
+                        apr_pool_t *pool)
+{
+    FILE *fp = fopen(file_path, "r");
+
+    if (fp) {
+        X509 *ssl_cert = PEM_read_X509(fp, NULL, NULL, NULL);
+        fclose(fp);
+
+        if (ssl_cert) {
+            *cert = apr_palloc(pool, sizeof(serf_ssl_certificate_t));
+            (*cert)->ssl_cert = ssl_cert;
+
+            return APR_SUCCESS;
+        }
+    }
+
+    return APR_EGENERAL;
+}
+
+SERF_DECLARE(apr_status_t)
+serf_ssl_trust_cert(serf_ssl_context_t *ssl_ctx, serf_ssl_certificate_t *cert)
+{
+    X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx->ctx);
+
+    int result = X509_STORE_add_cert(store, cert->ssl_cert);
+
+    return result ? APR_SUCCESS : APR_EGENERAL;
+}
+
 SERF_DECLARE(serf_bucket_t *) serf_bucket_ssl_decrypt_create(
     serf_bucket_t *stream,
     serf_ssl_context_t *ssl_ctx,
@@ -947,6 +1100,131 @@ SERF_DECLARE(serf_ssl_context_t *) serf_bucket_ssl_encrypt_context_get(
     return ctx->ssl_ctx;
 }
 
+/* Functions to read a serf_ssl_certificate structure. */
+
+/* Creates a hash_table with keys (E, CN, OU, O, L, ST and C). */
+static apr_hash_t *
+convert_X509_NAME_to_table(X509_NAME *org, apr_pool_t *pool)
+{
+    char buf[1024];
+    int ret;
+
+    apr_hash_t *tgt = apr_hash_make(pool);
+
+    ret = X509_NAME_get_text_by_NID(org,
+                                    NID_commonName,
+                                    buf, 1024);
+    if (ret != -1)
+        apr_hash_set(tgt, "CN", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf));
+    ret = X509_NAME_get_text_by_NID(org,
+                                    NID_pkcs9_emailAddress,
+                                    buf, 1024);
+    if (ret != -1)
+        apr_hash_set(tgt, "E", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf));
+    ret = X509_NAME_get_text_by_NID(org,
+                                    NID_organizationalUnitName,
+                                    buf, 1024);
+    if (ret != -1)
+        apr_hash_set(tgt, "OU", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf));
+    ret = X509_NAME_get_text_by_NID(org,
+                                    NID_organizationName,
+                                    buf, 1024);
+    if (ret != -1)
+        apr_hash_set(tgt, "O", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf));
+    ret = X509_NAME_get_text_by_NID(org,
+                                    NID_localityName,
+                                    buf, 1024);
+    if (ret != -1)
+        apr_hash_set(tgt, "L", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf));
+    ret = X509_NAME_get_text_by_NID(org,
+                                    NID_stateOrProvinceName,
+                                    buf, 1024);
+    if (ret != -1)
+        apr_hash_set(tgt, "ST", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf));
+    ret = X509_NAME_get_text_by_NID(org,
+                                    NID_countryName,
+                                    buf, 1024);
+    if (ret != -1)
+        apr_hash_set(tgt, "C", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf));
+
+    return tgt;
+}
+
+SERF_DECLARE(apr_hash_t *)
+serf_ssl_cert_issuer(const serf_ssl_certificate_t *cert, apr_pool_t *pool)
+{
+
+    X509_NAME *issuer = X509_get_issuer_name(cert->ssl_cert);
+    if (!issuer)
+        return NULL;
+
+    return convert_X509_NAME_to_table(issuer, pool);
+}
+
+SERF_DECLARE(apr_hash_t *)
+serf_ssl_cert_subject(const serf_ssl_certificate_t *cert, apr_pool_t *pool)
+{
+
+    X509_NAME *subject = X509_get_subject_name(cert->ssl_cert);
+    if (!subject)
+        return NULL;
+
+    return convert_X509_NAME_to_table(subject, pool);
+}
+
+SERF_DECLARE(apr_hash_t *)
+serf_ssl_cert_certificate(const serf_ssl_certificate_t *cert, apr_pool_t *pool)
+{
+    apr_hash_t *tgt = apr_hash_make(pool);
+    unsigned int md_size, i;
+    unsigned char md[EVP_MAX_MD_SIZE];
+    BIO *bio;
+
+    /* sha1 fingerprint */
+    if (X509_digest(cert->ssl_cert, EVP_sha1(), md, &md_size)) {
+        const char hex[] = "0123456789ABCDEF";
+        char fingerprint[EVP_MAX_MD_SIZE * 3];
+
+        for (i=0; i<md_size; i++) {
+            fingerprint[3*i] = hex[(md[i] & 0xf0) >> 4];
+            fingerprint[(3*i)+1] = hex[(md[i] & 0x0f)];
+            fingerprint[(3*i)+2] = ':';
+        }
+        if (md_size > 0)
+            fingerprint[(3*(md_size-1))+2] = '\0';
+        else
+            fingerprint[0] = '\0';
+
+        apr_hash_set(tgt, "sha1", APR_HASH_KEY_STRING,
+                     apr_pstrdup(pool, fingerprint));
+    }
+
+    /* set expiry dates */
+    bio = BIO_new(BIO_s_mem());
+    if (bio) {
+        ASN1_TIME *notBefore, *notAfter;
+        char buf[256];
+
+        memset (buf, 0, sizeof (buf));
+        notBefore = X509_get_notBefore(cert->ssl_cert);
+        if (ASN1_TIME_print(bio, notBefore)) {
+            BIO_read(bio, buf, 255);
+            apr_hash_set(tgt, "notBefore", APR_HASH_KEY_STRING,
+                         apr_pstrdup(pool, buf));
+        }
+        memset (buf, 0, sizeof (buf));
+        notAfter = X509_get_notAfter(cert->ssl_cert);
+        if (ASN1_TIME_print(bio, notAfter)) {
+            BIO_read(bio, buf, 255);
+            apr_hash_set(tgt, "notAfter", APR_HASH_KEY_STRING,
+                         apr_pstrdup(pool, buf));
+        }
+    }
+    BIO_free(bio);
+
+    return tgt;
+}
+
 static void serf_ssl_destroy_and_data(serf_bucket_t *bucket)
 {
     ssl_context_t *ctx = bucket->data;
index 1c17591..2afb466 100644 (file)
@@ -161,8 +161,8 @@ changequote([, ])dnl
   # autoconf doesn't add --silent to ac_configure_args; explicitly pass it
   test "x$silent" = "xyes" && apr_configure_args="$apr_configure_args --silent"
 
-  dnl The eval makes quoting arguments work - specifically $2 where the
-  dnl quoting mechanisms used is "" rather than [].
+  dnl The eval makes quoting arguments work - specifically the second argument
+  dnl where the quoting mechanisms used is "" rather than [].
   dnl
   dnl We need to execute another shell because some autoconf/shell combinations
   dnl will choke after doing repeated APR_SUBDIR_CONFIG()s.  (Namely Solaris
@@ -959,3 +959,18 @@ fi
 
 AC_SUBST(MKDEP)
 ])
+
+dnl
+dnl APR_CHECK_TYPES_COMPATIBLE(TYPE-1, TYPE-2, [ACTION-IF-TRUE])
+dnl
+dnl Try to determine whether two types are the same. Only works
+dnl for gcc and icc.
+dnl
+AC_DEFUN([APR_CHECK_TYPES_COMPATIBLE], [
+define([apr_cvname], apr_cv_typematch_[]translit([$1], [ ], [_])_[]translit([$2], [ ], [_]))
+AC_CACHE_CHECK([whether $1 and $2 are the same], apr_cvname, [
+AC_TRY_COMPILE(AC_INCLUDES_DEFAULT, [
+    int foo[0 - !__builtin_types_compatible_p($1, $2)];
+], [apr_cvname=yes
+$3], [apr_cvname=no])])
+])
index 6654162..dfa4e0e 100644 (file)
@@ -1,10 +1,10 @@
 dnl -------------------------------------------------------- -*- autoconf -*-
-dnl Copyright 2002-2005 The Apache Software Foundation or its licensors, as
-dnl applicable.
-dnl
-dnl Licensed under the Apache License, Version 2.0 (the "License");
-dnl you may not use this file except in compliance with the License.
-dnl You may obtain a copy of the License at
+dnl Licensed to the Apache Software Foundation (ASF) under one or more
+dnl contributor license agreements.  See the NOTICE file distributed with
+dnl this work for additional information regarding copyright ownership.
+dnl The ASF licenses this file to You under the Apache License, Version 2.0
+dnl (the "License"); you may not use this file except in compliance with
+dnl the License.  You may obtain a copy of the License at
 dnl
 dnl     http://www.apache.org/licenses/LICENSE-2.0
 dnl
diff --git a/src/serf/config.log b/src/serf/config.log
deleted file mode 100644 (file)
index 991987a..0000000
+++ /dev/null
@@ -1,418 +0,0 @@
-This file contains any messages produced by compilers while
-running configure, to aid debugging if configure makes a mistake.
-
-It was created by configure, which was
-generated by GNU Autoconf 2.60.  Invocation command line was
-
-  $ ./configure --enable-shared --with-apr=/usr/bin --with-apr-util=/usr/bin
-
-## --------- ##
-## Platform. ##
-## --------- ##
-
-hostname = oregano
-uname -m = i686
-uname -r = 2.4.18-bf2.4-xfs
-uname -s = Linux
-uname -v = #1 Son Jul 14 09:40:39 CEST 2002
-
-/usr/bin/uname -p = unknown
-/bin/uname -X     = unknown
-
-/bin/arch              = i686
-/usr/bin/arch -k       = unknown
-/usr/convex/getsysinfo = unknown
-/usr/bin/hostinfo      = unknown
-/bin/machine           = unknown
-/usr/bin/oslevel       = unknown
-/bin/universe          = unknown
-
-PATH: /usr/lib/oracle/xe/app/oracle/product/10.2.0/server/bin
-PATH: /usr/local/ant/bin
-PATH: /usr/local/jdk6/bin
-PATH: /usr/local/jdk6/jre/bin
-PATH: /usr/local/mysql/bin
-PATH: /usr/local/mysql/bin
-PATH: /usr/local/samba/bin
-PATH: /usr/local/bin
-PATH: /usr/bin
-PATH: /bin
-PATH: /usr/bin/X11
-PATH: /usr/games
-PATH: /usr/local/ant/bin
-PATH: /usr/local/ant/bin
-PATH: /usr/local/ant/bin
-PATH: /usr/local/jdk6/bin
-PATH: /home/konno/work/bin
-
-
-## ----------- ##
-## Core tests. ##
-## ----------- ##
-
-configure:1895: checking for chosen layout
-configure:1897: result: Serf
-configure:2091: checking for working mkdir -p
-configure:2107: result: yes
-configure:2125: checking build system type
-configure:2143: result: i686-pc-linux-gnu
-configure:2165: checking host system type
-configure:2180: result: i686-pc-linux-gnu
-configure:2202: checking target system type
-configure:2217: result: i686-pc-linux-gnu
-configure:2275: checking for APR
-configure:2360: result: yes
-configure:2637: checking for APR-util
-configure:2722: result: yes
-configure:2972: checking for gcc
-configure:2999: result: i486-linux-gnu-gcc
-configure:3237: checking for C compiler version
-configure:3244: i486-linux-gnu-gcc --version >&5
-i486-linux-gnu-gcc (GCC) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)
-Copyright (C) 2006 Free Software Foundation, Inc.
-This is free software; see the source for copying conditions.  There is NO
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-configure:3247: $? = 0
-configure:3254: i486-linux-gnu-gcc -v >&5
-Using built-in specs.
-Target: i486-linux-gnu
-Configured with: ../src/configure -v --enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --program-suffix=-4.1 --enable-__cxa_atexit --enable-clocale=gnu --enable-libstdcxx-debug --enable-mpfr --with-tune=i686 --enable-checking=release i486-linux-gnu
-Thread model: posix
-gcc version 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)
-configure:3257: $? = 0
-configure:3264: i486-linux-gnu-gcc -V >&5
-i486-linux-gnu-gcc: '-V' option must have argument
-configure:3267: $? = 1
-configure:3290: checking for C compiler default output file name
-configure:3317: i486-linux-gnu-gcc -fPIC -pipe -Wall -g -O2 -pthread  -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE   conftest.c  >&5
-configure:3320: $? = 0
-configure:3366: result: a.out
-configure:3371: checking whether the C compiler works
-configure:3381: ./a.out
-configure:3384: $? = 0
-configure:3401: result: yes
-configure:3408: checking whether we are cross compiling
-configure:3410: result: no
-configure:3413: checking for suffix of executables
-configure:3420: i486-linux-gnu-gcc -o conftest -fPIC -pipe -Wall -g -O2 -pthread  -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE   conftest.c  >&5
-configure:3423: $? = 0
-configure:3447: result: 
-configure:3453: checking for suffix of object files
-configure:3479: i486-linux-gnu-gcc -c -fPIC -pipe -Wall -g -O2 -pthread  -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE conftest.c >&5
-configure:3482: $? = 0
-configure:3505: result: o
-configure:3509: checking whether we are using the GNU C compiler
-configure:3538: i486-linux-gnu-gcc -c -fPIC -pipe -Wall -g -O2 -pthread  -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE conftest.c >&5
-configure:3544: $? = 0
-configure:3551: test -z "$ac_c_werror_flag" || test ! -s conftest.err
-configure:3554: $? = 0
-configure:3561: test -s conftest.o
-configure:3564: $? = 0
-configure:3578: result: yes
-configure:3583: checking whether i486-linux-gnu-gcc accepts -g
-configure:3613: i486-linux-gnu-gcc -c -g  -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE conftest.c >&5
-configure:3619: $? = 0
-configure:3626: test -z "$ac_c_werror_flag" || test ! -s conftest.err
-configure:3629: $? = 0
-configure:3636: test -s conftest.o
-configure:3639: $? = 0
-configure:3769: result: yes
-configure:3786: checking for i486-linux-gnu-gcc option to accept ISO C89
-configure:3860: i486-linux-gnu-gcc  -c -fPIC -pipe -Wall -g -O2 -pthread  -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE conftest.c >&5
-configure:3866: $? = 0
-configure:3873: test -z "$ac_c_werror_flag" || test ! -s conftest.err
-configure:3876: $? = 0
-configure:3883: test -s conftest.o
-configure:3886: $? = 0
-configure:3906: result: none needed
-configure:3929: checking how to run the C preprocessor
-configure:4059: result: i486-linux-gnu-gcc -E
-configure:4088: i486-linux-gnu-gcc -E  -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE conftest.c
-configure:4094: $? = 0
-configure:4132: i486-linux-gnu-gcc -E  -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE conftest.c
-conftest.c:8:28: error: ac_nonexistent.h: No such file or directory
-configure:4138: $? = 1
-configure: failed program was:
-| /* confdefs.h.  */
-| #define PACKAGE_NAME ""
-| #define PACKAGE_TARNAME ""
-| #define PACKAGE_VERSION ""
-| #define PACKAGE_STRING ""
-| #define PACKAGE_BUGREPORT ""
-| /* end confdefs.h.  */
-| #include <ac_nonexistent.h>
-configure:4195: checking for a BSD-compatible install
-configure:4251: result: /usr/bin/install -c
-configure:4372: checking for grep that handles long lines and -e
-configure:4446: result: /bin/grep
-configure:4451: checking for egrep
-configure:4529: result: /bin/grep -E
-configure:4534: checking for ANSI C header files
-configure:4564: i486-linux-gnu-gcc -c -fPIC -pipe -Wall -g -O2 -pthread  -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE conftest.c >&5
-configure:4570: $? = 0
-configure:4577: test -z "$ac_c_werror_flag" || test ! -s conftest.err
-configure:4580: $? = 0
-configure:4587: test -s conftest.o
-configure:4590: $? = 0
-configure:4686: i486-linux-gnu-gcc -o conftest -fPIC -pipe -Wall -g -O2 -pthread  -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE   conftest.c  >&5
-configure:4689: $? = 0
-configure:4695: ./conftest
-configure:4698: $? = 0
-configure:4715: result: yes
-configure:4739: checking for sys/types.h
-configure:4760: i486-linux-gnu-gcc -c -fPIC -pipe -Wall -g -O2 -pthread  -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE conftest.c >&5
-configure:4766: $? = 0
-configure:4773: test -z "$ac_c_werror_flag" || test ! -s conftest.err
-configure:4776: $? = 0
-configure:4783: test -s conftest.o
-configure:4786: $? = 0
-configure:4799: result: yes
-configure:4739: checking for sys/stat.h
-configure:4760: i486-linux-gnu-gcc -c -fPIC -pipe -Wall -g -O2 -pthread  -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE conftest.c >&5
-configure:4766: $? = 0
-configure:4773: test -z "$ac_c_werror_flag" || test ! -s conftest.err
-configure:4776: $? = 0
-configure:4783: test -s conftest.o
-configure:4786: $? = 0
-configure:4799: result: yes
-configure:4739: checking for stdlib.h
-configure:4760: i486-linux-gnu-gcc -c -fPIC -pipe -Wall -g -O2 -pthread  -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE conftest.c >&5
-configure:4766: $? = 0
-configure:4773: test -z "$ac_c_werror_flag" || test ! -s conftest.err
-configure:4776: $? = 0
-configure:4783: test -s conftest.o
-configure:4786: $? = 0
-configure:4799: result: yes
-configure:4739: checking for string.h
-configure:4760: i486-linux-gnu-gcc -c -fPIC -pipe -Wall -g -O2 -pthread  -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE conftest.c >&5
-configure:4766: $? = 0
-configure:4773: test -z "$ac_c_werror_flag" || test ! -s conftest.err
-configure:4776: $? = 0
-configure:4783: test -s conftest.o
-configure:4786: $? = 0
-configure:4799: result: yes
-configure:4739: checking for memory.h
-configure:4760: i486-linux-gnu-gcc -c -fPIC -pipe -Wall -g -O2 -pthread  -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE conftest.c >&5
-configure:4766: $? = 0
-configure:4773: test -z "$ac_c_werror_flag" || test ! -s conftest.err
-configure:4776: $? = 0
-configure:4783: test -s conftest.o
-configure:4786: $? = 0
-configure:4799: result: yes
-configure:4739: checking for strings.h
-configure:4760: i486-linux-gnu-gcc -c -fPIC -pipe -Wall -g -O2 -pthread  -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE conftest.c >&5
-configure:4766: $? = 0
-configure:4773: test -z "$ac_c_werror_flag" || test ! -s conftest.err
-configure:4776: $? = 0
-configure:4783: test -s conftest.o
-configure:4786: $? = 0
-configure:4799: result: yes
-configure:4739: checking for inttypes.h
-configure:4760: i486-linux-gnu-gcc -c -fPIC -pipe -Wall -g -O2 -pthread  -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE conftest.c >&5
-configure:4766: $? = 0
-configure:4773: test -z "$ac_c_werror_flag" || test ! -s conftest.err
-configure:4776: $? = 0
-configure:4783: test -s conftest.o
-configure:4786: $? = 0
-configure:4799: result: yes
-configure:4739: checking for stdint.h
-configure:4760: i486-linux-gnu-gcc -c -fPIC -pipe -Wall -g -O2 -pthread  -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE conftest.c >&5
-configure:4766: $? = 0
-configure:4773: test -z "$ac_c_werror_flag" || test ! -s conftest.err
-configure:4776: $? = 0
-configure:4783: test -s conftest.o
-configure:4786: $? = 0
-configure:4799: result: yes
-configure:4739: checking for unistd.h
-configure:4760: i486-linux-gnu-gcc -c -fPIC -pipe -Wall -g -O2 -pthread  -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE conftest.c >&5
-configure:4766: $? = 0
-configure:4773: test -z "$ac_c_werror_flag" || test ! -s conftest.err
-configure:4776: $? = 0
-configure:4783: test -s conftest.o
-configure:4786: $? = 0
-configure:4799: result: yes
-configure:4821: checking openssl/opensslv.h usability
-configure:4838: i486-linux-gnu-gcc -c -fPIC -pipe -Wall -g -O2 -pthread  -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE conftest.c >&5
-configure:4844: $? = 0
-configure:4851: test -z "$ac_c_werror_flag" || test ! -s conftest.err
-configure:4854: $? = 0
-configure:4861: test -s conftest.o
-configure:4864: $? = 0
-configure:4875: result: yes
-configure:4879: checking openssl/opensslv.h presence
-configure:4894: i486-linux-gnu-gcc -E  -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE conftest.c
-configure:4900: $? = 0
-configure:4921: result: yes
-configure:4949: checking for openssl/opensslv.h
-configure:4956: result: yes
-configure:5129: creating ./config.status
-
-## ---------------------- ##
-## Running config.status. ##
-## ---------------------- ##
-
-This file was extended by config.status, which was
-generated by GNU Autoconf 2.60.  Invocation command line was
-
-  CONFIG_FILES    = 
-  CONFIG_HEADERS  = 
-  CONFIG_LINKS    = 
-  CONFIG_COMMANDS = 
-  $ ./config.status 
-
-on oregano
-
-config.status:598: creating Makefile
-config.status:783: executing mkdir-vpath commands
-
-## ---------------- ##
-## Cache variables. ##
-## ---------------- ##
-
-ac_cv_build=i686-pc-linux-gnu
-ac_cv_c_compiler_gnu=yes
-ac_cv_env_CC_set=
-ac_cv_env_CC_value=
-ac_cv_env_CFLAGS_set=set
-ac_cv_env_CFLAGS_value=-fPIC
-ac_cv_env_CPPFLAGS_set=
-ac_cv_env_CPPFLAGS_value=
-ac_cv_env_CPP_set=
-ac_cv_env_CPP_value=
-ac_cv_env_LDFLAGS_set=
-ac_cv_env_LDFLAGS_value=
-ac_cv_env_build_alias_set=
-ac_cv_env_build_alias_value=
-ac_cv_env_host_alias_set=
-ac_cv_env_host_alias_value=
-ac_cv_env_target_alias_set=
-ac_cv_env_target_alias_value=
-ac_cv_header_inttypes_h=yes
-ac_cv_header_memory_h=yes
-ac_cv_header_openssl_opensslv_h=yes
-ac_cv_header_stdc=yes
-ac_cv_header_stdint_h=yes
-ac_cv_header_stdlib_h=yes
-ac_cv_header_string_h=yes
-ac_cv_header_strings_h=yes
-ac_cv_header_sys_stat_h=yes
-ac_cv_header_sys_types_h=yes
-ac_cv_header_unistd_h=yes
-ac_cv_host=i686-pc-linux-gnu
-ac_cv_mkdir_p=yes
-ac_cv_objext=o
-ac_cv_path_EGREP='/bin/grep -E'
-ac_cv_path_GREP=/bin/grep
-ac_cv_path_install='/usr/bin/install -c'
-ac_cv_prog_CPP='i486-linux-gnu-gcc -E'
-ac_cv_prog_ac_ct_CC=i486-linux-gnu-gcc
-ac_cv_prog_cc_c89=
-ac_cv_prog_cc_g=yes
-ac_cv_target=i686-pc-linux-gnu
-
-## ----------------- ##
-## Output variables. ##
-## ----------------- ##
-
-APR_BINDIR='/usr/bin'
-APR_CONFIG='/usr/bin/apr-config'
-APR_INCLUDEDIR='/usr/include/apr-1.0'
-APR_LIBTOOL='/usr/share/apr-1.0/build/libtool'
-APR_VERSION='1.2.7'
-APU_BINDIR='/usr/bin'
-APU_CONFIG='/usr/bin/apu-1-config'
-APU_INCLUDEDIR='/usr/include/apr-1.0'
-APU_VERSION='1.2.7'
-CC='i486-linux-gnu-gcc'
-CFLAGS='-fPIC -pipe -Wall -g -O2 -pthread'
-CPP='i486-linux-gnu-gcc -E'
-CPPFLAGS=' -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE'
-DEFS='-DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1'
-ECHO_C=''
-ECHO_N='-n'
-ECHO_T=''
-EGREP='/bin/grep -E'
-EXEEXT=''
-GREP='/bin/grep'
-INSTALL_DATA='${INSTALL} -m 644'
-INSTALL_PROGRAM='${INSTALL}'
-INSTALL_SCRIPT='${INSTALL}'
-LDFLAGS=' '
-LIBOBJS=''
-LIBS=''
-LTLIBOBJS=''
-OBJEXT='o'
-PACKAGE_BUGREPORT=''
-PACKAGE_NAME=''
-PACKAGE_STRING=''
-PACKAGE_TARNAME=''
-PACKAGE_VERSION=''
-PATH_SEPARATOR=':'
-SERF_BUILD_SRCLIB_DIRS=''
-SERF_CLEAN_SRCLIB_DIRS=''
-SERF_DOTTED_VERSION='0.1.2'
-SERF_LIBS=' /usr/lib/libaprutil-1.la   /usr/lib/libapr-1.la -luuid -lrt -lcrypt  -lpthread -ldl'
-SERF_MAJOR_VERSION='0'
-SHELL='/bin/sh'
-ac_ct_CC='i486-linux-gnu-gcc'
-bindir='${exec_prefix}/bin'
-build='i686-pc-linux-gnu'
-build_alias=''
-build_cpu='i686'
-build_os='linux-gnu'
-build_vendor='pc'
-datadir='${prefix}'
-datarootdir='${prefix}/share'
-docdir='${datarootdir}/doc/${PACKAGE}'
-dvidir='${docdir}'
-exec_prefix='${prefix}'
-host='i686-pc-linux-gnu'
-host_alias=''
-host_cpu='i686'
-host_os='linux-gnu'
-host_vendor='pc'
-htmldir='${docdir}'
-includedir='${prefix}/include/serf-${SERF_MAJOR_VERSION}'
-infodir='${datarootdir}/info'
-libdir='${exec_prefix}/lib'
-libexecdir='${exec_prefix}/modules'
-localedir='${datarootdir}/locale'
-localstatedir='${prefix}'
-mandir='${prefix}/man'
-mkdir_p='mkdir -p'
-oldincludedir='/usr/include'
-pdfdir='${docdir}'
-prefix='/usr/local/serf'
-program_transform_name='s,x,x,'
-psdir='${docdir}'
-sbindir='${exec_prefix}/bin'
-sharedstatedir='${prefix}/com'
-sysconfdir='${prefix}/conf'
-target='i686-pc-linux-gnu'
-target_alias=''
-target_cpu='i686'
-target_os='linux-gnu'
-target_vendor='pc'
-
-## ----------- ##
-## confdefs.h. ##
-## ----------- ##
-
-#define PACKAGE_NAME ""
-#define PACKAGE_TARNAME ""
-#define PACKAGE_VERSION ""
-#define PACKAGE_STRING ""
-#define PACKAGE_BUGREPORT ""
-#define STDC_HEADERS 1
-#define HAVE_SYS_TYPES_H 1
-#define HAVE_SYS_STAT_H 1
-#define HAVE_STDLIB_H 1
-#define HAVE_STRING_H 1
-#define HAVE_MEMORY_H 1
-#define HAVE_STRINGS_H 1
-#define HAVE_INTTYPES_H 1
-#define HAVE_STDINT_H 1
-#define HAVE_UNISTD_H 1
-
-configure: exit 0
diff --git a/src/serf/config.nice b/src/serf/config.nice
deleted file mode 100755 (executable)
index 19c6651..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#! /bin/sh
-#
-# Created by configure
-
-CFLAGS="-fPIC"; export CFLAGS
-"./configure" \
-"--enable-shared" \
-"--with-apr=/usr/bin" \
-"--with-apr-util=/usr/bin" \
-"CFLAGS=-fPIC" \
-"$@"
diff --git a/src/serf/config.status b/src/serf/config.status
deleted file mode 100755 (executable)
index ef75fb9..0000000
+++ /dev/null
@@ -1,796 +0,0 @@
-#! /bin/sh
-# Generated by configure.
-# Run this file to recreate the current configuration.
-# Compiler output produced by configure, useful for debugging
-# configure, is in config.log if it exists.
-
-debug=false
-ac_cs_recheck=false
-ac_cs_silent=false
-SHELL=${CONFIG_SHELL-/bin/sh}
-## --------------------- ##
-## M4sh Initialization.  ##
-## --------------------- ##
-
-# Be Bourne compatible
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
-  emulate sh
-  NULLCMD=:
-  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
-  # is contrary to our usage.  Disable this feature.
-  alias -g '${1+"$@"}'='"$@"'
-  setopt NO_GLOB_SUBST
-else
-  case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
-fi
-BIN_SH=xpg4; export BIN_SH # for Tru64
-DUALCASE=1; export DUALCASE # for MKS sh
-
-
-# PATH needs CR
-# Avoid depending upon Character Ranges.
-as_cr_letters='abcdefghijklmnopqrstuvwxyz'
-as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-as_cr_Letters=$as_cr_letters$as_cr_LETTERS
-as_cr_digits='0123456789'
-as_cr_alnum=$as_cr_Letters$as_cr_digits
-
-# The user is always right.
-if test "${PATH_SEPARATOR+set}" != set; then
-  echo "#! /bin/sh" >conf$$.sh
-  echo  "exit 0"   >>conf$$.sh
-  chmod +x conf$$.sh
-  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
-    PATH_SEPARATOR=';'
-  else
-    PATH_SEPARATOR=:
-  fi
-  rm -f conf$$.sh
-fi
-
-# Support unset when possible.
-if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
-  as_unset=unset
-else
-  as_unset=false
-fi
-
-
-# IFS
-# We need space, tab and new line, in precisely that order.  Quoting is
-# there to prevent editors from complaining about space-tab.
-# (If _AS_PATH_WALK were called with IFS unset, it would disable word
-# splitting by setting IFS to empty value.)
-as_nl='
-'
-IFS=" ""       $as_nl"
-
-# Find who we are.  Look in the path if we contain no directory separator.
-case $0 in
-  *[\\/]* ) as_myself=$0 ;;
-  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
-done
-IFS=$as_save_IFS
-
-     ;;
-esac
-# We did not find ourselves, most probably we were run as `sh COMMAND'
-# in which case we are not to be found in the path.
-if test "x$as_myself" = x; then
-  as_myself=$0
-fi
-if test ! -f "$as_myself"; then
-  echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
-  { (exit 1); exit 1; }
-fi
-
-# Work around bugs in pre-3.0 UWIN ksh.
-for as_var in ENV MAIL MAILPATH
-do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
-done
-PS1='$ '
-PS2='> '
-PS4='+ '
-
-# NLS nuisances.
-for as_var in \
-  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
-  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
-  LC_TELEPHONE LC_TIME
-do
-  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
-    eval $as_var=C; export $as_var
-  else
-    ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
-  fi
-done
-
-# Required to use basename.
-if expr a : '\(a\)' >/dev/null 2>&1 &&
-   test "X`expr 00001 : '.*\(...\)'`" = X001; then
-  as_expr=expr
-else
-  as_expr=false
-fi
-
-if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
-  as_basename=basename
-else
-  as_basename=false
-fi
-
-
-# Name of the executable.
-as_me=`$as_basename -- "$0" ||
-$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
-        X"$0" : 'X\(//\)$' \| \
-        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
-echo X/"$0" |
-    sed '/^.*\/\([^/][^/]*\)\/*$/{
-           s//\1/
-           q
-         }
-         /^X\/\(\/\/\)$/{
-           s//\1/
-           q
-         }
-         /^X\/\(\/\).*/{
-           s//\1/
-           q
-         }
-         s/.*/./; q'`
-
-# CDPATH.
-$as_unset CDPATH
-
-
-
-  as_lineno_1=$LINENO
-  as_lineno_2=$LINENO
-  test "x$as_lineno_1" != "x$as_lineno_2" &&
-  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
-
-  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
-  # uniformly replaced by the line number.  The first 'sed' inserts a
-  # line-number line after each line using $LINENO; the second 'sed'
-  # does the real work.  The second script uses 'N' to pair each
-  # line-number line with the line containing $LINENO, and appends
-  # trailing '-' during substitution so that $LINENO is not a special
-  # case at line end.
-  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
-  # scripts with optimization help from Paolo Bonzini.  Blame Lee
-  # E. McMahon (1931-1989) for sed's syntax.  :-)
-  sed -n '
-    p
-    /[$]LINENO/=
-  ' <$as_myself |
-    sed '
-      s/[$]LINENO.*/&-/
-      t lineno
-      b
-      :lineno
-      N
-      :loop
-      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
-      t loop
-      s/-\n.*//
-    ' >$as_me.lineno &&
-  chmod +x "$as_me.lineno" ||
-    { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
-   { (exit 1); exit 1; }; }
-
-  # Don't try to exec as it changes $[0], causing all sort of problems
-  # (the dirname of $[0] is not the place where we might find the
-  # original and so on.  Autoconf is especially sensitive to this).
-  . "./$as_me.lineno"
-  # Exit status is that of the last command.
-  exit
-}
-
-
-if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
-  as_dirname=dirname
-else
-  as_dirname=false
-fi
-
-ECHO_C= ECHO_N= ECHO_T=
-case `echo -n x` in
--n*)
-  case `echo 'x\c'` in
-  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
-  *)   ECHO_C='\c';;
-  esac;;
-*)
-  ECHO_N='-n';;
-esac
-
-if expr a : '\(a\)' >/dev/null 2>&1 &&
-   test "X`expr 00001 : '.*\(...\)'`" = X001; then
-  as_expr=expr
-else
-  as_expr=false
-fi
-
-rm -f conf$$ conf$$.exe conf$$.file
-if test -d conf$$.dir; then
-  rm -f conf$$.dir/conf$$.file
-else
-  rm -f conf$$.dir
-  mkdir conf$$.dir
-fi
-echo >conf$$.file
-if ln -s conf$$.file conf$$ 2>/dev/null; then
-  as_ln_s='ln -s'
-  # ... but there are two gotchas:
-  # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
-  # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
-  # In both cases, we have to default to `cp -p'.
-  ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
-    as_ln_s='cp -p'
-elif ln conf$$.file conf$$ 2>/dev/null; then
-  as_ln_s=ln
-else
-  as_ln_s='cp -p'
-fi
-rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
-rmdir conf$$.dir 2>/dev/null
-
-if mkdir -p . 2>/dev/null; then
-  as_mkdir_p=:
-else
-  test -d ./-p && rmdir ./-p
-  as_mkdir_p=false
-fi
-
-# Find out whether ``test -x'' works.  Don't use a zero-byte file, as
-# systems may use methods other than mode bits to determine executability.
-cat >conf$$.file <<_ASEOF
-#! /bin/sh
-exit 0
-_ASEOF
-chmod +x conf$$.file
-if test -x conf$$.file >/dev/null 2>&1; then
-  as_executable_p="test -x"
-else
-  as_executable_p=:
-fi
-rm -f conf$$.file
-
-# Sed expression to map a string onto a valid CPP name.
-as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
-
-# Sed expression to map a string onto a valid variable name.
-as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
-
-
-exec 6>&1
-
-# Save the log message, to keep $[0] and so on meaningful, and to
-# report actual input values of CONFIG_FILES etc. instead of their
-# values after options handling.
-ac_log="
-This file was extended by $as_me, which was
-generated by GNU Autoconf 2.60.  Invocation command line was
-
-  CONFIG_FILES    = $CONFIG_FILES
-  CONFIG_HEADERS  = $CONFIG_HEADERS
-  CONFIG_LINKS    = $CONFIG_LINKS
-  CONFIG_COMMANDS = $CONFIG_COMMANDS
-  $ $0 $@
-
-on `(hostname || uname -n) 2>/dev/null | sed 1q`
-"
-
-# Files that config.status was made for.
-config_files=" Makefile"
-config_commands=" mkdir-vpath"
-
-ac_cs_usage="\
-\`$as_me' instantiates files from templates according to the
-current configuration.
-
-Usage: $0 [OPTIONS] [FILE]...
-
-  -h, --help       print this help, then exit
-  -V, --version    print version number, then exit
-  -q, --quiet      do not print progress messages
-  -d, --debug      don't remove temporary files
-      --recheck    update $as_me by reconfiguring in the same conditions
-  --file=FILE[:TEMPLATE]
-                  instantiate the configuration file FILE
-
-Configuration files:
-$config_files
-
-Configuration commands:
-$config_commands
-
-Report bugs to <bug-autoconf@gnu.org>."
-
-ac_cs_version="\
-config.status
-configured by ./configure, generated by GNU Autoconf 2.60,
-  with options \"'--enable-shared' '--with-apr=/usr/bin' '--with-apr-util=/usr/bin' 'CFLAGS=-fPIC'\"
-
-Copyright (C) 2006 Free Software Foundation, Inc.
-This config.status script is free software; the Free Software Foundation
-gives unlimited permission to copy, distribute and modify it."
-
-ac_pwd='/home/konno/work/mod_chxj/mod_chxj/src/serf'
-srcdir='.'
-INSTALL='/usr/bin/install -c'
-# If no file are specified by the user, then we need to provide default
-# value.  By we need to know if files were specified by the user.
-ac_need_defaults=:
-while test $# != 0
-do
-  case $1 in
-  --*=*)
-    ac_option=`expr "X$1" : 'X\([^=]*\)='`
-    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
-    ac_shift=:
-    ;;
-  *)
-    ac_option=$1
-    ac_optarg=$2
-    ac_shift=shift
-    ;;
-  esac
-
-  case $ac_option in
-  # Handling of the options.
-  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
-    ac_cs_recheck=: ;;
-  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
-    echo "$ac_cs_version"; exit ;;
-  --debug | --debu | --deb | --de | --d | -d )
-    debug=: ;;
-  --file | --fil | --fi | --f )
-    $ac_shift
-    CONFIG_FILES="$CONFIG_FILES $ac_optarg"
-    ac_need_defaults=false;;
-  --he | --h |  --help | --hel | -h )
-    echo "$ac_cs_usage"; exit ;;
-  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
-  | -silent | --silent | --silen | --sile | --sil | --si | --s)
-    ac_cs_silent=: ;;
-
-  # This is an error.
-  -*) { echo "$as_me: error: unrecognized option: $1
-Try \`$0 --help' for more information." >&2
-   { (exit 1); exit 1; }; } ;;
-
-  *) ac_config_targets="$ac_config_targets $1"
-     ac_need_defaults=false ;;
-
-  esac
-  shift
-done
-
-ac_configure_extra_args=
-
-if $ac_cs_silent; then
-  exec 6>/dev/null
-  ac_configure_extra_args="$ac_configure_extra_args --silent"
-fi
-
-if $ac_cs_recheck; then
-  echo "running CONFIG_SHELL=/bin/sh /bin/sh ./configure " '--enable-shared' '--with-apr=/usr/bin' '--with-apr-util=/usr/bin' 'CFLAGS=-fPIC' $ac_configure_extra_args " --no-create --no-recursion" >&6
-  CONFIG_SHELL=/bin/sh
-  export CONFIG_SHELL
-  exec /bin/sh "./configure" '--enable-shared' '--with-apr=/usr/bin' '--with-apr-util=/usr/bin' 'CFLAGS=-fPIC' $ac_configure_extra_args --no-create --no-recursion
-fi
-
-exec 5>>config.log
-{
-  echo
-  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
-## Running $as_me. ##
-_ASBOX
-  echo "$ac_log"
-} >&5
-
-
-# Handling of arguments.
-for ac_config_target in $ac_config_targets
-do
-  case $ac_config_target in
-    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
-    "mkdir-vpath") CONFIG_COMMANDS="$CONFIG_COMMANDS mkdir-vpath" ;;
-
-  *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
-echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
-   { (exit 1); exit 1; }; };;
-  esac
-done
-
-
-# If the user did not use the arguments to specify the items to instantiate,
-# then the envvar interface is used.  Set only those that are not.
-# We use the long form for the default assignment because of an extremely
-# bizarre bug on SunOS 4.1.3.
-if $ac_need_defaults; then
-  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
-  test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
-fi
-
-# Have a temporary directory for convenience.  Make it in the build tree
-# simply because there is no reason against having it here, and in addition,
-# creating and moving files from /tmp can sometimes cause problems.
-# Hook for its removal unless debugging.
-# Note that there is a small window in which the directory will not be cleaned:
-# after its creation but before its name has been assigned to `$tmp'.
-$debug ||
-{
-  tmp=
-  trap 'exit_status=$?
-  { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
-' 0
-  trap '{ (exit 1); exit 1; }' 1 2 13 15
-}
-# Create a (secure) tmp directory for tmp files.
-
-{
-  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
-  test -n "$tmp" && test -d "$tmp"
-}  ||
-{
-  tmp=./conf$$-$RANDOM
-  (umask 077 && mkdir "$tmp")
-} ||
-{
-   echo "$me: cannot create a temporary directory in ." >&2
-   { (exit 1); exit 1; }
-}
-
-#
-# Set up the sed scripts for CONFIG_FILES section.
-#
-
-# No need to generate the scripts if there are no CONFIG_FILES.
-# This happens for instance when ./config.status config.h
-if test -n "$CONFIG_FILES"; then
-
-cat >"$tmp/subs-1.sed" <<\CEOF
-/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end
-s,@SHELL@,|#_!!_#|/bin/sh,g
-s,@PATH_SEPARATOR@,|#_!!_#|:,g
-s,@PACKAGE_NAME@,|#_!!_#|,g
-s,@PACKAGE_TARNAME@,|#_!!_#|,g
-s,@PACKAGE_VERSION@,|#_!!_#|,g
-s,@PACKAGE_STRING@,|#_!!_#|,g
-s,@PACKAGE_BUGREPORT@,|#_!!_#|,g
-s,@exec_prefix@,|#_!!_#|${prefix},g
-s,@prefix@,|#_!!_#|/usr/local/serf,g
-s,@program_transform_name@,|#_!!_#|s\,x\,x\,,g
-s,@bindir@,|#_!!_#|${exec_prefix}/bin,g
-s,@sbindir@,|#_!!_#|${exec_prefix}/bin,g
-s,@libexecdir@,|#_!!_#|${exec_prefix}/modules,g
-s,@datarootdir@,|#_!!_#|${prefix}/share,g
-s,@datadir@,|#_!!_#|${prefix},g
-s,@sysconfdir@,|#_!!_#|${prefix}/conf,g
-s,@sharedstatedir@,|#_!!_#|${prefix}/com,g
-s,@localstatedir@,|#_!!_#|${prefix},g
-s,@includedir@,|#_!!_#|${prefix}/include/serf-${SERF_MAJOR_VERSION},g
-s,@oldincludedir@,|#_!!_#|/usr/include,g
-s,@docdir@,|#_!!_#|${datarootdir}/doc/${PACKAGE},g
-s,@infodir@,|#_!!_#|${datarootdir}/info,g
-s,@htmldir@,|#_!!_#|${docdir},g
-s,@dvidir@,|#_!!_#|${docdir},g
-s,@pdfdir@,|#_!!_#|${docdir},g
-s,@psdir@,|#_!!_#|${docdir},g
-s,@libdir@,|#_!!_#|${exec_prefix}/lib,g
-s,@localedir@,|#_!!_#|${datarootdir}/locale,g
-s,@mandir@,|#_!!_#|${prefix}/man,g
-s,@DEFS@,|#_!!_#|-DPACKAGE_NAME=\\"\\" -DPACKAGE_TARNAME=\\"\\" -DPACKAGE_VERSION=\\"\\" -DPACKAGE_STRING=\\"\\" -DPACKAGE_BUGREPORT=\\"\\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1,g
-s,@ECHO_C@,|#_!!_#|,g
-s,@ECHO_N@,|#_!!_#|-n,g
-s,@ECHO_T@,|#_!!_#|,g
-s,@LIBS@,|#_!!_#|,g
-s,@build_alias@,|#_!!_#|,g
-s,@host_alias@,|#_!!_#|,g
-s,@target_alias@,|#_!!_#|,g
-s,@mkdir_p@,|#_!!_#|mkdir -p,g
-s,@build@,|#_!!_#|i686-pc-linux-gnu,g
-s,@build_cpu@,|#_!!_#|i686,g
-s,@build_vendor@,|#_!!_#|pc,g
-s,@build_os@,|#_!!_#|linux-gnu,g
-s,@host@,|#_!!_#|i686-pc-linux-gnu,g
-s,@host_cpu@,|#_!!_#|i686,g
-s,@host_vendor@,|#_!!_#|pc,g
-s,@host_os@,|#_!!_#|linux-gnu,g
-s,@target@,|#_!!_#|i686-pc-linux-gnu,g
-s,@target_cpu@,|#_!!_#|i686,g
-s,@target_vendor@,|#_!!_#|pc,g
-s,@target_os@,|#_!!_#|linux-gnu,g
-s,@APR_LIBTOOL@,|#_!!_#|/usr/share/apr-1.0/build/libtool,g
-s,@APR_BINDIR@,|#_!!_#|/usr/bin,g
-s,@APR_INCLUDEDIR@,|#_!!_#|/usr/include/apr-1.0,g
-s,@APR_VERSION@,|#_!!_#|1.2.7,g
-s,@APR_CONFIG@,|#_!!_#|/usr/bin/apr-config,g
-s,@APU_BINDIR@,|#_!!_#|/usr/bin,g
-s,@APU_INCLUDEDIR@,|#_!!_#|/usr/include/apr-1.0,g
-s,@APU_VERSION@,|#_!!_#|1.2.7,g
-s,@APU_CONFIG@,|#_!!_#|/usr/bin/apu-1-config,g
-s,@CC@,|#_!!_#|i486-linux-gnu-gcc,g
-s,@CFLAGS@,|#_!!_#|-fPIC -pipe -Wall -g -O2 -pthread,g
-s,@LDFLAGS@,|#_!!_#| ,g
-s,@CPPFLAGS@,|#_!!_#| -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE,g
-s,@ac_ct_CC@,|#_!!_#|i486-linux-gnu-gcc,g
-s,@EXEEXT@,|#_!!_#|,g
-s,@OBJEXT@,|#_!!_#|o,g
-s,@CPP@,|#_!!_#|i486-linux-gnu-gcc -E,g
-s,@INSTALL_PROGRAM@,|#_!!_#|${INSTALL},g
-s,@INSTALL_SCRIPT@,|#_!!_#|${INSTALL},g
-s,@INSTALL_DATA@,|#_!!_#|${INSTALL} -m 644,g
-s,@SERF_MAJOR_VERSION@,|#_!!_#|0,g
-s,@SERF_DOTTED_VERSION@,|#_!!_#|0.1.2,g
-s,@SERF_BUILD_SRCLIB_DIRS@,|#_!!_#|,g
-s,@SERF_CLEAN_SRCLIB_DIRS@,|#_!!_#|,g
-s,@GREP@,|#_!!_#|/bin/grep,g
-s,@EGREP@,|#_!!_#|/bin/grep -E,g
-s,@SERF_LIBS@,|#_!!_#| /usr/lib/libaprutil-1.la   /usr/lib/libapr-1.la -luuid -lrt -lcrypt  -lpthread -ldl,g
-s,@LIBOBJS@,|#_!!_#|,g
-s,@LTLIBOBJS@,|#_!!_#|,g
-:end
-s/|#_!!_#|//g
-CEOF
-fi # test -n "$CONFIG_FILES"
-
-
-for ac_tag in  :F $CONFIG_FILES      :C $CONFIG_COMMANDS
-do
-  case $ac_tag in
-  :[FHLC]) ac_mode=$ac_tag; continue;;
-  esac
-  case $ac_mode$ac_tag in
-  :[FHL]*:*);;
-  :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5
-echo "$as_me: error: Invalid tag $ac_tag." >&2;}
-   { (exit 1); exit 1; }; };;
-  :[FH]-) ac_tag=-:-;;
-  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
-  esac
-  ac_save_IFS=$IFS
-  IFS=:
-  set x $ac_tag
-  IFS=$ac_save_IFS
-  shift
-  ac_file=$1
-  shift
-
-  case $ac_mode in
-  :L) ac_source=$1;;
-  :[FH])
-    ac_file_inputs=
-    for ac_f
-    do
-      case $ac_f in
-      -) ac_f="$tmp/stdin";;
-      *) # Look for the file first in the build tree, then in the source tree
-        # (if the path is not absolute).  The absolute path cannot be DOS-style,
-        # because $ac_f cannot contain `:'.
-        test -f "$ac_f" ||
-          case $ac_f in
-          [\\/$]*) false;;
-          *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
-          esac ||
-          { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5
-echo "$as_me: error: cannot find input file: $ac_f" >&2;}
-   { (exit 1); exit 1; }; };;
-      esac
-      ac_file_inputs="$ac_file_inputs $ac_f"
-    done
-
-    # Let's still pretend it is `configure' which instantiates (i.e., don't
-    # use $as_me), people would be surprised to read:
-    #    /* config.h.  Generated by config.status.  */
-    configure_input="Generated from "`IFS=:
-         echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure."
-    if test x"$ac_file" != x-; then
-      configure_input="$ac_file.  $configure_input"
-      { echo "$as_me:$LINENO: creating $ac_file" >&5
-echo "$as_me: creating $ac_file" >&6;}
-    fi
-
-    case $ac_tag in
-    *:-:* | *:-) cat >"$tmp/stdin";;
-    esac
-    ;;
-  esac
-
-  ac_dir=`$as_dirname -- "$ac_file" ||
-$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-        X"$ac_file" : 'X\(//\)[^/]' \| \
-        X"$ac_file" : 'X\(//\)$' \| \
-        X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
-echo X"$ac_file" |
-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)[^/].*/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\).*/{
-           s//\1/
-           q
-         }
-         s/.*/./; q'`
-  { as_dir="$ac_dir"
-  case $as_dir in #(
-  -*) as_dir=./$as_dir;;
-  esac
-  test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || {
-    as_dirs=
-    while :; do
-      case $as_dir in #(
-      *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #(
-      *) as_qdir=$as_dir;;
-      esac
-      as_dirs="'$as_qdir' $as_dirs"
-      as_dir=`$as_dirname -- "$as_dir" ||
-$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-        X"$as_dir" : 'X\(//\)[^/]' \| \
-        X"$as_dir" : 'X\(//\)$' \| \
-        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-echo X"$as_dir" |
-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)[^/].*/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\).*/{
-           s//\1/
-           q
-         }
-         s/.*/./; q'`
-      test -d "$as_dir" && break
-    done
-    test -z "$as_dirs" || eval "mkdir $as_dirs"
-  } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5
-echo "$as_me: error: cannot create directory $as_dir" >&2;}
-   { (exit 1); exit 1; }; }; }
-  ac_builddir=.
-
-case "$ac_dir" in
-.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
-*)
-  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
-  # A ".." for each directory in $ac_dir_suffix.
-  ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'`
-  case $ac_top_builddir_sub in
-  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
-  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
-  esac ;;
-esac
-ac_abs_top_builddir=$ac_pwd
-ac_abs_builddir=$ac_pwd$ac_dir_suffix
-# for backward compatibility:
-ac_top_builddir=$ac_top_build_prefix
-
-case $srcdir in
-  .)  # We are building in place.
-    ac_srcdir=.
-    ac_top_srcdir=$ac_top_builddir_sub
-    ac_abs_top_srcdir=$ac_pwd ;;
-  [\\/]* | ?:[\\/]* )  # Absolute name.
-    ac_srcdir=$srcdir$ac_dir_suffix;
-    ac_top_srcdir=$srcdir
-    ac_abs_top_srcdir=$srcdir ;;
-  *) # Relative name.
-    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
-    ac_top_srcdir=$ac_top_build_prefix$srcdir
-    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
-esac
-ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
-
-
-  case $ac_mode in
-  :F)
-  #
-  # CONFIG_FILE
-  #
-
-  case $INSTALL in
-  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
-  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
-  esac
-# If the template does not know about datarootdir, expand it.
-# FIXME: This hack should be removed a few years after 2.60.
-ac_datarootdir_hack=; ac_datarootdir_seen=
-
-case `sed -n '/datarootdir/ {
-  p
-  q
-}
-/@datadir@/p
-/@docdir@/p
-/@infodir@/p
-/@localedir@/p
-/@mandir@/p
-' $ac_file_inputs` in
-*datarootdir*) ac_datarootdir_seen=yes;;
-*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
-  { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
-echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
-  ac_datarootdir_hack='
-  s&@datadir@&${prefix}&g
-  s&@docdir@&${datarootdir}/doc/${PACKAGE}&g
-  s&@infodir@&${datarootdir}/info&g
-  s&@localedir@&${datarootdir}/locale&g
-  s&@mandir@&${prefix}/man&g
-    s&\${datarootdir}&${prefix}/share&g' ;;
-esac
-  sed "/^[      ]*VPATH[        ]*=/{
-s/:*\$(srcdir):*/:/
-s/:*\${srcdir}:*/:/
-s/:*@srcdir@:*/:/
-s/^\([^=]*=[    ]*\):*/\1/
-s/:*$//
-s/^[^=]*=[      ]*$//
-}
-
-:t
-/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
-s&@configure_input@&$configure_input&;t t
-s&@top_builddir@&$ac_top_builddir_sub&;t t
-s&@srcdir@&$ac_srcdir&;t t
-s&@abs_srcdir@&$ac_abs_srcdir&;t t
-s&@top_srcdir@&$ac_top_srcdir&;t t
-s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
-s&@builddir@&$ac_builddir&;t t
-s&@abs_builddir@&$ac_abs_builddir&;t t
-s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
-s&@INSTALL@&$ac_INSTALL&;t t
-$ac_datarootdir_hack
-" $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out
-
-test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
-  { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
-  { ac_out=`sed -n '/^[         ]*datarootdir[  ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
-  { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir'
-which seems to be undefined.  Please make sure it is defined." >&5
-echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
-which seems to be undefined.  Please make sure it is defined." >&2;}
-
-  rm -f "$tmp/stdin"
-  case $ac_file in
-  -) cat "$tmp/out"; rm -f "$tmp/out";;
-  *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;;
-  esac
- ;;
-
-
-  :C)  { echo "$as_me:$LINENO: executing $ac_file commands" >&5
-echo "$as_me: executing $ac_file commands" >&6;}
- ;;
-  esac
-
-
-  case $ac_file$ac_mode in
-    "mkdir-vpath":C) make mkdir-vpath ;;
-
-  esac
-done # for ac_tag
-
-
-{ (exit 0); exit 0; }
index d4b44b2..e780c3f 100755 (executable)
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.60.
+# Generated by GNU Autoconf 2.61.
 #
 # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
 # 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
@@ -10,7 +10,8 @@
 ## M4sh Initialization.  ##
 ## --------------------- ##
 
-# Be Bourne compatible
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
 if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
   emulate sh
   NULLCMD=:
@@ -19,10 +20,13 @@ if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
   alias -g '${1+"$@"}'='"$@"'
   setopt NO_GLOB_SUBST
 else
-  case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
 fi
-BIN_SH=xpg4; export BIN_SH # for Tru64
-DUALCASE=1; export DUALCASE # for MKS sh
+
+
 
 
 # PATH needs CR
@@ -215,7 +219,7 @@ test \$exitcode = 0) || { (exit 1); exit 1; }
 else
   as_candidate_shells=
     as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in /usr/bin/posix$PATH_SEPARATOR/bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
@@ -233,7 +237,6 @@ IFS=$as_save_IFS
         # Try only shells that exist, to save several forks.
         if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
                { ("$as_shell") 2> /dev/null <<\_ASEOF
-# Be Bourne compatible
 if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
   emulate sh
   NULLCMD=:
@@ -242,10 +245,12 @@ if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
   alias -g '${1+"$@"}'='"$@"'
   setopt NO_GLOB_SUBST
 else
-  case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
 fi
-BIN_SH=xpg4; export BIN_SH # for Tru64
-DUALCASE=1; export DUALCASE # for MKS sh
+
 
 :
 _ASEOF
@@ -253,7 +258,6 @@ _ASEOF
   CONFIG_SHELL=$as_shell
               as_have_required=yes
               if { "$as_shell" 2> /dev/null <<\_ASEOF
-# Be Bourne compatible
 if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
   emulate sh
   NULLCMD=:
@@ -262,10 +266,12 @@ if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
   alias -g '${1+"$@"}'='"$@"'
   setopt NO_GLOB_SUBST
 else
-  case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
 fi
-BIN_SH=xpg4; export BIN_SH # for Tru64
-DUALCASE=1; export DUALCASE # for MKS sh
+
 
 :
 (as_func_return () {
@@ -512,19 +518,28 @@ else
   as_mkdir_p=false
 fi
 
-# Find out whether ``test -x'' works.  Don't use a zero-byte file, as
-# systems may use methods other than mode bits to determine executability.
-cat >conf$$.file <<_ASEOF
-#! /bin/sh
-exit 0
-_ASEOF
-chmod +x conf$$.file
-if test -x conf$$.file >/dev/null 2>&1; then
-  as_executable_p="test -x"
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
 else
-  as_executable_p=:
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+        test -d "$1/.";
+      else
+       case $1 in
+        -*)set "./$1";;
+       esac;
+       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+       ???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
 fi
-rm -f conf$$.file
+as_executable_p=$as_test_x
 
 # Sed expression to map a string onto a valid CPP name.
 as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -566,36 +581,36 @@ ac_default_prefix=/usr/local/serf
 # Factoring default headers for most tests.
 ac_includes_default="\
 #include <stdio.h>
-#if HAVE_SYS_TYPES_H
+#ifdef HAVE_SYS_TYPES_H
 # include <sys/types.h>
 #endif
-#if HAVE_SYS_STAT_H
+#ifdef HAVE_SYS_STAT_H
 # include <sys/stat.h>
 #endif
-#if STDC_HEADERS
+#ifdef STDC_HEADERS
 # include <stdlib.h>
 # include <stddef.h>
 #else
-# if HAVE_STDLIB_H
+# ifdef HAVE_STDLIB_H
 #  include <stdlib.h>
 # endif
 #endif
-#if HAVE_STRING_H
-# if !STDC_HEADERS && HAVE_MEMORY_H
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
 #  include <memory.h>
 # endif
 # include <string.h>
 #endif
-#if HAVE_STRINGS_H
+#ifdef HAVE_STRINGS_H
 # include <strings.h>
 #endif
-#if HAVE_INTTYPES_H
+#ifdef HAVE_INTTYPES_H
 # include <inttypes.h>
 #endif
-#if HAVE_STDINT_H
+#ifdef HAVE_STDINT_H
 # include <stdint.h>
 #endif
-#if HAVE_UNISTD_H
+#ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif"
 
@@ -685,6 +700,7 @@ target_alias
 CC
 CFLAGS
 LDFLAGS
+LIBS
 CPPFLAGS
 CPP'
 
@@ -792,10 +808,10 @@ do
   -disable-* | --disable-*)
     ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
     # Reject names that are not valid shell variable names.
-    expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+    expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null &&
       { echo "$as_me: error: invalid feature name: $ac_feature" >&2
    { (exit 1); exit 1; }; }
-    ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+    ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'`
     eval enable_$ac_feature=no ;;
 
   -docdir | --docdir | --docdi | --doc | --do)
@@ -811,10 +827,10 @@ do
   -enable-* | --enable-*)
     ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
     # Reject names that are not valid shell variable names.
-    expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+    expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null &&
       { echo "$as_me: error: invalid feature name: $ac_feature" >&2
    { (exit 1); exit 1; }; }
-    ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+    ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'`
     eval enable_$ac_feature=\$ac_optarg ;;
 
   -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
@@ -1008,19 +1024,19 @@ do
   -with-* | --with-*)
     ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
     # Reject names that are not valid shell variable names.
-    expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+    expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null &&
       { echo "$as_me: error: invalid package name: $ac_package" >&2
    { (exit 1); exit 1; }; }
-    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    ac_package=`echo $ac_package | sed 's/[-.]/_/g'`
     eval with_$ac_package=\$ac_optarg ;;
 
   -without-* | --without-*)
     ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
     # Reject names that are not valid shell variable names.
-    expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+    expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null &&
       { echo "$as_me: error: invalid package name: $ac_package" >&2
    { (exit 1); exit 1; }; }
-    ac_package=`echo $ac_package | sed 's/-/_/g'`
+    ac_package=`echo $ac_package | sed 's/[-.]/_/g'`
     eval with_$ac_package=no ;;
 
   --x)
@@ -1276,6 +1292,7 @@ Some influential environment variables:
   CFLAGS      C compiler flags
   LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
               nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
   CPPFLAGS    C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
               you have headers in a nonstandard directory <include dir>
   CPP         C preprocessor
@@ -1344,7 +1361,7 @@ test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
 configure
-generated by GNU Autoconf 2.60
+generated by GNU Autoconf 2.61
 
 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
@@ -1358,7 +1375,7 @@ This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
 It was created by $as_me, which was
-generated by GNU Autoconf 2.60.  Invocation command line was
+generated by GNU Autoconf 2.61.  Invocation command line was
 
   $ $0 $@
 
@@ -1821,6 +1838,8 @@ ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
 
 
 
+
+
 # Check whether --enable-layout was given.
 if test "${enable_layout+set}" = set; then
   enableval=$enable_layout;
@@ -2943,7 +2962,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
   for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_CC="${ac_tool_prefix}gcc"
     echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -2983,7 +3002,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
   for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_ac_ct_CC="gcc"
     echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3040,7 +3059,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
   for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_CC="${ac_tool_prefix}cc"
     echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3081,7 +3100,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
   for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
        ac_prog_rejected=yes
        continue
@@ -3139,7 +3158,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
   for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
     echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3183,7 +3202,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
   for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_ac_ct_CC="$ac_prog"
     echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3324,7 +3343,7 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
 # in a Makefile.  We should not override ac_cv_exeext if it was cached,
 # so that the user can short-circuit this test for compilers unknown to
 # Autoconf.
-for ac_file in $ac_files
+for ac_file in $ac_files ''
 do
   test -f "$ac_file" || continue
   case $ac_file in
@@ -3352,6 +3371,12 @@ done
 test "$ac_cv_exeext" = no && ac_cv_exeext=
 
 else
+  ac_file=''
+fi
+
+{ echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6; }
+if test -z "$ac_file"; then
   echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
@@ -3363,8 +3388,6 @@ See \`config.log' for more details." >&2;}
 fi
 
 ac_exeext=$ac_cv_exeext
-{ echo "$as_me:$LINENO: result: $ac_file" >&5
-echo "${ECHO_T}$ac_file" >&6; }
 
 # Check that the compiler produces executables we can run.  If not, either
 # the compiler is broken, or we cross compile.
@@ -3542,27 +3565,10 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
   rm -f conftest.er1
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; } &&
-        { ac_try='test -s conftest.$ac_objext'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
   ac_compiler_gnu=yes
 else
   echo "$as_me: failed program was:" >&5
@@ -3617,27 +3623,10 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
   rm -f conftest.er1
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; } &&
-        { ac_try='test -s conftest.$ac_objext'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
   ac_cv_prog_cc_g=yes
 else
   echo "$as_me: failed program was:" >&5
@@ -3672,27 +3661,10 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
   rm -f conftest.er1
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; } &&
-        { ac_try='test -s conftest.$ac_objext'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
   :
 else
   echo "$as_me: failed program was:" >&5
@@ -3728,27 +3700,10 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
   rm -f conftest.er1
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; } &&
-        { ac_try='test -s conftest.$ac_objext'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
   ac_cv_prog_cc_g=yes
 else
   echo "$as_me: failed program was:" >&5
@@ -3864,27 +3819,10 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
   rm -f conftest.er1
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; } &&
-        { ac_try='test -s conftest.$ac_objext'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
   ac_cv_prog_cc_c89=$ac_arg
 else
   echo "$as_me: failed program was:" >&5
@@ -3973,17 +3911,10 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
   rm -f conftest.er1
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null; then
-  if test -s conftest.err; then
-    ac_cpp_err=$ac_c_preproc_warn_flag
-    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
-  else
-    ac_cpp_err=
-  fi
-else
-  ac_cpp_err=yes
-fi
-if test -z "$ac_cpp_err"; then
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
   :
 else
   echo "$as_me: failed program was:" >&5
@@ -4017,17 +3948,10 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
   rm -f conftest.er1
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null; then
-  if test -s conftest.err; then
-    ac_cpp_err=$ac_c_preproc_warn_flag
-    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
-  else
-    ac_cpp_err=
-  fi
-else
-  ac_cpp_err=yes
-fi
-if test -z "$ac_cpp_err"; then
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
   # Broken: success on invalid input.
 continue
 else
@@ -4092,17 +4016,10 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
   rm -f conftest.er1
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null; then
-  if test -s conftest.err; then
-    ac_cpp_err=$ac_c_preproc_warn_flag
-    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
-  else
-    ac_cpp_err=
-  fi
-else
-  ac_cpp_err=yes
-fi
-if test -z "$ac_cpp_err"; then
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
   :
 else
   echo "$as_me: failed program was:" >&5
@@ -4136,17 +4053,10 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
   rm -f conftest.er1
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null; then
-  if test -s conftest.err; then
-    ac_cpp_err=$ac_c_preproc_warn_flag
-    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
-  else
-    ac_cpp_err=
-  fi
-else
-  ac_cpp_err=yes
-fi
-if test -z "$ac_cpp_err"; then
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
   # Broken: success on invalid input.
 continue
 else
@@ -4215,7 +4125,7 @@ case $as_dir/ in
     # by default.
     for ac_prog in ginstall scoinst install; do
       for ac_exec_ext in '' $ac_executable_extensions; do
-       if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; }; then
+       if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
          if test $ac_prog = install &&
            grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
            # AIX install.  It has an incompatible calling convention.
@@ -4390,7 +4300,7 @@ do
   for ac_prog in grep ggrep; do
   for ac_exec_ext in '' $ac_executable_extensions; do
     ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
-    { test -f "$ac_path_GREP" && $as_executable_p "$ac_path_GREP"; } || continue
+    { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
     # Check for GNU ac_path_GREP and select it if it is found.
   # Check for GNU $ac_path_GREP
 case `"$ac_path_GREP" --version 2>&1` in
@@ -4472,7 +4382,7 @@ do
   for ac_prog in egrep; do
   for ac_exec_ext in '' $ac_executable_extensions; do
     ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
-    { test -f "$ac_path_EGREP" && $as_executable_p "$ac_path_EGREP"; } || continue
+    { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
     # Check for GNU ac_path_EGREP and select it if it is found.
   # Check for GNU $ac_path_EGREP
 case `"$ac_path_EGREP" --version 2>&1` in
@@ -4568,27 +4478,10 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
   rm -f conftest.er1
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; } &&
-        { ac_try='test -s conftest.$ac_objext'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
   ac_cv_header_stdc=yes
 else
   echo "$as_me: failed program was:" >&5
@@ -4764,27 +4657,10 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
   rm -f conftest.er1
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; } &&
-        { ac_try='test -s conftest.$ac_objext'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
   eval "$as_ac_Header=yes"
 else
   echo "$as_me: failed program was:" >&5
@@ -4842,27 +4718,10 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
   rm -f conftest.er1
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; } &&
-        { ac_try='test -s conftest.$ac_objext'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
   ac_header_compiler=yes
 else
   echo "$as_me: failed program was:" >&5
@@ -4898,17 +4757,10 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
   rm -f conftest.er1
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null; then
-  if test -s conftest.err; then
-    ac_cpp_err=$ac_c_preproc_warn_flag
-    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
-  else
-    ac_cpp_err=
-  fi
-else
-  ac_cpp_err=yes
-fi
-if test -z "$ac_cpp_err"; then
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
   ac_header_preproc=yes
 else
   echo "$as_me: failed program was:" >&5
@@ -5146,7 +4998,8 @@ cat >>$CONFIG_STATUS <<\_ACEOF
 ## M4sh Initialization.  ##
 ## --------------------- ##
 
-# Be Bourne compatible
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
 if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
   emulate sh
   NULLCMD=:
@@ -5155,10 +5008,13 @@ if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
   alias -g '${1+"$@"}'='"$@"'
   setopt NO_GLOB_SUBST
 else
-  case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
 fi
-BIN_SH=xpg4; export BIN_SH # for Tru64
-DUALCASE=1; export DUALCASE # for MKS sh
+
+
 
 
 # PATH needs CR
@@ -5382,19 +5238,28 @@ else
   as_mkdir_p=false
 fi
 
-# Find out whether ``test -x'' works.  Don't use a zero-byte file, as
-# systems may use methods other than mode bits to determine executability.
-cat >conf$$.file <<_ASEOF
-#! /bin/sh
-exit 0
-_ASEOF
-chmod +x conf$$.file
-if test -x conf$$.file >/dev/null 2>&1; then
-  as_executable_p="test -x"
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
 else
-  as_executable_p=:
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+        test -d "$1/.";
+      else
+       case $1 in
+        -*)set "./$1";;
+       esac;
+       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+       ???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
 fi
-rm -f conf$$.file
+as_executable_p=$as_test_x
 
 # Sed expression to map a string onto a valid CPP name.
 as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -5410,7 +5275,7 @@ exec 6>&1
 # values after options handling.
 ac_log="
 This file was extended by $as_me, which was
-generated by GNU Autoconf 2.60.  Invocation command line was
+generated by GNU Autoconf 2.61.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
   CONFIG_HEADERS  = $CONFIG_HEADERS
@@ -5438,7 +5303,7 @@ current configuration.
 Usage: $0 [OPTIONS] [FILE]...
 
   -h, --help       print this help, then exit
-  -V, --version    print version number, then exit
+  -V, --version    print version number and configuration settings, then exit
   -q, --quiet      do not print progress messages
   -d, --debug      don't remove temporary files
       --recheck    update $as_me by reconfiguring in the same conditions
@@ -5457,7 +5322,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF
 ac_cs_version="\\
 config.status
-configured by $0, generated by GNU Autoconf 2.60,
+configured by $0, generated by GNU Autoconf 2.61,
   with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
 
 Copyright (C) 2006 Free Software Foundation, Inc.
index 36b25f2..9c45e5e 100644 (file)
@@ -13,8 +13,6 @@
  * limitations under the License.
  */
 
-#include <stdlib.h>  /* ### for abort() */
-
 #include <apr_pools.h>
 #include <apr_poll.h>
 #include <apr_version.h>
@@ -59,12 +57,18 @@ struct serf_request_t {
     struct serf_request_t *next;
 };
 
+typedef struct serf_pollset_t {
+    /* the set of connections to poll */
+    apr_pollset_t *pollset;
+} serf_pollset_t;
+
 struct serf_context_t {
     /* the pool used for self and for other allocations */
     apr_pool_t *pool;
 
-    /* the set of connections to poll */
-    apr_pollset_t *pollset;
+    void *pollset_baton;
+    serf_socket_add_t pollset_add;
+    serf_socket_remove_t pollset_rm;
 
     /* one of our connections has a dirty pollset state. */
     int dirty_pollset;
@@ -72,6 +76,15 @@ struct serf_context_t {
     /* the list of active connections */
     apr_array_header_t *conns;
 #define GET_CONN(ctx, i) (((serf_connection_t **)(ctx)->conns->elts)[i])
+
+    /* Proxy server address */
+    apr_sockaddr_t *proxy_address;
+
+    /* Progress callback */
+    serf_progress_t progress_func;
+    void *progress_baton;
+    apr_off_t progress_read;
+    apr_off_t progress_written;
 };
 
 struct serf_connection_t {
@@ -128,6 +141,13 @@ struct serf_connection_t {
     void *setup_baton;
     serf_connection_closed_t closed;
     void *closed_baton;
+
+    /* Max. number of outstanding requests. */
+    unsigned int max_outstanding_requests;
+
+    /* Host info. */
+    const char *host_url;
+    apr_uri_t host_info;
 };
 
 /* cleanup for sockets */
@@ -167,12 +187,17 @@ static apr_status_t update_pollset(serf_connection_t *conn)
     apr_status_t status;
     apr_pollfd_t desc = { 0 };
 
+    if (!conn->skt) {
+        return APR_SUCCESS;
+    }
+
     /* Remove the socket from the poll set. */
     desc.desc_type = APR_POLL_SOCKET;
     desc.desc.s = conn->skt;
     desc.reqevents = conn->reqevents;
 
-    status = apr_pollset_remove(ctx->pollset, &desc);
+    status = ctx->pollset_rm(ctx->pollset_baton,
+                              &desc, conn);
     if (status && !APR_STATUS_IS_NOTFOUND(status))
         return status;
 
@@ -191,8 +216,11 @@ static apr_status_t update_pollset(serf_connection_t *conn)
         else {
             serf_request_t *request = conn->requests;
 
-            if (conn->probable_keepalive_limit &&
-                conn->completed_requests > conn->probable_keepalive_limit) {
+            if ((conn->probable_keepalive_limit &&
+                 conn->completed_requests > conn->probable_keepalive_limit) ||
+                (conn->max_outstanding_requests &&
+                 conn->completed_requests - conn->completed_responses >=
+                     conn->max_outstanding_requests)) {
                 /* we wouldn't try to write any way right now. */
             }
             else {
@@ -205,15 +233,14 @@ static apr_status_t update_pollset(serf_connection_t *conn)
         }
     }
 
-    desc.client_data = conn;
-
     /* save our reqevents, so we can pass it in to remove later. */
     conn->reqevents = desc.reqevents;
 
     /* Note: even if we don't want to read/write this socket, we still
      * want to poll it for hangups and errors.
      */
-    return apr_pollset_add(ctx->pollset, &desc);
+    return ctx->pollset_add(ctx->pollset_baton,
+                            &desc, conn);
 }
 
 #ifdef SERF_DEBUG_BUCKET_USE
@@ -248,6 +275,7 @@ static apr_status_t open_connections(serf_context_t *ctx)
         serf_connection_t *conn = GET_CONN(ctx, i);
         apr_status_t status;
         apr_socket_t *skt;
+        apr_sockaddr_t *serv_addr;
 
         conn->seen_in_pollset = 0;
 
@@ -286,11 +314,17 @@ static apr_status_t open_connections(serf_context_t *ctx)
         /* Configured. Store it into the connection now. */
         conn->skt = skt;
 
+        /* Do we have to connect to a proxy server? */
+        if (ctx->proxy_address)
+            serv_addr = ctx->proxy_address;
+        else
+            serv_addr = conn->address;
+
         /* Now that the socket is set up, let's connect it. This should
          * return immediately.
          */
         if ((status = apr_socket_connect(skt,
-                                         conn->address)) != APR_SUCCESS) {
+                                         serv_addr)) != APR_SUCCESS) {
             if (!APR_STATUS_IS_EINPROGRESS(status))
                 return status;
         }
@@ -328,6 +362,26 @@ static apr_status_t no_more_writes(serf_connection_t *conn,
   return APR_SUCCESS;
 }
 
+/* Read the 'Connection' header from the response. Return SERF_ERROR_CLOSING if
+ * the header contains value 'close' indicating the server is closing the
+ * connection right after this response.
+ * Otherwise returns APR_SUCCESS.
+ */
+static apr_status_t is_conn_closing(serf_bucket_t *response)
+{
+  serf_bucket_t *hdrs;
+  const char *val;
+
+  hdrs = serf_bucket_response_get_headers(response);
+  val = serf_bucket_headers_get(hdrs, "Connection");
+  if (val && strcasecmp("close", val) == 0)
+    {
+      return SERF_ERROR_CLOSING;
+    }
+
+  return APR_SUCCESS;
+}
+
 static void link_requests(serf_request_t **list, serf_request_t **tail,
                           serf_request_t *request)
 {
@@ -395,7 +449,8 @@ static apr_status_t remove_connection(serf_context_t *ctx,
     desc.desc.s = conn->skt;
     desc.reqevents = conn->reqevents;
 
-    return apr_pollset_remove(ctx->pollset, &desc);
+    return ctx->pollset_rm(ctx->pollset_baton,
+                           &desc, conn);
 }
 
 static apr_status_t reset_connection(serf_connection_t *conn,
@@ -412,7 +467,7 @@ static apr_status_t reset_connection(serf_connection_t *conn,
     old_reqs = conn->requests;
     held_reqs = conn->hold_requests;
     held_reqs_tail = conn->hold_requests_tail;
+
     if (conn->closing) {
         conn->hold_requests = NULL;
         conn->hold_requests_tail = NULL;
@@ -475,6 +530,27 @@ static apr_status_t reset_connection(serf_connection_t *conn,
     return APR_SUCCESS;
 }
 
+/**
+ * Callback function (implements serf_progress_t). Takes a number of bytes
+ * read @a read and bytes written @a written, adds those to the total for this
+ * context and notifies an interested party (if any).
+ */
+static void serf_context_progress_delta(
+    void *progress_baton,
+    apr_off_t read,
+    apr_off_t written)
+{
+    serf_context_t *ctx = progress_baton;
+
+    ctx->progress_read += read;
+    ctx->progress_written += written;
+
+    if (ctx->progress_func)
+        ctx->progress_func(ctx->progress_baton,
+                           ctx->progress_read,
+                           ctx->progress_written);
+}
+
 static apr_status_t socket_writev(serf_connection_t *conn)
 {
     apr_size_t written;
@@ -504,6 +580,9 @@ static apr_status_t socket_writev(serf_connection_t *conn)
         if (len == written) {
             conn->vec_len = 0;
         }
+
+        /* Log progress information */
+        serf_context_progress_delta(conn->ctx, 0, written);
     }
 
     return status;
@@ -535,6 +614,13 @@ static apr_status_t write_to_connection(serf_connection_t *conn)
         apr_status_t status;
         apr_status_t read_status;
 
+        if (conn->max_outstanding_requests &&
+            conn->completed_requests -
+                conn->completed_responses >= conn->max_outstanding_requests) {
+            /* backoff for now. */
+            return APR_SUCCESS;
+        }
+
         /* If we have unwritten data, then write what we can. */
         while (conn->vec_len) {
             status = socket_writev(conn);
@@ -673,6 +759,7 @@ static apr_status_t read_from_connection(serf_connection_t *conn)
 {
     apr_status_t status;
     apr_pool_t *tmppool;
+    int close_connection = FALSE;
 
     /* Whatever is coming in on the socket corresponds to the first request
      * on our chain.
@@ -772,7 +859,10 @@ static apr_status_t read_from_connection(serf_connection_t *conn)
             continue;
         }
 
-        if (!APR_STATUS_IS_EOF(status) && status != SERF_ERROR_CLOSING) {
+        close_connection = is_conn_closing(request->resp_bkt);
+
+        if (!APR_STATUS_IS_EOF(status) &&
+            close_connection != SERF_ERROR_CLOSING) {
             /* Whether success, or an error, there is no more to do unless
              * this request has been completed.
              */
@@ -802,15 +892,16 @@ static apr_status_t read_from_connection(serf_connection_t *conn)
             conn->requests_tail = NULL;
         }
 
+        conn->completed_responses++;
+
         /* This means that we're being advised that the connection is done. */
-        if (status == SERF_ERROR_CLOSING) {
+        if (close_connection == SERF_ERROR_CLOSING) {
             reset_connection(conn, 1);
-            status = APR_SUCCESS;
+            if (APR_STATUS_IS_EOF(status))
+                status = APR_SUCCESS;
             goto error;
         }
 
-        conn->completed_responses++;
-
         /* The server is suddenly deciding to serve more responses than we've
          * seen before.
          *
@@ -914,21 +1005,105 @@ static apr_status_t check_dirty_pollsets(serf_context_t *ctx)
     return APR_SUCCESS;
 }
 
-SERF_DECLARE(serf_context_t *) serf_context_create(apr_pool_t *pool)
+
+static apr_status_t pollset_add(void *user_baton,
+                                apr_pollfd_t *pfd,
+                                void *serf_baton)
+{
+    serf_pollset_t *s = (serf_pollset_t*)user_baton;
+    pfd->client_data = serf_baton;
+    return apr_pollset_add(s->pollset, pfd);
+}
+
+static apr_status_t pollset_rm(void *user_baton,
+                               apr_pollfd_t *pfd,
+                               void *serf_baton)
+{
+    serf_pollset_t *s = (serf_pollset_t*)user_baton;
+    pfd->client_data = serf_baton;
+    return apr_pollset_remove(s->pollset, pfd);
+}
+
+
+SERF_DECLARE(void) serf_config_proxy(serf_context_t *ctx,
+                                     apr_sockaddr_t *address)
+{
+    ctx->proxy_address = address;
+}
+
+SERF_DECLARE(serf_context_t *) serf_context_create_ex(void *user_baton,
+                                                      serf_socket_add_t addf,
+                                                      serf_socket_remove_t rmf,
+                                                      apr_pool_t *pool)
 {
     serf_context_t *ctx = apr_pcalloc(pool, sizeof(*ctx));
 
     ctx->pool = pool;
 
-    /* build the pollset with a (default) number of connections */
-    (void) apr_pollset_create(&ctx->pollset, MAX_CONN, pool, 0);
+    if (user_baton != NULL) {
+        ctx->pollset_baton = user_baton;
+        ctx->pollset_add = addf;
+        ctx->pollset_rm = rmf;
+    }
+    else {
+        /* build the pollset with a (default) number of connections */
+        serf_pollset_t *ps = apr_pcalloc(pool, sizeof(*ps));
+        (void) apr_pollset_create(&ps->pollset, MAX_CONN, pool, 0);
+        ctx->pollset_baton = ps;
+        ctx->pollset_add = pollset_add;
+        ctx->pollset_rm = pollset_rm;
+    }
 
     /* default to a single connection since that is the typical case */
     ctx->conns = apr_array_make(pool, 1, sizeof(serf_connection_t *));
 
+    /* Initialize progress status */
+    ctx->progress_read = 0;
+    ctx->progress_written = 0;
+
     return ctx;
 }
 
+SERF_DECLARE(serf_context_t *) serf_context_create(apr_pool_t *pool)
+{
+    return serf_context_create_ex(NULL, NULL, NULL, pool);
+}
+
+SERF_DECLARE(apr_status_t) serf_context_prerun(serf_context_t *ctx)
+{
+    apr_status_t status = APR_SUCCESS;
+    if ((status = open_connections(ctx)) != APR_SUCCESS)
+        return status;
+
+    if ((status = check_dirty_pollsets(ctx)) != APR_SUCCESS)
+        return status;
+    return status;
+}
+
+SERF_DECLARE(apr_status_t) serf_event_trigger(serf_context_t *s,
+                                              void *serf_baton,
+                                              const apr_pollfd_t *desc)
+{
+    apr_status_t status = APR_SUCCESS;
+
+    serf_connection_t *conn = serf_baton;
+
+    /* apr_pollset_poll() can return a conn multiple times... */
+    if ((conn->seen_in_pollset & desc->rtnevents) != 0 ||
+        (conn->seen_in_pollset & APR_POLLHUP) != 0) {
+        return APR_SUCCESS;
+    }
+
+    conn->seen_in_pollset |= desc->rtnevents;
+
+    if ((status = process_connection(conn,
+                                     desc->rtnevents)) != APR_SUCCESS) {
+        return status;
+    }
+
+    return status;
+}
+
 SERF_DECLARE(apr_status_t) serf_context_run(serf_context_t *ctx,
                                             apr_short_interval_time_t duration,
                                             apr_pool_t *pool)
@@ -936,14 +1111,13 @@ SERF_DECLARE(apr_status_t) serf_context_run(serf_context_t *ctx,
     apr_status_t status;
     apr_int32_t num;
     const apr_pollfd_t *desc;
+    serf_pollset_t *ps = (serf_pollset_t*)ctx->pollset_baton;
 
-    if ((status = open_connections(ctx)) != APR_SUCCESS)
-        return status;
-
-    if ((status = check_dirty_pollsets(ctx)) != APR_SUCCESS)
+    if ((status = serf_context_prerun(ctx)) != APR_SUCCESS) {
         return status;
+    }
 
-    if ((status = apr_pollset_poll(ctx->pollset, duration, &num,
+    if ((status = apr_pollset_poll(ps->pollset, duration, &num,
                                    &desc)) != APR_SUCCESS) {
         /* ### do we still need to dispatch stuff here?
            ### look at the potential return codes. map to our defined
@@ -955,23 +1129,25 @@ SERF_DECLARE(apr_status_t) serf_context_run(serf_context_t *ctx,
     while (num--) {
         serf_connection_t *conn = desc->client_data;
 
-        /* apr_pollset_poll() can return a conn multiple times... */
-        if ((conn->seen_in_pollset & desc->rtnevents) != 0 ||
-            (conn->seen_in_pollset & APR_POLLHUP) != 0) {
-            continue;
-        }
-        conn->seen_in_pollset |= desc->rtnevents;
-
-        if ((status = process_connection(conn,
-                                         desc++->rtnevents)) != APR_SUCCESS) {
-            /* ### what else to do? */
+        status = serf_event_trigger(ctx, conn, desc);
+        if (status) {
             return status;
         }
+
+        desc++;
     }
 
     return APR_SUCCESS;
 }
 
+SERF_DECLARE(void) serf_context_set_progress_cb(
+    serf_context_t *ctx,
+    const serf_progress_t progress_func,
+    void *progress_baton)
+{
+    ctx->progress_func = progress_func;
+    ctx->progress_baton = progress_baton;
+}
 
 SERF_DECLARE(serf_connection_t *) serf_connection_create(
     serf_context_t *ctx,
@@ -992,6 +1168,7 @@ SERF_DECLARE(serf_connection_t *) serf_connection_create(
     conn->closed_baton = closed_baton;
     conn->pool = pool;
     conn->allocator = serf_bucket_allocator_create(pool, NULL, NULL);
+    conn->stream = NULL;
 
     /* Create a subpool for our connection. */
     apr_pool_create(&conn->skt_pool, conn->pool);
@@ -1004,6 +1181,41 @@ SERF_DECLARE(serf_connection_t *) serf_connection_create(
     return conn;
 }
 
+SERF_DECLARE(apr_status_t) serf_connection_create2(
+    serf_connection_t **conn,
+    serf_context_t *ctx,
+    apr_uri_t host_info,
+    serf_connection_setup_t setup,
+    void *setup_baton,
+    serf_connection_closed_t closed,
+    void *closed_baton,
+    apr_pool_t *pool)
+{
+    apr_status_t status;
+    serf_connection_t *c;
+    apr_sockaddr_t *host_address;
+
+    /* Parse the url, store the address of the server. */
+    status = apr_sockaddr_info_get(&host_address,
+                                   host_info.hostname,
+                                   APR_UNSPEC, host_info.port, 0, pool);
+    if (status)
+        return status;
+
+    c = serf_connection_create(ctx, host_address, setup, setup_baton,
+                               closed, closed_baton, pool);
+
+    /* We're not interested in the path following the hostname. */
+    c->host_url = apr_uri_unparse(c->pool,
+                                  &host_info,
+                                  APR_URI_UNP_OMITPATHINFO);
+    c->host_info = host_info;
+
+    *conn = c;
+
+    return status;
+}
+
 SERF_DECLARE(apr_status_t) serf_connection_reset(
     serf_connection_t *conn)
 {
@@ -1031,6 +1243,7 @@ SERF_DECLARE(apr_status_t) serf_connection_close(
                     (*conn->closed)(conn, conn->closed_baton, status,
                                     conn->pool);
                 }
+                conn->skt = NULL;
             }
             if (conn->stream != NULL) {
                 serf_bucket_destroy(conn->stream);
@@ -1059,6 +1272,13 @@ SERF_DECLARE(apr_status_t) serf_connection_close(
     return APR_NOTFOUND;
 }
 
+SERF_DECLARE(void)
+serf_connection_set_max_outstanding_requests(serf_connection_t *conn,
+                                             unsigned int max_requests)
+{
+    conn->max_outstanding_requests = max_requests;
+}
+
 SERF_DECLARE(serf_request_t *) serf_connection_request_create(
     serf_connection_t *conn,
     serf_request_setup_t setup,
@@ -1091,6 +1311,61 @@ SERF_DECLARE(serf_request_t *) serf_connection_request_create(
     return request;
 }
 
+SERF_DECLARE(serf_request_t *) serf_connection_priority_request_create(
+    serf_connection_t *conn,
+    serf_request_setup_t setup,
+    void *setup_baton)
+{
+    serf_request_t *request;
+    serf_request_t *iter, *prev;
+
+    request = serf_bucket_mem_alloc(conn->allocator, sizeof(*request));
+    request->conn = conn;
+    request->setup = setup;
+    request->setup_baton = setup_baton;
+    request->handler = NULL;
+    request->respool = NULL;
+    request->req_bkt = NULL;
+    request->resp_bkt = NULL;
+    request->next = NULL;
+
+    /* Link the new request after the last written request, but before all
+       upcoming requests. */
+    if (conn->closing) {
+        iter = conn->hold_requests;
+    }
+    else {
+        iter = conn->requests;
+    }
+    prev = NULL;
+
+    /* Find a request that has data which needs to be delivered. */
+    while (iter != NULL && iter->req_bkt == NULL && iter->setup == NULL) {
+        prev = iter;
+        iter = iter->next;
+    }
+
+    if (prev) {
+        request->next = iter;
+        prev->next = request;
+    } else {
+        request->next = iter;
+        if (conn->closing) {
+            conn->hold_requests = request;
+        }
+        else {
+            conn->requests = request;
+        }
+    }
+
+    if (! conn->closing) {
+        /* Ensure our pollset becomes writable in context run */
+        conn->ctx->dirty_pollset = 1;
+        conn->dirty_conn = 1;
+    }
+
+    return request;
+}
 
 SERF_DECLARE(apr_status_t) serf_request_cancel(serf_request_t *request)
 {
@@ -1122,3 +1397,41 @@ SERF_DECLARE(void) serf_request_set_handler(
     request->handler = handler;
     request->handler_baton = handler_baton;
 }
+
+SERF_DECLARE(serf_bucket_t *) serf_context_bucket_socket_create(
+    serf_context_t *ctx,
+    apr_socket_t *skt,
+    serf_bucket_alloc_t *allocator)
+{
+    serf_bucket_t *bucket = serf_bucket_socket_create(skt, allocator);
+
+    /* Use serf's default bytes read/written callback */
+    serf_bucket_socket_set_read_progress_cb(bucket,
+                                            serf_context_progress_delta,
+                                            ctx);
+
+    return bucket;
+}
+
+SERF_DECLARE(serf_bucket_t *) serf_request_bucket_request_create(
+    serf_request_t *request,
+    const char *method,
+    const char *uri,
+    serf_bucket_t *body,
+    serf_bucket_alloc_t *allocator)
+{
+    serf_bucket_t *req_bkt, *hdrs_bkt;
+
+    req_bkt = serf_bucket_request_create(method, uri, body, allocator);
+    hdrs_bkt = serf_bucket_request_get_headers(req_bkt);
+
+    /* Proxy? */
+    if (request->conn->ctx->proxy_address && request->conn->host_url)
+      serf_bucket_request_set_root(req_bkt, request->conn->host_url);
+
+    if (request->conn->host_info.hostname)
+      serf_bucket_headers_setn(hdrs_bkt, "Host",
+                               request->conn->host_info.hostname);
+
+    return req_bkt;
+}
index dd455ae..eb0a1f2 100644 (file)
@@ -27,6 +27,8 @@
 #include <apr_pools.h>
 #include <apr_network_io.h>
 #include <apr_time.h>
+#include <apr_poll.h>
+#include <apr_uri.h>
 
 #include "serf_declare.h"
 
@@ -77,6 +79,51 @@ typedef struct serf_request_t serf_request_t;
  */
 SERF_DECLARE(serf_context_t *) serf_context_create(apr_pool_t *pool);
 
+/**
+ * Callback function. Add a socket to the externally managed poll set.
+ *
+ * Both @a pfd and @a serf_baton should be used when calling serf_event_trigger
+ * later.
+ */
+typedef apr_status_t (*serf_socket_add_t)(void *user_baton,
+                                          apr_pollfd_t *pfd,
+                                          void *serf_baton);
+/**
+ * Callback function. Remove the socket, identified by both @a pfd and
+ * @a serf_baton from the externally managed poll set.
+ */
+typedef apr_status_t (*serf_socket_remove_t)(void *user_baton,
+                                             apr_pollfd_t *pfd,
+                                             void *serf_baton);
+
+/* Create a new context for serf operations.
+ *
+ * Use this function to make serf not use its internal control loop, but
+ * instead rely on an external event loop. Serf will use the @a addf and @a rmf
+ * callbacks to notify of any event on a connection. The @a user_baton will be
+ * passed through the addf and rmf callbacks.
+ *
+ * The context will be allocated within @a pool.
+ */
+SERF_DECLARE(serf_context_t *) serf_context_create_ex(void *user_baton,
+                                                      serf_socket_add_t addf,
+                                                      serf_socket_remove_t rmf,
+                                                      apr_pool_t *pool);
+
+/**
+ * Make serf process events on a connection, identified by both @a pfd and
+ * @a serf_baton.
+ *
+ * Any outbound data is delivered, and incoming data is made available to
+ * the associated response handlers and their buckets.
+ *
+ * If any data is processed (incoming or outgoing), then this function will
+ * return with APR_SUCCESS.
+ */
+SERF_DECLARE(apr_status_t) serf_event_trigger(serf_context_t *s,
+                                              void *serf_baton,
+                                              const apr_pollfd_t *pfd);
+
 /** @see serf_context_run should not block at all. */
 #define SERF_DURATION_NOBLOCK 0
 /** @see serf_context_run should run for (nearly) "forever". */
@@ -104,6 +151,25 @@ SERF_DECLARE(apr_status_t) serf_context_run(serf_context_t *ctx,
                                             apr_pool_t *pool);
 
 
+SERF_DECLARE(apr_status_t) serf_context_prerun(serf_context_t *ctx);
+
+/**
+ * Callback function for progress information. @a progress indicates cumulative
+ * number of bytes read or written, for the whole context.
+ */
+typedef void (*serf_progress_t)(void *progress_baton,
+                                apr_off_t read,
+                                apr_off_t write);
+
+/**
+ * Sets the progress callback function. @a progress_func will be called every
+ * time bytes are read of or written on a socket.
+ */
+SERF_DECLARE(void) serf_context_set_progress_cb(
+    serf_context_t *ctx,
+    const serf_progress_t progress_func,
+    void *progress_baton);
+
 /** @} */
 
 /**
@@ -255,6 +321,39 @@ SERF_DECLARE(serf_connection_t *) serf_connection_create(
     apr_pool_t *pool);
 
 /**
+ * Create a new connection associated with the @a ctx serf context.
+ *
+ * A connection will be created to (eventually) connect to the address
+ * specified by @a address. The address must live at least as long as
+ * @a pool (thus, as long as the connection object).
+ *
+ * The host address will be looked up based on the hostname in @a host_info.
+ *
+ * The connection object will be allocated within @a pool. Clearing or
+ * destroying this pool will close the connection, and terminate any
+ * outstanding requests or responses.
+ *
+ * When the connection is closed (upon request or because of an error),
+ * then the @a closed callback is invoked, and @a closed_baton is passed.
+ *
+ * ### doc on setup(_baton). tweak below comment re: acceptor.
+ * NULL may be passed for @a acceptor and @a closed; default implementations
+ * will be used.
+ *
+ * Note: the connection is not made immediately. It will be opened on
+ * the next call to @see serf_context_run.
+ */
+SERF_DECLARE(apr_status_t) serf_connection_create2(
+    serf_connection_t **conn,
+    serf_context_t *ctx,
+    apr_uri_t host_info,
+    serf_connection_setup_t setup,
+    void *setup_baton,
+    serf_connection_closed_t closed,
+    void *closed_baton,
+    apr_pool_t *pool);
+
+/**
  * Reset the connection, but re-open the socket again.
  */
 SERF_DECLARE(apr_status_t) serf_connection_reset(
@@ -270,6 +369,16 @@ SERF_DECLARE(apr_status_t) serf_connection_close(
     serf_connection_t *conn);
 
 /**
+ * Sets the maximum number of outstanding requests @a max_requests on the
+ * connection @a conn. Setting max_requests to 0 means unlimited (the default).
+ * Ex.: setting max_requests to 1 means a request is sent when a response on the
+ * previous request was received and handled.
+ */
+SERF_DECLARE(void)
+serf_connection_set_max_outstanding_requests(serf_connection_t *conn,
+                                             unsigned int max_requests);
+
+/**
  * Setup the @a request for delivery on its connection.
  *
  * Right before this is invoked, @a pool will be built within the
@@ -314,6 +423,25 @@ SERF_DECLARE(serf_request_t *) serf_connection_request_create(
     void *setup_baton);
 
 /**
+ * Construct a request object for the @a conn connection, add it in the
+ * list as the next to-be-written request before all unwritten requests.
+ *
+ * When it is time to deliver the request, the @a setup callback will
+ * be invoked with the @a setup_baton passed into it to complete the
+ * construction of the request object.
+ *
+ * If the request has not (yet) been delivered, then it may be canceled
+ * with @see serf_request_cancel.
+ *
+ * Invoking any calls other than @see serf_request_cancel before the setup
+ * callback executes is not supported.
+ */
+SERF_DECLARE(serf_request_t *) serf_connection_priority_request_create(
+    serf_connection_t *conn,
+    serf_request_setup_t setup,
+    void *setup_baton);
+
+/**
  * Cancel the request specified by the @a request object.
  *
  * If the request has been scheduled for delivery, then its response
@@ -359,8 +487,48 @@ SERF_DECLARE(void) serf_request_set_handler(
     const serf_response_handler_t handler,
     const void **handler_baton);
 
+/**
+ * Configure proxy server settings, to be used by all connections associated
+ * with the @a ctx serf context.
+ *
+ * The next connection will be created to connect to the proxy server
+ * specified by @a address. The address must live at least as long as the
+ * serf context.
+ */
+SERF_DECLARE(void) serf_config_proxy(
+    serf_context_t *ctx,
+    apr_sockaddr_t *address);
+
 /* ### maybe some connection control functions for flood? */
 
+/*** Special bucket creation functions ***/
+
+/**
+ * Create a bucket of type 'socket bucket'.
+ * This is basically a wrapper around @a serf_bucket_socket_create, which
+ * initializes the bucket using connection and/or context specific settings.
+ */
+SERF_DECLARE(serf_bucket_t *) serf_context_bucket_socket_create(
+    serf_context_t *ctx,
+    apr_socket_t *skt,
+    serf_bucket_alloc_t *allocator);
+
+/**
+ * Create a bucket of type 'request bucket'.
+ * This is basically a wrapper around @a serf_bucket_request_create, which
+ * initializes the bucket using request, connection and/or context specific
+ * settings.
+ *
+ * If the host_url and/or user_agent options are set on the connection,
+ * headers 'Host' and/or 'User-Agent' will be set on the request message.
+ */
+SERF_DECLARE(serf_bucket_t *) serf_request_bucket_request_create(
+    serf_request_t *request,
+    const char *method,
+    const char *uri,
+    serf_bucket_t *body,
+    serf_bucket_alloc_t *allocator);
+
 /** @} */
 
 
@@ -717,8 +885,13 @@ SERF_DECLARE(void) serf_debug__bucket_alloc_check(serf_bucket_alloc_t *allocator
 
 /* Version info */
 #define SERF_MAJOR_VERSION 0
-#define SERF_MINOR_VERSION 1
-#define SERF_PATCH_VERSION 2
+#define SERF_MINOR_VERSION 2
+#define SERF_PATCH_VERSION 0
+
+/* Version number string */
+#define SERF_VERSION_STRING APR_STRINGIFY(SERF_MAJOR_VERSION) "." \
+                            APR_STRINGIFY(SERF_MINOR_VERSION) "." \
+                            APR_STRINGIFY(SERF_PATCH_VERSION)
 
 /**
  * Check at compile time if the Serf version is at least a certain
index c0c7709..207e129 100644 (file)
-#**** serf Win32 -*- Makefile -*- ********************************************\r
-#\r
-# Define DEBUG_BUILD to create a debug version of the library.\r
-\r
-!IF "$(OS)" == "Windows_NT"\r
-NULL=\r
-!ELSE\r
-NULL=nul\r
-!ENDIF\r
-\r
-CFLAGS = /Zi /W3 /EHsc /I "./"\r
-\r
-!IF "$(DEBUG_BUILD)" == ""\r
-INTDIR = Release\r
-CFLAGS = /MD /O2 /D "NDEBUG" $(CFLAGS)\r
-STATIC_LIB = $(INTDIR)\serf.lib\r
-!ELSE\r
-INTDIR = Debug\r
-CFLAGS = /MDd /Od /W3 /Gm /D "_DEBUG" $(CFLAGS)\r
-STATIC_LIB = $(INTDIR)\serf.lib\r
-!ENDIF\r
-\r
-########\r
-# Support for OpenSSL integration\r
-!IF "$(OPENSSL_SRC)" == ""\r
-!ERROR OpenSSL is required. Please define OPENSSL_SRC.\r
-!ELSE\r
-OPENSSL_FLAGS = /I "$(OPENSSL_SRC)\inc32"\r
-!ENDIF\r
-\r
-!IF "$(HTTPD_SRC)" != ""\r
-!IF "$(APR_SRC)" == ""\r
-APR_SRC=$(HTTPD_SRC)\srclib\apr\r
-!ENDIF\r
-\r
-!IF "$(APRUTIL_SRC)" == ""\r
-APRUTIL_SRC=$(HTTPD_SRC)\srclib\apr-util\r
-!ENDIF\r
-\r
-!ENDIF\r
-\r
-########\r
-# APR\r
-!IF "$(APR_SRC)" == ""\r
-!ERROR APR is required. Please define APR_SRC or HTTPD_SRC.\r
-!ENDIF\r
-\r
-APR_FLAGS = /I "$(APR_SRC)\include"\r
-!IF [IF EXIST "$(APR_SRC)\$(INTDIR)\libapr-1.lib" exit 1] == 1\r
-APR_LIBS = "$(APR_SRC)\$(INTDIR)\libapr-1.lib"\r
-!ELSE\r
-APR_LIBS = "$(APR_SRC)\$(INTDIR)\libapr.lib"\r
-!ENDIF\r
-\r
-########\r
-# APR Util\r
-!IF "$(APRUTIL_SRC)" == ""\r
-!ERROR APR-Util is required. Please define APRUTIL_SRC or HTTPD_SRC.\r
-!ENDIF\r
-\r
-APRUTIL_FLAGS = /I "$(APRUTIL_SRC)\include"\r
-!IF [IF EXIST "$(APRUTIL_SRC)\$(INTDIR)\libaprutil-1.lib" exit 1] == 1\r
-APRUTIL_LIBS = "$(APRUTIL_SRC)\$(INTDIR)\libaprutil-1.lib"\r
-!ELSE\r
-APRUTIL_LIBS = "$(APRUTIL_SRC)\$(INTDIR)\libaprutil.lib"\r
-!ENDIF\r
-\r
-########\r
-# Support for zlib integration\r
-!IF "$(ZLIB_SRC)" == ""\r
-!ERROR ZLib is required. Please define ZLIB_SRC.\r
-!ELSE\r
-ZLIB_FLAGS = /I "$(ZLIB_SRC)"\r
-!IF "$(ZLIB_DLL)" == ""\r
-!IF "$(ZLIB_LIBDIR)" == ""\r
-!IF "$(DEBUG_BUILD)" == ""\r
-ZLIB_LIBS = "$(ZLIB_SRC)\zlibstat.lib"\r
-!ELSE\r
-ZLIB_LIBS = "$(ZLIB_SRC)\zlibstatD.lib"\r
-!ENDIF\r
-!ELSE\r
-ZLIB_LIBS = "$(ZLIB_LIBDIR)\x86\ZlibStat$(INTDIR)\zlibstat.lib"\r
-ZLIB_FLAGS = $(ZLIB_FLAGS) /D ZLIB_WINAPI\r
-!ENDIF\r
-!ELSE\r
-ZLIB_FLAGS = $(ZLIB_FLAGS) /D ZLIB_DLL\r
-ZLIB_LIBS = "$(ZLIB_SRC)\zlibdll.lib"\r
-!ENDIF\r
-!ENDIF\r
-\r
-\r
-# Exclude stuff we don't need from the Win32 headers\r
-WIN32_DEFS = /D WIN32 /D WIN32_LEAN_AND_MEAN /D NOUSER /D NOGDI /D NONLS /D NOCRYPT\r
-\r
-CPP=cl.exe\r
-CPP_PROJ = /c /nologo $(CFLAGS) $(WIN32_DEFS) $(EXPAT_FLAGS) $(APR_FLAGS) $(APRUTIL_FLAGS) $(OPENSSL_FLAGS) $(ZLIB_FLAGS) /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\"\r
-LIB32=link.exe\r
-LIB32_FLAGS=/nologo\r
-\r
-LIB32_OBJS= \\r
-    "$(INTDIR)\aggregate_buckets.obj" \\r
-    "$(INTDIR)\context.obj" \\r
-    "$(INTDIR)\allocator.obj" \\r
-    "$(INTDIR)\barrier_buckets.obj" \\r
-    "$(INTDIR)\buckets.obj" \\r
-    "$(INTDIR)\chunk_buckets.obj" \\r
-    "$(INTDIR)\dechunk_buckets.obj" \\r
-    "$(INTDIR)\deflate_buckets.obj" \\r
-    "$(INTDIR)\file_buckets.obj" \\r
-    "$(INTDIR)\headers_buckets.obj" \\r
-    "$(INTDIR)\limit_buckets.obj" \\r
-    "$(INTDIR)\mmap_buckets.obj" \\r
-    "$(INTDIR)\request_buckets.obj" \\r
-    "$(INTDIR)\response_buckets.obj" \\r
-    "$(INTDIR)\simple_buckets.obj" \\r
-    "$(INTDIR)\socket_buckets.obj" \\r
-    "$(INTDIR)\ssl_buckets.obj" \\r
-\r
-!IFDEF OPENSSL_STATIC\r
-LIB32_OBJS = $(LIB32_OBJS) "$(OPENSSL_SRC)\out32\libeay32.lib" \\r
-               "$(OPENSSL_SRC)\out32\ssleay32.lib"\r
-!ELSE\r
-LIB32_OBJS = $(LIB32_OBJS) "$(OPENSSL_SRC)\out32dll\libeay32.lib" \\r
-               "$(OPENSSL_SRC)\out32dll\ssleay32.lib"\r
-!ENDIF\r
-\r
-LIB32_OBJS = $(LIB32_OBJS) $(APR_LIBS) $(APRUTIL_LIBS) $(ZLIB_LIBS) \r
-\r
-ALL: INTDIR $(STATIC_LIB) TESTS\r
\r
-\r
-CLEAN:\r
-  -@erase /q "$(INTDIR)" >nul\r
-\r
-INTDIR:\r
-  -@if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)"\r
-\r
-TESTS: $(STATIC_LIB) $(INTDIR)\serf_response.exe $(INTDIR)\serf_get.exe \\r
-       $(INTDIR)\serf_request.exe\r
-\r
-CHECK: INTDIR TESTS\r
-  $(INTDIR)\serf_response.exe test\testcases\simple.response\r
-  $(INTDIR)\serf_response.exe test\testcases\chunked-empty.response\r
-  $(INTDIR)\serf_response.exe test\testcases\chunked.response\r
-  $(INTDIR)\serf_response.exe test\testcases\chunked-trailers.response\r
-  $(INTDIR)\serf_response.exe test\testcases\deflate.response\r
-  \r
-"$(STATIC_LIB)": INTDIR $(LIB32_OBJS)\r
-  $(LIB32) -lib @<<\r
-    $(LIB32_FLAGS) $(LIB32_OBJS) /OUT:"$(STATIC_LIB)"\r
-<<\r
-\r
-\r
-.c{$(INTDIR)}.obj:\r
-  $(CPP) @<<\r
-    $(CPP_PROJ) $<\r
-<<\r
-\r
-{buckets}.c{$(INTDIR)}.obj:\r
-  $(CPP) @<<\r
-    $(CPP_PROJ) $<\r
-<<\r
-\r
-{test}.c{$(INTDIR)}.obj: \r
-  $(CPP) @<<\r
-    $(CPP_PROJ) $<\r
-<<\r
-\r
-$(INTDIR)\serf_response.exe: $(INTDIR)\serf_response.obj $(STATIC_LIB)\r
-  $(LIB32) /DEBUG  $(INTDIR)\serf_response.obj /OUT:$(INTDIR)\serf_response.exe $(LIB32_FLAGS) $(STATIC_LIB)\r
-\r
-$(INTDIR)\serf_get.exe: $(INTDIR)\serf_get.obj $(STATIC_LIB)\r
-  $(LIB32) $(INTDIR)\serf_get.obj /OUT:$(INTDIR)\serf_get.exe $(LIB32_FLAGS) $(STATIC_LIB)\r
-\r
-$(INTDIR)\serf_request.exe: $(INTDIR)\serf_request.obj $(STATIC_LIB)\r
-  $(LIB32) $(INTDIR)\serf_request.obj /OUT:$(INTDIR)\serf_request.exe $(LIB32_FLAGS) $(STATIC_LIB)\r
-\r
-$(INTDIR)\serf_spider.exe: $(INTDIR)\serf_spider.obj $(STATIC_LIB)\r
-  $(LIB32) $(INTDIR)\serf_spider.obj /OUT:$(INTDIR)\serf_spider.exe $(LIB32_FLAGS) $(STATIC_LIB)\r
+#**** serf Win32 -*- Makefile -*- ********************************************
+#
+# Define DEBUG_BUILD to create a debug version of the library.
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+CFLAGS = /Zi /W3 /EHsc /I "./"
+
+!IF "$(DEBUG_BUILD)" == ""
+INTDIR = Release
+CFLAGS = /MD /O2 /D "NDEBUG" $(CFLAGS)
+STATIC_LIB = $(INTDIR)\serf.lib
+!ELSE
+INTDIR = Debug
+CFLAGS = /MDd /Od /W3 /Gm /D "_DEBUG" $(CFLAGS)
+STATIC_LIB = $(INTDIR)\serf.lib
+!ENDIF
+
+########
+# Support for OpenSSL integration
+!IF "$(OPENSSL_SRC)" == ""
+!ERROR OpenSSL is required. Please define OPENSSL_SRC.
+!ELSE
+OPENSSL_FLAGS = /I "$(OPENSSL_SRC)\inc32"
+!ENDIF
+
+!IF "$(HTTPD_SRC)" != ""
+!IF "$(APR_SRC)" == ""
+APR_SRC=$(HTTPD_SRC)\srclib\apr
+!ENDIF
+
+!IF "$(APRUTIL_SRC)" == ""
+APRUTIL_SRC=$(HTTPD_SRC)\srclib\apr-util
+!ENDIF
+
+!ENDIF
+
+########
+# APR
+!IF "$(APR_SRC)" == ""
+!ERROR APR is required. Please define APR_SRC or HTTPD_SRC.
+!ENDIF
+
+APR_FLAGS = /I "$(APR_SRC)\include"
+!IF [IF EXIST "$(APR_SRC)\$(INTDIR)\libapr-1.lib" exit 1] == 1
+APR_LIBS = "$(APR_SRC)\$(INTDIR)\libapr-1.lib"
+!ELSE
+APR_LIBS = "$(APR_SRC)\$(INTDIR)\libapr.lib"
+!ENDIF
+
+########
+# APR Util
+!IF "$(APRUTIL_SRC)" == ""
+!ERROR APR-Util is required. Please define APRUTIL_SRC or HTTPD_SRC.
+!ENDIF
+
+APRUTIL_FLAGS = /I "$(APRUTIL_SRC)\include"
+!IF [IF EXIST "$(APRUTIL_SRC)\$(INTDIR)\libaprutil-1.lib" exit 1] == 1
+APRUTIL_LIBS = "$(APRUTIL_SRC)\$(INTDIR)\libaprutil-1.lib"
+!ELSE
+APRUTIL_LIBS = "$(APRUTIL_SRC)\$(INTDIR)\libaprutil.lib"
+!ENDIF
+
+########
+# Support for zlib integration
+!IF "$(ZLIB_SRC)" == ""
+!ERROR ZLib is required. Please define ZLIB_SRC.
+!ELSE
+ZLIB_FLAGS = /I "$(ZLIB_SRC)"
+!IF "$(ZLIB_DLL)" == ""
+!IF "$(ZLIB_LIBDIR)" == ""
+!IF "$(DEBUG_BUILD)" == ""
+ZLIB_LIBS = "$(ZLIB_SRC)\zlibstat.lib"
+!ELSE
+ZLIB_LIBS = "$(ZLIB_SRC)\zlibstatD.lib"
+!ENDIF
+!ELSE
+ZLIB_LIBS = "$(ZLIB_LIBDIR)\x86\ZlibStat$(INTDIR)\zlibstat.lib"
+ZLIB_FLAGS = $(ZLIB_FLAGS) /D ZLIB_WINAPI
+!ENDIF
+!ELSE
+ZLIB_FLAGS = $(ZLIB_FLAGS) /D ZLIB_DLL
+ZLIB_LIBS = "$(ZLIB_SRC)\zlibdll.lib"
+!ENDIF
+!ENDIF
+
+
+# Exclude stuff we don't need from the Win32 headers
+WIN32_DEFS = /D WIN32 /D WIN32_LEAN_AND_MEAN /D NOUSER /D NOGDI /D NONLS /D NOCRYPT
+
+CPP=cl.exe
+CPP_PROJ = /c /nologo $(CFLAGS) $(WIN32_DEFS) $(EXPAT_FLAGS) $(APR_FLAGS) $(APRUTIL_FLAGS) $(OPENSSL_FLAGS) $(ZLIB_FLAGS) /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\"
+LIB32=link.exe
+LIB32_FLAGS=/nologo
+
+LIB32_OBJS= \
+    "$(INTDIR)\aggregate_buckets.obj" \
+    "$(INTDIR)\context.obj" \
+    "$(INTDIR)\allocator.obj" \
+    "$(INTDIR)\barrier_buckets.obj" \
+    "$(INTDIR)\buckets.obj" \
+    "$(INTDIR)\chunk_buckets.obj" \
+    "$(INTDIR)\dechunk_buckets.obj" \
+    "$(INTDIR)\deflate_buckets.obj" \
+    "$(INTDIR)\file_buckets.obj" \
+    "$(INTDIR)\headers_buckets.obj" \
+    "$(INTDIR)\limit_buckets.obj" \
+    "$(INTDIR)\mmap_buckets.obj" \
+    "$(INTDIR)\request_buckets.obj" \
+    "$(INTDIR)\response_buckets.obj" \
+    "$(INTDIR)\simple_buckets.obj" \
+    "$(INTDIR)\socket_buckets.obj" \
+    "$(INTDIR)\ssl_buckets.obj" \
+
+!IFDEF OPENSSL_STATIC
+LIB32_OBJS = $(LIB32_OBJS) "$(OPENSSL_SRC)\out32\libeay32.lib" \
+               "$(OPENSSL_SRC)\out32\ssleay32.lib"
+!ELSE
+LIB32_OBJS = $(LIB32_OBJS) "$(OPENSSL_SRC)\out32dll\libeay32.lib" \
+               "$(OPENSSL_SRC)\out32dll\ssleay32.lib"
+!ENDIF
+
+LIB32_OBJS = $(LIB32_OBJS) $(APR_LIBS) $(APRUTIL_LIBS) $(ZLIB_LIBS)
+
+TEST_OBJS = \
+    "$(INTDIR)\CuTest.obj" \
+    "$(INTDIR)\test_all.obj" \
+    "$(INTDIR)\test_util.obj" \
+    "$(INTDIR)\test_context.obj" \
+    "$(INTDIR)\test_buckets.obj" \
+    "$(INTDIR)\test_ssl.obj" \
+
+ALL: INTDIR $(STATIC_LIB) TESTS
+
+CLEAN:
+  -@erase /q "$(INTDIR)" >nul
+
+INTDIR:
+  -@if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)"
+
+TESTS: $(STATIC_LIB) $(INTDIR)\serf_response.exe $(INTDIR)\serf_get.exe \
+       $(INTDIR)\serf_request.exe $(INTDIR)\test_all.exe
+
+CHECK: INTDIR TESTS
+  $(INTDIR)\serf_response.exe test\testcases\simple.response
+  $(INTDIR)\serf_response.exe test\testcases\chunked-empty.response
+  $(INTDIR)\serf_response.exe test\testcases\chunked.response
+  $(INTDIR)\serf_response.exe test\testcases\chunked-trailers.response
+  $(INTDIR)\serf_response.exe test\testcases\deflate.response
+  $(INTDIR)\test_all.exe
+
+"$(STATIC_LIB)": INTDIR $(LIB32_OBJS)
+  $(LIB32) -lib @<<
+    $(LIB32_FLAGS) $(LIB32_OBJS) /OUT:$@
+<<
+
+
+.c{$(INTDIR)}.obj:
+  $(CPP) @<<
+    $(CPP_PROJ) $<
+<<
+
+{buckets}.c{$(INTDIR)}.obj:
+  $(CPP) @<<
+    $(CPP_PROJ) $<
+<<
+
+{test}.c{$(INTDIR)}.obj:
+  $(CPP) @<<
+    $(CPP_PROJ) $<
+<<
+
+$(INTDIR)\serf_response.exe: $(INTDIR)\serf_response.obj $(STATIC_LIB)
+  $(LIB32) /DEBUG /OUT:$@ $** $(LIB32_FLAGS)
+
+$(INTDIR)\serf_get.exe: $(INTDIR)\serf_get.obj $(STATIC_LIB)
+  $(LIB32) /OUT:$@ $** $(LIB32_FLAGS)
+
+$(INTDIR)\serf_request.exe: $(INTDIR)\serf_request.obj $(STATIC_LIB)
+  $(LIB32) /OUT:$@ $** $(LIB32_FLAGS)
+
+$(INTDIR)\test_all.exe: $(TEST_OBJS) $(STATIC_LIB)
+  $(LIB32) /DEBUG /OUT:$@ $** $(LIB32_FLAGS)
index c146908..cbb0bc3 100644 (file)
@@ -17,6 +17,7 @@
 #define SERF_BUCKET_TYPES_H
 
 #include <apr_mmap.h>
+#include <apr_hash.h>
 
 /* this header and serf.h refer to each other, so take a little extra care */
 #ifndef SERF_H
@@ -56,6 +57,15 @@ SERF_DECLARE(void) serf_bucket_request_become(serf_bucket_t *bucket,
                                               const char *uri,
                                               serf_bucket_t *body);
 
+/**
+ * Sets the root url of the remote host. If this request contains a relative
+ * url, it will be prefixed with the root url to form an absolute url.
+ * @a bucket is the request bucket. @a root_url is the absolute url of the
+ * root of the remote host, without the closing '/'.
+ */
+SERF_DECLARE(void) serf_bucket_request_set_root(serf_bucket_t *bucket,
+                                                const char *root_url);
+
 /* ==================================================================== */
 
 
@@ -163,6 +173,18 @@ SERF_DECLARE(serf_bucket_t *) serf_bucket_socket_create(
     apr_socket_t *skt,
     serf_bucket_alloc_t *allocator);
 
+/**
+ * Call @a progress_func every time bytes are read from the socket, pass
+ * the number of bytes read.
+ *
+ * When using serf's bytes read & written progress indicator, pass
+ * @a serf_context_progress_delta for progress_func and the serf_context for
+ * progress_baton.
+ */
+SERF_DECLARE(void) serf_bucket_socket_set_read_progress_cb(
+    serf_bucket_t *bucket,
+    const serf_progress_t progress_func,
+    void *progress_baton);
 
 /* ==================================================================== */
 
@@ -244,6 +266,9 @@ SERF_DECLARE(void) serf_bucket_headers_setc(
  * Set the specified @a header and @a value into the bucket, without
  * copying either attribute. Both attributes should remain in scope at
  * least as long as the bucket.
+ *
+ * @note In the case where a header already exists this will result
+ *       in a reallocation and copy, @see serf_bucket_headers_setn.
  */
 SERF_DECLARE(void) serf_bucket_headers_setn(
     serf_bucket_t *headers_bucket,
@@ -258,6 +283,12 @@ SERF_DECLARE(void) serf_bucket_headers_setn(
  * be copied if @a header_copy is set, and the value is copied if
  * @a value_copy is set. If the values are not copied, then they should
  * remain in scope at least as long as the bucket.
+ *
+ * If @a headers_bucket already contains a header with the same name
+ * as @a header, then append @a value to the existing value,
+ * separating with a comma (as per RFC 2616, section 4.2).  In this
+ * case, the new value must be allocated and the header re-used, so
+ * behave as if @a value_copy were true and @a header_copy false.
  */
 SERF_DECLARE(void) serf_bucket_headers_setx(
     serf_bucket_t *headers_bucket,
@@ -275,7 +306,7 @@ SERF_DECLARE(const char *) serf_bucket_headers_get(
  */
 typedef int (serf_bucket_headers_do_callback_fn_t)(
     void *baton,
-    const char *key, 
+    const char *key,
     const char *value);
 
 /**
@@ -339,12 +370,17 @@ SERF_DECLARE(serf_bucket_t *) serf_bucket_limit_create(
 
 
 /* ==================================================================== */
-
+#define SERF_SSL_CERT_NOTYETVALID       1
+#define SERF_SSL_CERT_EXPIRED           2
+#define SERF_SSL_CERT_UNKNOWNCA         4
+#define SERF_SSL_CERT_SELF_SIGNED       8
+#define SERF_SSL_CERT_UNKNOWN_FAILURE  16
 
 SERF_DECLARE_DATA extern const serf_bucket_type_t serf_bucket_type_ssl_encrypt;
 #define SERF_BUCKET_IS_SSL_ENCRYPT(b) SERF_BUCKET_CHECK((b), ssl_encrypt)
 
 typedef struct serf_ssl_context_t serf_ssl_context_t;
+typedef struct serf_ssl_certificate_t serf_ssl_certificate_t;
 
 typedef apr_status_t (*serf_ssl_need_client_cert_t)(void *data,
                                                     const char **cert_path);
@@ -353,6 +389,11 @@ typedef apr_status_t (*serf_ssl_need_cert_password_t)(void *data,
                                                       const char *cert_path,
                                                       const char **password);
 
+typedef apr_status_t
+(*serf_ssl_need_server_cert_t)(void *data,
+                               int failures,
+                               const serf_ssl_certificate_t *cert);
+
 SERF_DECLARE(void)
 serf_ssl_client_cert_provider_set(serf_ssl_context_t *context,
                                   serf_ssl_need_client_cert_t callback,
@@ -364,6 +405,58 @@ serf_ssl_client_cert_password_set(serf_ssl_context_t *context,
                                   serf_ssl_need_cert_password_t callback,
                                   void *data,
                                   void *cache_pool);
+/**
+ * Set a callback to override the default SSL server certificate validation
+ * algorithm.
+ */
+SERF_DECLARE(void)
+serf_ssl_server_cert_callback_set(serf_ssl_context_t *context,
+                                  serf_ssl_need_server_cert_t callback,
+                                  void *data);
+
+/**
+ * Use the default root CA certificates as included with the OpenSSL library.
+ */
+SERF_DECLARE(apr_status_t)
+serf_ssl_use_default_certificates(serf_ssl_context_t *context);
+
+/**
+ * Extract the fields of the issuer in a table with keys (E, CN, OU, O, L,
+ * ST and C). The returned table will be allocated in @a pool.
+ */
+SERF_DECLARE(apr_hash_t *)
+serf_ssl_cert_issuer(const serf_ssl_certificate_t *cert, apr_pool_t *pool);
+
+/**
+ * Extract the fields of the subject in a table with keys (E, CN, OU, O, L,
+ * ST and C). The returned table will be allocated in @a pool.
+ */
+SERF_DECLARE(apr_hash_t *)
+serf_ssl_cert_subject(const serf_ssl_certificate_t *cert, apr_pool_t *pool);
+
+/**
+ * Extract the fields of the certificate in a table with keys (sha1, notBefore,
+ * notAfter). The returned table will be allocated in @a pool.
+ */
+SERF_DECLARE(apr_hash_t *)
+serf_ssl_cert_certificate(const serf_ssl_certificate_t *cert, apr_pool_t *pool);
+
+/**
+ * Load a CA certificate file from a path @a file_path. If the file was loaded
+ * and parsed correctly, a certificate @a cert will be created and returned.
+ * This certificate object will be alloced in @a pool.
+ */
+SERF_DECLARE(apr_status_t)
+serf_ssl_load_cert_file(serf_ssl_certificate_t **cert, const char *file_path,
+                        apr_pool_t *pool);
+
+/**
+ * Adds the certificate @a cert to the list of trusted certificates in
+ * @a ssl_ctx that will be used for verification.
+ * See also @a serf_ssl_load_cert_file.
+ */
+SERF_DECLARE(apr_status_t)
+serf_ssl_trust_cert(serf_ssl_context_t *ssl_ctx, serf_ssl_certificate_t *cert);
 
 SERF_DECLARE(serf_bucket_t *) serf_bucket_ssl_encrypt_create(
     serf_bucket_t *stream,
old mode 100644 (file)
new mode 100755 (executable)
index d8be479..fbe6c96
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 
 import os
 import re
@@ -34,11 +34,25 @@ LIB_FILES = [
   ('buckets', 'chunk_buckets'),
   ]
 
+TEST_DEPS = [
+  ('test', 'CuTest'),
+  ('test', 'test_util'),
+  ('test', 'test_context'),
+  ('test', 'test_buckets'),
+  ('test', 'test_ssl'),
+  ]
+
+TEST_HDR_FILES = [
+  ('test', 'CuTest'),
+  ('test', 'test_serf'),
+  ]
+
 TEST_FILES = [
   ('test', 'serf_get'),
   ('test', 'serf_response'),
   ('test', 'serf_request'),
   ('test', 'serf_spider'),
+  ('test', 'test_all'),
   ]
 
 TESTCASES = [
@@ -108,15 +122,20 @@ def cmd_install(param):
 
 def cmd_check(param):
   builder = Builder(param)
-  builder.build_target(File('test', 'serf_response', None), False)
+  for dirpath, fname in TEST_FILES:
+    builder.build_target(File(dirpath, fname, None), False)
 
   for dirpath, fname in TESTCASES:
     case = os.path.join(dirpath, fname)
     print '== Testing %s ==' % case
     result = os.system('%s %s' % (os.path.join('test', 'serf_response'), case))
     if result:
-      raise TestError(case, result)
+      raise TestError("", result)
 
+  # run the test suite based on the CuTest framework
+  result = os.system(os.path.join('test', 'test_all'))
+  if result:
+    raise TestError(case, result)
 
 def cmd_clean(param):
   clean = [File(dirpath, fname, 'o') for dirpath, fname in LIB_FILES]
@@ -125,6 +144,8 @@ def cmd_clean(param):
   clean += [File(dirpath, fname, 'o') for dirpath, fname in TEST_FILES]
   clean += [File(dirpath, fname, 'lo') for dirpath, fname in TEST_FILES]
   clean += [File(dirpath, fname, None) for dirpath, fname in TEST_FILES]
+  clean += [File(dirpath, fname, 'o') for dirpath, fname in TEST_DEPS]
+  clean += [File(dirpath, fname, 'lo') for dirpath, fname in TEST_DEPS]
   for i in clean:
     if i.mtime:
       os.remove(i.fname)
@@ -190,6 +211,14 @@ class Builder:
     self._add_dep(lib, libobjs, cmd)
 
     # load the test program dependencies now
+    testhdrs = hdrs
+    testhdrs += [File(dirpath, fname, 'h') for dirpath, fname in TEST_HDR_FILES]
+    testdeps = [File(dirpath, fname, 'c') for dirpath, fname in TEST_DEPS]
+    testobjs = [File(dirpath, fname, 'lo') for dirpath, fname in TEST_DEPS]
+
+    for testsrc, testobj in zip(testdeps, testobjs):
+      self._add_compile(testsrc, testobj, testhdrs)
+
     for dirpath, fname in TEST_FILES:
       src = File(dirpath, fname, 'c')
       obj = File(dirpath, fname, 'lo')
@@ -197,10 +226,18 @@ class Builder:
 
       self._add_compile(src, obj, hdrs)
 
-      cmd = '%s --silent --mode=link %s %s -static -o %s %s %s %s' % (
-        self.LIBTOOL, self.CC, self.LDFLAGS,
-        prog.fname, lib.fname, obj.fname, self.LIBS)
-      self._add_dep(prog, [lib, obj], cmd)
+      # test_all requires extra dependencies
+      if fname == "test_all":
+        cmd = '%s --silent --mode=link %s %s -static -o %s %s %s %s' % (
+          self.LIBTOOL, self.CC, self.LDFLAGS,
+          prog.fname, lib.fname, ' '.join([l.fname for l in [obj] + testobjs]),
+          self.LIBS)
+        self._add_dep(prog, [lib, obj] + testobjs, cmd)
+      else:
+        cmd = '%s --silent --mode=link %s %s -static -o %s %s %s %s' % (
+          self.LIBTOOL, self.CC, self.LDFLAGS,
+          prog.fname, lib.fname, obj.fname, self.LIBS)
+        self._add_dep(prog, [lib, obj], cmd)
 
   def _add_compile(self, src, obj, hdrs):
     cmd = '%s --silent --mode=compile %s %s %s %s -c -o %s %s' % (
diff --git a/src/serf/test/CuTest-README.txt b/src/serf/test/CuTest-README.txt
new file mode 100644 (file)
index 0000000..81b1d93
--- /dev/null
@@ -0,0 +1,230 @@
+Originally obtained from "http://cutest.sourceforge.net/" version 1.4.
+
+HOW TO USE
+
+You can use CuTest to create unit tests to drive your development
+in the style of Extreme Programming. You can also add unit tests to
+existing code to ensure that it works as you suspect.
+
+Your unit tests are an investment. They let you to change your
+code and add new features confidently without worrying about
+accidentally breaking earlier features.
+
+
+LICENSING
+
+Copyright (c) 2003 Asim Jalis
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+claim that you wrote the original software. If you use this software in
+a product, an acknowledgment in the product documentation would be
+appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and must not
+be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+
+
+GETTING STARTED
+
+To add unit testing to your C code the only files you need are
+CuTest.c and CuTest.h.
+
+CuTestTest.c and AllTests.c have been included to provide an
+example of how to write unit tests and then how to aggregate them
+into suites and into a single AllTests.c file. Suites allow you
+to put group tests into logical sets. AllTests.c combines all the
+suites and runs them.
+
+You should not have to look inside CuTest.c. Looking in
+CuTestTest.c and AllTests.c (for example usage) should be
+sufficient.
+
+After downloading the sources, run your compiler to create an
+executable called AllTests.exe. For example, if you are using
+Windows with the cl.exe compiler you would type:
+
+    cl.exe AllTests.c CuTest.c CuTestTest.c
+    AllTests.exe
+
+This will run all the unit tests associated with CuTest and print
+the output on the console. You can replace cl.exe with gcc or
+your favorite compiler in the command above.
+
+
+DETAILED EXAMPLE
+
+Here is a more detailed example. We will work through a simple
+test first exercise. The goal is to create a library of string
+utilities. First, lets write a function that converts a
+null-terminated string to all upper case.
+
+Ensure that CuTest.c and CuTest.h are accessible from your C
+project. Next, create a file called StrUtil.c with these
+contents:
+
+    #include "CuTest.h"
+
+    char* StrToUpper(char* str) {
+        return str;
+    }
+
+    void TestStrToUpper(CuTest *tc) {
+        char* input = strdup("hello world");
+        char* actual = StrToUpper(input);
+        char* expected = "HELLO WORLD";
+        CuAssertStrEquals(tc, expected, actual);
+    }
+
+    CuSuite* StrUtilGetSuite() {
+        CuSuite* suite = CuSuiteNew();
+        SUITE_ADD_TEST(suite, TestStrToUpper);
+        return suite;
+    }
+
+Create another file called AllTests.c with these contents:
+
+    #include "CuTest.h"
+
+    CuSuite* StrUtilGetSuite();
+
+    void RunAllTests(void) {
+        CuString *output = CuStringNew();
+        CuSuite* suite = CuSuiteNew();
+
+        CuSuiteAddSuite(suite, StrUtilGetSuite());
+
+        CuSuiteRun(suite);
+        CuSuiteSummary(suite, output);
+        CuSuiteDetails(suite, output);
+        printf("%s\n", output->buffer);
+    }
+
+    int main(void) {
+        RunAllTests();
+    }
+
+Then type this on the command line:
+
+    gcc AllTests.c CuTest.c StrUtil.c
+
+to compile. You can replace gcc with your favorite compiler.
+CuTest should be portable enough to handle all Windows and Unix
+compilers. Then to run the tests type:
+
+    a.out
+
+This will print an error because we haven't implemented the
+StrToUpper function correctly. We are just returning the string
+without changing it to upper case.
+
+    char* StrToUpper(char* str) {
+        return str;
+    }
+
+Rewrite this as follows:
+
+    char* StrToUpper(char* str) {
+        char* p;
+        for (p = str ; *p ; ++p) *p = toupper(*p);
+        return str;
+    }
+
+Recompile and run the tests again. The test should pass this
+time.
+
+
+WHAT TO DO NEXT
+
+At this point you might want to write more tests for the
+StrToUpper function. Here are some ideas:
+
+TestStrToUpper_EmptyString :  pass in ""
+TestStrToUpper_UpperCase   :  pass in "HELLO WORLD"
+TestStrToUpper_MixedCase   :  pass in "HELLO world"
+TestStrToUpper_Numbers     :  pass in "1234 hello"
+
+As you write each one of these tests add it to StrUtilGetSuite
+function. If you don't the tests won't be run. Later as you write
+other functions and write tests for them be sure to include those
+in StrUtilGetSuite also. The StrUtilGetSuite function should
+include all the tests in StrUtil.c
+
+Over time you will create another file called FunkyStuff.c
+containing other functions unrelated to StrUtil. Follow the same
+pattern. Create a FunkyStuffGetSuite function in FunkyStuff.c.
+And add FunkyStuffGetSuite to AllTests.c.
+
+The framework is designed in the way it is so that it is easy to
+organize a lot of tests.
+
+THE BIG PICTURE
+
+Each individual test corresponds to a CuTest. These are grouped
+to form a CuSuite. CuSuites can hold CuTests or other CuSuites.
+AllTests.c collects all the CuSuites in the program into a single
+CuSuite which it then runs as a single CuSuite.
+
+The project is open source so feel free to take a peek under the
+hood at the CuTest.c file to see how it works. CuTestTest.c
+contains tests for CuTest.c. So CuTest tests itself.
+
+Since AllTests.c has a main() you will need to exclude this when
+you are building your product. Here is a nicer way to do this if
+you want to avoid messing with multiple builds. Remove the main()
+in AllTests.c. Note that it just calls RunAllTests(). Instead
+we'll call this directly from the main program.
+
+Now in the main() of the actual program check to see if the
+command line option "--test" was passed. If it was then I call
+RunAllTests() from AllTests.c. Otherwise run the real program.
+
+Shipping the tests with the code can be useful. If you customers
+complain about a problem you can ask them to run the unit tests
+and send you the output. This can help you to quickly isolate the
+piece of your system that is malfunctioning in the customer's
+environment.
+
+CuTest offers a rich set of CuAssert functions. Here is a list:
+
+void CuAssert(CuTest* tc, char* message, int condition);
+void CuAssertTrue(CuTest* tc, int condition);
+void CuAssertStrEquals(CuTest* tc, char* expected, char* actual);
+void CuAssertIntEquals(CuTest* tc, int expected, int actual);
+void CuAssertPtrEquals(CuTest* tc, void* expected, void* actual);
+void CuAssertPtrNotNull(CuTest* tc, void* pointer);
+
+The project is open source and so you can add other more powerful
+asserts to make your tests easier to write and more concise.
+Please feel free to send me changes you make so that I can
+incorporate them into future releases.
+
+If you see any errors in this document please contact me at
+asimjalis@peakprogramming.com.
+
+
+AUTOMATING TEST SUITE GENERATION
+
+make-tests.sh will grep through all the .c files in the current
+directory and generate the code to run all the tests contained in
+them. Using this script you don't have to worry about writing
+AllTests.c or dealing with any of the other suite code.
+
+
+CREDITS
+
+[02.23.2003] Dave Glowacki <dglo@hyde.ssec.wisc.edu> has added
+(1) file name and line numbers to the error messages, (2)
+AssertDblEquals for doubles, (3) Assert<X>Equals_Msg version of
+all the Assert<X>Equals to pass in optional message which is
+printed out on assert failure.
diff --git a/src/serf/test/CuTest.c b/src/serf/test/CuTest.c
new file mode 100644 (file)
index 0000000..277fe0e
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 2003 Asim Jalis
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any
+ *  damages arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any
+ *  purpose, including commercial applications, and to alter it and
+ *  redistribute it freely, subject to the following restrictions:
+ *
+ *  1. The origin of this software must not be misrepresented; you
+ *  must not claim that you wrote the original software. If you use
+ *  this software in a product, an acknowledgment in the product
+ *  documentation would be appreciated but is not required.
+ *
+ *  2. Altered source versions must be plainly marked as such, and
+ *  must not be misrepresented as being the original software.
+ *
+ *  3. This notice may not be removed or altered from any source
+ *  distribution.
+ *-------------------------------------------------------------------------*
+ *
+ * Originally obtained from "http://cutest.sourceforge.net/" version 1.4.
+ *
+ * Modified for serf as follows
+ *    1) added CuStringFree(), CuTestFree(), CuSuiteFree(), and
+ *       CuSuiteFreeDeep()
+ *    0) reformatted the whitespace (doh!)
+ */
+#include <assert.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include "CuTest.h"
+
+/*-------------------------------------------------------------------------*
+ * CuStr
+ *-------------------------------------------------------------------------*/
+
+char* CuStrAlloc(int size)
+{
+    char* newStr = (char*) malloc( sizeof(char) * (size) );
+    return newStr;
+}
+
+char* CuStrCopy(const char* old)
+{
+    int len = strlen(old);
+    char* newStr = CuStrAlloc(len + 1);
+    strcpy(newStr, old);
+    return newStr;
+}
+
+/*-------------------------------------------------------------------------*
+ * CuString
+ *-------------------------------------------------------------------------*/
+
+void CuStringInit(CuString* str)
+{
+    str->length = 0;
+    str->size = STRING_MAX;
+    str->buffer = (char*) malloc(sizeof(char) * str->size);
+    str->buffer[0] = '\0';
+}
+
+CuString* CuStringNew(void)
+{
+    CuString* str = (CuString*) malloc(sizeof(CuString));
+    str->length = 0;
+    str->size = STRING_MAX;
+    str->buffer = (char*) malloc(sizeof(char) * str->size);
+    str->buffer[0] = '\0';
+    return str;
+}
+
+void CuStringFree(CuString *str)
+{
+    free(str->buffer);
+    free(str);
+}
+
+void CuStringResize(CuString* str, int newSize)
+{
+    str->buffer = (char*) realloc(str->buffer, sizeof(char) * newSize);
+    str->size = newSize;
+}
+
+void CuStringAppend(CuString* str, const char* text)
+{
+    int length;
+
+    if (text == NULL) {
+        text = "NULL";
+    }
+
+    length = strlen(text);
+    if (str->length + length + 1 >= str->size)
+        CuStringResize(str, str->length + length + 1 + STRING_INC);
+    str->length += length;
+    strcat(str->buffer, text);
+}
+
+void CuStringAppendChar(CuString* str, char ch)
+{
+    char text[2];
+    text[0] = ch;
+    text[1] = '\0';
+    CuStringAppend(str, text);
+}
+
+void CuStringAppendFormat(CuString* str, const char* format, ...)
+{
+    va_list argp;
+    char buf[HUGE_STRING_LEN];
+    va_start(argp, format);
+    vsprintf(buf, format, argp);
+    va_end(argp);
+    CuStringAppend(str, buf);
+}
+
+void CuStringInsert(CuString* str, const char* text, int pos)
+{
+    int length = strlen(text);
+    if (pos > str->length)
+        pos = str->length;
+    if (str->length + length + 1 >= str->size)
+        CuStringResize(str, str->length + length + 1 + STRING_INC);
+    memmove(str->buffer + pos + length, str->buffer + pos, (str->length - pos) + 1);
+    str->length += length;
+    memcpy(str->buffer + pos, text, length);
+}
+
+/*-------------------------------------------------------------------------*
+ * CuTest
+ *-------------------------------------------------------------------------*/
+
+void CuTestInit(CuTest* t, const char* name, TestFunction function)
+{
+    t->name = CuStrCopy(name);
+    t->failed = 0;
+    t->ran = 0;
+    t->message = NULL;
+    t->function = function;
+    t->jumpBuf = NULL;
+}
+
+CuTest* CuTestNew(const char* name, TestFunction function)
+{
+    CuTest* tc = CU_ALLOC(CuTest);
+    CuTestInit(tc, name, function);
+    return tc;
+}
+
+void CuTestFree(CuTest* tc)
+{
+    free(tc->name);
+    free(tc);
+}
+
+void CuTestRun(CuTest* tc)
+{
+    jmp_buf buf;
+    tc->jumpBuf = &buf;
+    if (setjmp(buf) == 0)
+    {
+        tc->ran = 1;
+        (tc->function)(tc);
+    }
+    tc->jumpBuf = 0;
+}
+
+static void CuFailInternal(CuTest* tc, const char* file, int line, CuString* string)
+{
+    char buf[HUGE_STRING_LEN];
+
+    sprintf(buf, "%s:%d: ", file, line);
+    CuStringInsert(string, buf, 0);
+
+    tc->failed = 1;
+    tc->message = string->buffer;
+    if (tc->jumpBuf != 0) longjmp(*(tc->jumpBuf), 0);
+}
+
+void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message)
+{
+    CuString string;
+
+    CuStringInit(&string);
+    if (message2 != NULL)
+    {
+        CuStringAppend(&string, message2);
+        CuStringAppend(&string, ": ");
+    }
+    CuStringAppend(&string, message);
+    CuFailInternal(tc, file, line, &string);
+}
+
+void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition)
+{
+    if (condition) return;
+    CuFail_Line(tc, file, line, NULL, message);
+}
+
+void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
+    const char* expected, const char* actual)
+{
+    CuString string;
+    if ((expected == NULL && actual == NULL) ||
+        (expected != NULL && actual != NULL &&
+         strcmp(expected, actual) == 0))
+    {
+        return;
+    }
+
+    CuStringInit(&string);
+    if (message != NULL)
+    {
+        CuStringAppend(&string, message);
+        CuStringAppend(&string, ": ");
+    }
+    CuStringAppend(&string, "expected <");
+    CuStringAppend(&string, expected);
+    CuStringAppend(&string, "> but was <");
+    CuStringAppend(&string, actual);
+    CuStringAppend(&string, ">");
+    CuFailInternal(tc, file, line, &string);
+}
+
+void CuAssertIntEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
+    int expected, int actual)
+{
+    char buf[STRING_MAX];
+    if (expected == actual) return;
+    sprintf(buf, "expected <%d> but was <%d>", expected, actual);
+    CuFail_Line(tc, file, line, message, buf);
+}
+
+void CuAssertDblEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
+    double expected, double actual, double delta)
+{
+    char buf[STRING_MAX];
+    if (fabs(expected - actual) <= delta) return;
+    sprintf(buf, "expected <%lf> but was <%lf>", expected, actual);
+    CuFail_Line(tc, file, line, message, buf);
+}
+
+void CuAssertPtrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
+    void* expected, void* actual)
+{
+    char buf[STRING_MAX];
+    if (expected == actual) return;
+    sprintf(buf, "expected pointer <0x%p> but was <0x%p>", expected, actual);
+    CuFail_Line(tc, file, line, message, buf);
+}
+
+
+/*-------------------------------------------------------------------------*
+ * CuSuite
+ *-------------------------------------------------------------------------*/
+
+void CuSuiteInit(CuSuite* testSuite)
+{
+    testSuite->count = 0;
+    testSuite->failCount = 0;
+}
+
+CuSuite* CuSuiteNew(void)
+{
+    CuSuite* testSuite = CU_ALLOC(CuSuite);
+    CuSuiteInit(testSuite);
+    return testSuite;
+}
+
+void CuSuiteFree(CuSuite *testSuite)
+{
+    free(testSuite);
+}
+
+void CuSuiteFreeDeep(CuSuite *testSuite)
+{
+    int i;
+    for (i = 0 ; i < testSuite->count ; ++i)
+    {
+        CuTest* testCase = testSuite->list[i];
+        CuTestFree(testCase);
+    }
+    free(testSuite);
+}
+
+void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase)
+{
+    assert(testSuite->count < MAX_TEST_CASES);
+    testSuite->list[testSuite->count] = testCase;
+    testSuite->count++;
+}
+
+void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2)
+{
+    int i;
+    for (i = 0 ; i < testSuite2->count ; ++i)
+    {
+        CuTest* testCase = testSuite2->list[i];
+        CuSuiteAdd(testSuite, testCase);
+    }
+}
+
+void CuSuiteRun(CuSuite* testSuite)
+{
+    int i;
+    for (i = 0 ; i < testSuite->count ; ++i)
+    {
+        CuTest* testCase = testSuite->list[i];
+        CuTestRun(testCase);
+        if (testCase->failed) { testSuite->failCount += 1; }
+    }
+}
+
+void CuSuiteSummary(CuSuite* testSuite, CuString* summary)
+{
+    int i;
+    for (i = 0 ; i < testSuite->count ; ++i)
+    {
+        CuTest* testCase = testSuite->list[i];
+        CuStringAppend(summary, testCase->failed ? "F" : ".");
+    }
+    CuStringAppend(summary, "\n\n");
+}
+
+void CuSuiteDetails(CuSuite* testSuite, CuString* details)
+{
+    int i;
+    int failCount = 0;
+
+    if (testSuite->failCount == 0)
+    {
+        int passCount = testSuite->count - testSuite->failCount;
+        const char* testWord = passCount == 1 ? "test" : "tests";
+        CuStringAppendFormat(details, "OK (%d %s)\n", passCount, testWord);
+    }
+    else
+    {
+        if (testSuite->failCount == 1)
+            CuStringAppend(details, "There was 1 failure:\n");
+        else
+            CuStringAppendFormat(details, "There were %d failures:\n", testSuite->failCount);
+
+        for (i = 0 ; i < testSuite->count ; ++i)
+        {
+            CuTest* testCase = testSuite->list[i];
+            if (testCase->failed)
+            {
+                failCount++;
+                CuStringAppendFormat(details, "%d) %s: %s\n",
+                    failCount, testCase->name, testCase->message);
+            }
+        }
+        CuStringAppend(details, "\n!!!FAILURES!!!\n");
+
+        CuStringAppendFormat(details, "Runs: %d ",   testSuite->count);
+        CuStringAppendFormat(details, "Passes: %d ", testSuite->count - testSuite->failCount);
+        CuStringAppendFormat(details, "Fails: %d\n",  testSuite->failCount);
+    }
+}
diff --git a/src/serf/test/CuTest.h b/src/serf/test/CuTest.h
new file mode 100644 (file)
index 0000000..a699e92
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2003 Asim Jalis
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any
+ *  damages arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any
+ *  purpose, including commercial applications, and to alter it and
+ *  redistribute it freely, subject to the following restrictions:
+ *
+ *  1. The origin of this software must not be misrepresented; you
+ *  must not claim that you wrote the original software. If you use
+ *  this software in a product, an acknowledgment in the product
+ *  documentation would be appreciated but is not required.
+ *
+ *  2. Altered source versions must be plainly marked as such, and
+ *  must not be misrepresented as being the original software.
+ *
+ *  3. This notice may not be removed or altered from any source
+ *  distribution.
+ *-------------------------------------------------------------------------*
+ *
+ * Originally obtained from "http://cutest.sourceforge.net/" version 1.4.
+ *
+ * Modified for serf as follows
+ *    2) removed const from struct CuTest.name
+ *    1) added CuStringFree(), CuTestFree(), CuSuiteFree(), and
+ *       CuSuiteFreeDeep()
+ *    0) reformatted the whitespace (doh!)
+ */
+#ifndef CU_TEST_H
+#define CU_TEST_H
+
+#include <setjmp.h>
+#include <stdarg.h>
+
+/* CuString */
+
+char* CuStrAlloc(int size);
+char* CuStrCopy(const char* old);
+
+#define CU_ALLOC(TYPE)         ((TYPE*) malloc(sizeof(TYPE)))
+
+#define HUGE_STRING_LEN        8192
+#define STRING_MAX             256
+#define STRING_INC             256
+
+typedef struct
+{
+    int length;
+    int size;
+    char* buffer;
+} CuString;
+
+void CuStringInit(CuString* str);
+CuString* CuStringNew(void);
+void CuStringFree(CuString *str);
+void CuStringRead(CuString* str, const char* path);
+void CuStringAppend(CuString* str, const char* text);
+void CuStringAppendChar(CuString* str, char ch);
+void CuStringAppendFormat(CuString* str, const char* format, ...);
+void CuStringInsert(CuString* str, const char* text, int pos);
+void CuStringResize(CuString* str, int newSize);
+
+/* CuTest */
+
+typedef struct CuTest CuTest;
+
+typedef void (*TestFunction)(CuTest *);
+
+struct CuTest
+{
+    char* name;
+    TestFunction function;
+    int failed;
+    int ran;
+    const char* message;
+    jmp_buf *jumpBuf;
+};
+
+void CuTestInit(CuTest* t, const char* name, TestFunction function);
+CuTest* CuTestNew(const char* name, TestFunction function);
+void CuTestFree(CuTest* tc);
+void CuTestRun(CuTest* tc);
+
+/* Internal versions of assert functions -- use the public versions */
+void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message);
+void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition);
+void CuAssertStrEquals_LineMsg(CuTest* tc,
+    const char* file, int line, const char* message,
+    const char* expected, const char* actual);
+void CuAssertIntEquals_LineMsg(CuTest* tc,
+    const char* file, int line, const char* message,
+    int expected, int actual);
+void CuAssertDblEquals_LineMsg(CuTest* tc,
+    const char* file, int line, const char* message,
+    double expected, double actual, double delta);
+void CuAssertPtrEquals_LineMsg(CuTest* tc,
+    const char* file, int line, const char* message,
+    void* expected, void* actual);
+
+/* public assert functions */
+
+#define CuFail(tc, ms)                        CuFail_Line(  (tc), __FILE__, __LINE__, NULL, (ms))
+#define CuAssert(tc, ms, cond)                CuAssert_Line((tc), __FILE__, __LINE__, (ms), (cond))
+#define CuAssertTrue(tc, cond)                CuAssert_Line((tc), __FILE__, __LINE__, "assert failed", (cond))
+
+#define CuAssertStrEquals(tc,ex,ac)           CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac))
+#define CuAssertStrEquals_Msg(tc,ms,ex,ac)    CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac))
+#define CuAssertIntEquals(tc,ex,ac)           CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac))
+#define CuAssertIntEquals_Msg(tc,ms,ex,ac)    CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac))
+#define CuAssertDblEquals(tc,ex,ac,dl)        CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac),(dl))
+#define CuAssertDblEquals_Msg(tc,ms,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac),(dl))
+#define CuAssertPtrEquals(tc,ex,ac)           CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac))
+#define CuAssertPtrEquals_Msg(tc,ms,ex,ac)    CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac))
+
+#define CuAssertPtrNotNull(tc,p)        CuAssert_Line((tc),__FILE__,__LINE__,"null pointer unexpected",(p != NULL))
+#define CuAssertPtrNotNullMsg(tc,msg,p) CuAssert_Line((tc),__FILE__,__LINE__,(msg),(p != NULL))
+
+/* CuSuite */
+
+#define MAX_TEST_CASES 1024
+
+#define SUITE_ADD_TEST(SUITE,TEST)     CuSuiteAdd(SUITE, CuTestNew(#TEST, TEST))
+
+typedef struct
+{
+    int count;
+    CuTest* list[MAX_TEST_CASES];
+    int failCount;
+
+} CuSuite;
+
+
+void CuSuiteInit(CuSuite* testSuite);
+CuSuite* CuSuiteNew(void);
+void CuSuiteFree(CuSuite *testSuite);
+void CuSuiteFreeDeep(CuSuite *testSuite);
+void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase);
+void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2);
+void CuSuiteRun(CuSuite* testSuite);
+void CuSuiteSummary(CuSuite* testSuite, CuString* summary);
+void CuSuiteDetails(CuSuite* testSuite, CuString* details);
+
+#endif /* CU_TEST_H */
index 8636cb7..4e810d3 100644 (file)
@@ -25,8 +25,6 @@
 
 #include "serf.h"
 
-#define SERF_VERSION_STRING "0.01"
-
 typedef struct {
     int using_ssl;
     serf_ssl_context_t *ssl_ctx;
@@ -165,7 +163,8 @@ static apr_status_t handle_response(serf_request_t *request,
 static apr_status_t setup_request(serf_request_t *request,
                                   void *setup_baton,
                                   serf_bucket_t **req_bkt,
-                                  serf_response_acceptor_t *acceptor,                                             void **acceptor_baton,
+                                  serf_response_acceptor_t *acceptor,
+                                  void **acceptor_baton,
                                   serf_response_handler_t *handler,
                                   void **handler_baton,
                                   apr_pool_t *pool)
@@ -239,7 +238,7 @@ static apr_status_t setup_request(serf_request_t *request,
     return APR_SUCCESS;
 }
 
-void print_usage(apr_pool_t *pool)
+static void print_usage(apr_pool_t *pool)
 {
     puts("serf_get [options] URL");
     puts("-h\tDisplay this help");
index a6be6ed..0bd6a11 100644 (file)
 
 #include "serf.h"
 
-/* ### should this be in the header? */
-#define SERF_VERSION_STRING "0.01"
-
-
 static apr_status_t drain_bucket(serf_bucket_t *bucket)
 {
     apr_status_t status;
index d1387bf..a8d7d85 100644 (file)
@@ -23,8 +23,6 @@
 
 #include "serf.h"
 
-#define SERF_VERSION_STRING "0.01"
-
 typedef struct {
     const char *resp_file;
     serf_bucket_t *bkt;
@@ -127,6 +125,7 @@ int main(int argc, const char **argv)
         exit(-1);
     }
     accept_ctx.resp_file = argv[1];
+    accept_ctx.bkt = NULL;
 
     apr_initialize();
     atexit(apr_terminate);
index 186ee2c..a034a3b 100644 (file)
@@ -30,7 +30,6 @@
 #include "serf.h"
 #include "serf_bucket_util.h"
 
-#define SERF_VERSION_STRING "0.01"
 /*#define SERF_VERBOSE*/
 
 #if !APR_HAS_THREADS
@@ -123,8 +122,8 @@ typedef struct {
     apr_thread_cond_t *doc_queue_condvar;
 
     const char *hostinfo;
-  
-    /* includes: path, query, fragment. */ 
+
+    /* includes: path, query, fragment. */
     char *full_path;
     apr_size_t full_path_len;
 
@@ -564,10 +563,10 @@ static void * APR_THREAD_FUNC parser_thread(apr_thread_t *thread, void *data)
     apr_pool_create(&subpool, pool);
 
     while (1) {
-        apr_pool_clear(subpool);
-
         doc_path_t *dup;
 
+        apr_pool_clear(subpool);
+
         /* Grab it. */
         apr_thread_mutex_lock(ctx->mutex);
         /* Sleep. */
diff --git a/src/serf/test/serftestca.pem b/src/serf/test/serftestca.pem
new file mode 100644 (file)
index 0000000..9a0de18
--- /dev/null
@@ -0,0 +1,66 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            c2:31:db:41:c9:7b:a9:46
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=BE, ST=Antwerp, O=In Serf we trust, Inc., OU=Test Suite, CN=Serf/emailAddress=serf@example.com, L=Mechelen
+        Validity
+            Not Before: Mar 21 13:18:17 2008 GMT
+            Not After : Mar 21 13:18:17 2011 GMT
+        Subject: C=BE, ST=Antwerp, O=In Serf we trust, Inc., OU=Test Suite, CN=Serf/emailAddress=serf@example.com, L=Mechelen
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:a1:21:58:60:ea:79:ae:9f:0f:f4:69:b5:af:55:
+                    9a:8b:da:1d:74:80:88:44:42:46:64:59:98:3e:84:
+                    e1:70:f7:18:e1:7c:8d:cc:42:27:cd:e6:31:47:51:
+                    66:3d:58:1c:f9:54:26:4f:12:b7:0e:46:a7:27:c1:
+                    ca:ac:a7:38:0f:a1:00:fb:a8:20:77:37:14:6a:7b:
+                    65:34:1c:eb:30:fa:0b:9e:57:2c:7a:04:13:50:d4:
+                    e2:7c:66:5f:97:45:75:78:47:f5:9e:68:9d:40:b9:
+                    94:d3:78:50:c8:19:10:50:52:fd:2f:b8:a1:75:74:
+                    ad:73:95:46:9a:8e:95:b2:3d
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier:
+                15:BB:2D:8C:63:10:0D:31:01:D1:C6:26:01:27:43:A5:F4:57:6E:ED
+            X509v3 Authority Key Identifier:
+                keyid:15:BB:2D:8C:63:10:0D:31:01:D1:C6:26:01:27:43:A5:F4:57:6E:ED
+                DirName:/C=BE/ST=Antwerp/O=In Serf we trust, Inc./OU=Test Suite/CN=Serf/emailAddress=serf@example.com/L=Mechelen
+                serial:C2:31:DB:41:C9:7B:A9:46
+
+            X509v3 Basic Constraints:
+                CA:TRUE
+    Signature Algorithm: sha1WithRSAEncryption
+        59:9c:b0:62:cc:a4:c0:98:68:4b:52:bf:fa:84:ee:b5:65:d5:
+        a7:51:39:77:a0:be:d6:14:b0:7a:64:2f:0d:ee:49:e8:b6:6a:
+        c7:1d:5f:bc:27:4c:25:4b:25:b7:69:5c:07:86:54:69:22:99:
+        d9:1a:5d:dd:38:c9:00:b4:29:89:7d:ce:df:b5:3f:57:05:ee:
+        5b:0e:a4:f0:bc:7a:4f:1b:ba:84:85:e8:0f:e3:6b:fa:6f:cf:
+        3f:23:7c:d0:dd:c8:95:91:46:8a:05:84:84:46:cf:e3:c8:fc:
+        9c:94:c2:dd:15:d4:6e:d1:31:0b:d9:7b:ce:1e:13:72:c9:2e:
+        a9:86
+-----BEGIN CERTIFICATE-----
+MIIDsjCCAxugAwIBAgIJAMIx20HJe6lGMA0GCSqGSIb3DQEBBQUAMIGYMQswCQYD
+VQQGEwJCRTEQMA4GA1UECBMHQW50d2VycDEfMB0GA1UEChMWSW4gU2VyZiB3ZSB0
+cnVzdCwgSW5jLjETMBEGA1UECxMKVGVzdCBTdWl0ZTENMAsGA1UEAxMEU2VyZjEf
+MB0GCSqGSIb3DQEJARYQc2VyZkBleGFtcGxlLmNvbTERMA8GA1UEBxMITWVjaGVs
+ZW4wHhcNMDgwMzIxMTMxODE3WhcNMTEwMzIxMTMxODE3WjCBmDELMAkGA1UEBhMC
+QkUxEDAOBgNVBAgTB0FudHdlcnAxHzAdBgNVBAoTFkluIFNlcmYgd2UgdHJ1c3Qs
+IEluYy4xEzARBgNVBAsTClRlc3QgU3VpdGUxDTALBgNVBAMTBFNlcmYxHzAdBgkq
+hkiG9w0BCQEWEHNlcmZAZXhhbXBsZS5jb20xETAPBgNVBAcTCE1lY2hlbGVuMIGf
+MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQChIVhg6nmunw/0abWvVZqL2h10gIhE
+QkZkWZg+hOFw9xjhfI3MQifN5jFHUWY9WBz5VCZPErcORqcnwcqspzgPoQD7qCB3
+NxRqe2U0HOsw+gueVyx6BBNQ1OJ8Zl+XRXV4R/WeaJ1AuZTTeFDIGRBQUv0vuKF1
+dK1zlUaajpWyPQIDAQABo4IBADCB/TAdBgNVHQ4EFgQUFbstjGMQDTEB0cYmASdD
+pfRXbu0wgc0GA1UdIwSBxTCBwoAUFbstjGMQDTEB0cYmASdDpfRXbu2hgZ6kgZsw
+gZgxCzAJBgNVBAYTAkJFMRAwDgYDVQQIEwdBbnR3ZXJwMR8wHQYDVQQKExZJbiBT
+ZXJmIHdlIHRydXN0LCBJbmMuMRMwEQYDVQQLEwpUZXN0IFN1aXRlMQ0wCwYDVQQD
+EwRTZXJmMR8wHQYJKoZIhvcNAQkBFhBzZXJmQGV4YW1wbGUuY29tMREwDwYDVQQH
+EwhNZWNoZWxlboIJAMIx20HJe6lGMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEF
+BQADgYEAWZywYsykwJhoS1K/+oTutWXVp1E5d6C+1hSwemQvDe5J6LZqxx1fvCdM
+JUslt2lcB4ZUaSKZ2Rpd3TjJALQpiX3O37U/VwXuWw6k8Lx6Txu6hIXoD+Nr+m/P
+PyN80N3IlZFGigWEhEbP48j8nJTC3RXUbtExC9l7zh4TcskuqYY=
+-----END CERTIFICATE-----
diff --git a/src/serf/test/test_all.c b/src/serf/test/test_all.c
new file mode 100644 (file)
index 0000000..98f59bf
--- /dev/null
@@ -0,0 +1,108 @@
+/* Copyright 2002-2007 Justin Erenkrantz and Greg Stein
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr.h"
+#include "apr_pools.h"
+#include "test_serf.h"
+#include <stdlib.h>
+
+/* Top-level pool which can be used by tests. */
+apr_pool_t *test_pool;
+
+static const struct testlist {
+    const char *testname;
+    CuSuite *(*func)(void);
+} tests[] = {
+    {"context", test_context},
+    {"buckets", test_buckets},
+    {"ssl",     test_ssl},
+    {"LastTest", NULL}
+};
+
+int main(int argc, char *argv[])
+{
+    CuSuite *alltests = NULL;
+    CuString *output = CuStringNew();
+    int i;
+    int list_provided = 0;
+    int exit_code;
+
+    apr_initialize();
+    atexit(apr_terminate);
+
+    apr_pool_create(&test_pool, NULL);
+
+    for (i = 1; i < argc; i++) {
+        if (!strcmp(argv[i], "-v")) {
+            continue;
+        }
+        if (!strcmp(argv[i], "-l")) {
+            for (i = 0; tests[i].func != NULL; i++) {
+                printf("%s\n", tests[i].testname);
+            }
+            exit(0);
+        }
+        if (argv[i][0] == '-') {
+            fprintf(stderr, "invalid option: `%s'\n", argv[i]);
+            exit(1);
+        }
+        list_provided = 1;
+    }
+
+    alltests = CuSuiteNew();
+    if (!list_provided) {
+        /* add everything */
+        for (i = 0; tests[i].func != NULL; i++) {
+            CuSuite *st = tests[i].func();
+            CuSuiteAddSuite(alltests, st);
+            CuSuiteFree(st);
+        }
+    }
+    else {
+        /* add only the tests listed */
+        for (i = 1; i < argc; i++) {
+            int j;
+            int found = 0;
+
+            if (argv[i][0] == '-') {
+                continue;
+            }
+            for (j = 0; tests[j].func != NULL; j++) {
+                if (!strcmp(argv[i], tests[j].testname)) {
+                    CuSuiteAddSuite(alltests, tests[j].func());
+                    found = 1;
+                }
+            }
+            if (!found) {
+                fprintf(stderr, "invalid test name: `%s'\n", argv[i]);
+                exit(1);
+            }
+        }
+    }
+
+    CuSuiteRun(alltests);
+    CuSuiteSummary(alltests, output);
+    CuSuiteDetails(alltests, output);
+    printf("%s\n", output->buffer);
+
+    exit_code = alltests->failCount > 0 ? 1 : 0;
+
+    CuSuiteFreeDeep(alltests);
+    CuStringFree(output);
+
+    apr_pool_destroy(test_pool);
+
+    return exit_code;
+}
diff --git a/src/serf/test/test_buckets.c b/src/serf/test/test_buckets.c
new file mode 100644 (file)
index 0000000..cbfc034
--- /dev/null
@@ -0,0 +1,163 @@
+/* Copyright 2002-2007 Justin Erenkrantz and Greg Stein
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr.h>
+#include <apr_pools.h>
+#include <apr_strings.h>
+
+#include "serf.h"
+#include "test_serf.h"
+
+#define CRLF "\r\n"
+
+static void test_simple_bucket_readline(CuTest *tc)
+{
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+                                                              NULL);
+    apr_status_t status;
+    serf_bucket_t *bkt;
+    const char *data;
+    int found;
+    apr_size_t len;
+
+    bkt = SERF_BUCKET_SIMPLE_STRING(
+        "line1" CRLF
+        "line2",
+        alloc);
+
+    /* Initialize parameters to check that they will be initialized. */
+    len = 0x112233;
+    data = 0;
+    status = serf_bucket_readline(bkt, SERF_NEWLINE_CRLF, &found, &data, &len);
+
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    CuAssertIntEquals(tc, SERF_NEWLINE_CRLF, found);
+    CuAssertIntEquals(tc, 7, len);
+    CuAssert(tc, data, strncmp("line1" CRLF, data, len) == 0);
+
+    /* Initialize parameters to check that they will be initialized. */
+    len = 0x112233;
+    data = 0;
+    status = serf_bucket_readline(bkt, SERF_NEWLINE_CRLF, &found, &data, &len);
+
+    CuAssertIntEquals(tc, APR_EOF, status);
+    CuAssertIntEquals(tc, SERF_NEWLINE_NONE, found);
+    CuAssertIntEquals(tc, 5, len);
+    CuAssert(tc, data, strncmp("line2", data, len) == 0);
+}
+
+/* Reads bucket until EOF found and compares read data with zero terminated
+   string expected. Report all failures using CuTest. */
+static void read_and_check_bucket(CuTest *tc, serf_bucket_t *bkt,
+                                  const char *expected)
+{
+    apr_status_t status;
+    do
+    {
+        const char *data;
+        apr_size_t len;
+
+        status = serf_bucket_read(bkt, SERF_READ_ALL_AVAIL, &data, &len);
+        CuAssert(tc, "Got error during bucket reading.",
+                 !SERF_BUCKET_READ_ERROR(status));
+        CuAssert(tc, "Read more data than expected.",
+                 strlen(expected) >= len);
+        CuAssert(tc, "Read data is not equal to expected.",
+                 strncmp(expected, data, len) == 0);
+
+        expected += len;
+    } while(!APR_STATUS_IS_EOF(status));
+
+    CuAssert(tc, "Read less data than expected.", strlen(expected) == 0);
+}
+
+static void test_response_bucket_read(CuTest *tc)
+{
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+                                                              NULL);
+    serf_bucket_t *bkt, *tmp;
+
+    tmp = SERF_BUCKET_SIMPLE_STRING(
+        "HTTP/1.1 200 OK" CRLF
+        "Content-Length: 7" CRLF
+        CRLF
+        "abc1234",
+        alloc);
+
+    bkt = serf_bucket_response_create(tmp, alloc);
+
+    /* Read all bucket and check it content. */
+    read_and_check_bucket(tc, bkt, "abc1234");
+}
+
+static void test_response_bucket_chunked_read(CuTest *tc)
+{
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+                                                              NULL);
+    serf_bucket_t *bkt, *tmp, *hdrs;
+
+    tmp = SERF_BUCKET_SIMPLE_STRING(
+        "HTTP/1.1 200 OK" CRLF
+        "Transfer-Encoding: chunked" CRLF
+        CRLF
+        "3" CRLF
+        "abc" CRLF
+        "4" CRLF
+        "1234" CRLF
+        "0" CRLF
+        "Footer: value" CRLF
+        CRLF,
+        alloc);
+
+    bkt = serf_bucket_response_create(tmp, alloc);
+
+    /* Read all bucket and check it content. */
+    read_and_check_bucket(tc, bkt, "abc1234");
+
+    hdrs = serf_bucket_response_get_headers(bkt);
+    CuAssertTrue(tc, hdrs != NULL);
+
+    /* Check that trailing headers parsed correctly. */
+    CuAssertStrEquals(tc, "value", serf_bucket_headers_get(hdrs, "Footer"));
+}
+
+static void test_bucket_header_set(CuTest *tc)
+{
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+                                                              NULL);
+    serf_bucket_t *hdrs = serf_bucket_headers_create(alloc);
+
+    CuAssertTrue(tc, hdrs != NULL);
+
+    serf_bucket_headers_set(hdrs, "Foo", "bar");
+
+    CuAssertStrEquals(tc, "bar", serf_bucket_headers_get(hdrs, "Foo"));
+
+    serf_bucket_headers_set(hdrs, "Foo", "baz");
+
+    CuAssertStrEquals(tc, "bar,baz", serf_bucket_headers_get(hdrs, "Foo"));
+}
+
+CuSuite *test_buckets(void)
+{
+    CuSuite *suite = CuSuiteNew();
+
+    SUITE_ADD_TEST(suite, test_simple_bucket_readline);
+    SUITE_ADD_TEST(suite, test_response_bucket_read);
+    SUITE_ADD_TEST(suite, test_response_bucket_chunked_read);
+    SUITE_ADD_TEST(suite, test_bucket_header_set);
+
+    return suite;
+}
diff --git a/src/serf/test/test_context.c b/src/serf/test/test_context.c
new file mode 100644 (file)
index 0000000..1750b00
--- /dev/null
@@ -0,0 +1,1058 @@
+/* Copyright 2002-2007 Justin Erenkrantz and Greg Stein
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+
+#include <apr.h>
+#include <apr_pools.h>
+#include <apr_strings.h>
+#include <apr_version.h>
+
+#include "serf.h"
+
+#include "test_serf.h"
+
+typedef struct {
+    serf_response_acceptor_t acceptor;
+    void *acceptor_baton;
+
+    serf_response_handler_t handler;
+
+    apr_array_header_t *sent_requests;
+    apr_array_header_t *accepted_requests;
+    apr_array_header_t *handled_requests;
+    int req_id;
+
+    const char *method;
+    const char *path;
+    int done;
+
+    const char *server_root;
+    int use_proxy;
+
+    test_baton_t *tb;
+} handler_baton_t;
+
+static serf_bucket_t* accept_response(serf_request_t *request,
+                                      serf_bucket_t *stream,
+                                      void *acceptor_baton,
+                                      apr_pool_t *pool)
+{
+    serf_bucket_t *c;
+    serf_bucket_alloc_t *bkt_alloc;
+    handler_baton_t *ctx = acceptor_baton;
+
+    /* get the per-request bucket allocator */
+    bkt_alloc = serf_request_get_alloc(request);
+
+    /* Create a barrier so the response doesn't eat us! */
+    c = serf_bucket_barrier_create(stream, bkt_alloc);
+
+    APR_ARRAY_PUSH(ctx->accepted_requests, int) = ctx->req_id;
+
+    return serf_bucket_response_create(c, bkt_alloc);
+}
+
+static apr_status_t setup_request(serf_request_t *request,
+                                  void *setup_baton,
+                                  serf_bucket_t **req_bkt,
+                                  serf_response_acceptor_t *acceptor,
+                                  void **acceptor_baton,
+                                  serf_response_handler_t *handler,
+                                  void **handler_baton,
+                                  apr_pool_t *pool)
+{
+    handler_baton_t *ctx = setup_baton;
+    serf_bucket_t *body_bkt;
+
+    /* create a simple body text */
+    const char *str = apr_psprintf(pool, "%d", ctx->req_id);
+    body_bkt = serf_bucket_simple_create(str, strlen(str), NULL, NULL,
+                                         serf_request_get_alloc(request));
+    *req_bkt =
+        serf_request_bucket_request_create(request,
+                                           ctx->method, ctx->path,
+                                           body_bkt,
+                                           serf_request_get_alloc(request));
+
+    APR_ARRAY_PUSH(ctx->sent_requests, int) = ctx->req_id;
+
+    *acceptor = ctx->acceptor;
+    *acceptor_baton = ctx;
+    *handler = ctx->handler;
+    *handler_baton = ctx;
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t handle_response(serf_request_t *request,
+                                    serf_bucket_t *response,
+                                    void *handler_baton,
+                                    apr_pool_t *pool)
+{
+    handler_baton_t *ctx = handler_baton;
+
+    if (! response) {
+        serf_connection_request_create(ctx->tb->connection,
+                                       setup_request,
+                                       ctx);
+        return APR_SUCCESS;
+    }
+
+    while (1) {
+        apr_status_t status;
+        const char *data;
+        apr_size_t len;
+
+        status = serf_bucket_read(response, 2048, &data, &len);
+        if (SERF_BUCKET_READ_ERROR(status))
+            return status;
+
+        if (APR_STATUS_IS_EOF(status)) {
+            APR_ARRAY_PUSH(ctx->handled_requests, int) = ctx->req_id;
+            ctx->done = TRUE;
+            return APR_EOF;
+        }
+
+    }
+
+    return APR_SUCCESS;
+}
+
+/* Validate that requests are sent and completed in the order of creation. */
+static void test_serf_connection_request_create(CuTest *tc)
+{
+    test_baton_t *tb;
+    serf_request_t *request1, *request2;
+    handler_baton_t handler_ctx, handler2_ctx;
+    apr_status_t status;
+    apr_pool_t *iter_pool;
+    apr_array_header_t *accepted_requests, *handled_requests, *sent_requests;
+    int i;
+    test_server_action_t action_list[] = {
+        {SERVER_RECV,
+        "GET / HTTP/1.1" CRLF
+        "Transfer-Encoding: chunked" CRLF
+        CRLF
+        "1" CRLF
+        "1" CRLF
+        "0" CRLF
+        CRLF
+        "GET / HTTP/1.1" CRLF
+        "Transfer-Encoding: chunked" CRLF
+        "" CRLF
+        "1" CRLF
+        "2" CRLF
+        "0" CRLF
+        CRLF
+        },
+        {SERVER_SEND,
+        "HTTP/1.1 200 OK" CRLF
+        "Transfer-Encoding: chunked" CRLF
+        CRLF
+        "0" CRLF
+        CRLF
+        "HTTP/1.1 200 OK" CRLF
+        "Transfer-Encoding: chunked" CRLF
+        CRLF
+        "0" CRLF
+        CRLF
+        }
+    };
+
+    accepted_requests = apr_array_make(test_pool, 2, sizeof(int));
+    sent_requests = apr_array_make(test_pool, 2, sizeof(int));
+    handled_requests = apr_array_make(test_pool, 2, sizeof(int));
+
+    /* Set up a test context with a server */
+    status = test_server_create(&tb, action_list, 2, 0, NULL, NULL, NULL,
+                                test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    handler_ctx.method = "GET";
+    handler_ctx.path = "/";
+    handler_ctx.done = FALSE;
+
+    handler_ctx.acceptor = accept_response;
+    handler_ctx.acceptor_baton = NULL;
+    handler_ctx.handler = handle_response;
+    handler_ctx.req_id = 1;
+    handler_ctx.accepted_requests = accepted_requests;
+    handler_ctx.sent_requests = sent_requests;
+    handler_ctx.handled_requests = handled_requests;
+    handler_ctx.use_proxy = FALSE;
+    handler_ctx.server_root = NULL;
+
+    request1 = serf_connection_request_create(tb->connection,
+                                              setup_request,
+                                              &handler_ctx);
+
+    handler2_ctx = handler_ctx;
+    handler2_ctx.req_id = 2;
+
+    request2 = serf_connection_request_create(tb->connection,
+                                              setup_request,
+                                              &handler2_ctx);
+
+    apr_pool_create(&iter_pool, test_pool);
+
+    while (!handler_ctx.done && !handler2_ctx.done)
+    {
+        apr_pool_clear(iter_pool);
+
+        status = test_server_run(tb, 0, iter_pool);
+        if (APR_STATUS_IS_TIMEUP(status))
+            status = APR_SUCCESS;
+        CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+        status = serf_context_run(tb->context, 0, iter_pool);
+        if (APR_STATUS_IS_TIMEUP(status))
+            status = APR_SUCCESS;
+        CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+        /* Debugging purposes only! */
+        serf_debug__closed_conn(tb->bkt_alloc);
+    }
+    apr_pool_destroy(iter_pool);
+
+    /* Check that all requests were received */
+    CuAssertIntEquals(tc, 2, sent_requests->nelts);
+    CuAssertIntEquals(tc, 2, accepted_requests->nelts);
+    CuAssertIntEquals(tc, 2, handled_requests->nelts);
+
+    /* Check that the requests were sent in the order we created them */
+    for (i = 0; i < sent_requests->nelts; i++) {
+        int req_nr = APR_ARRAY_IDX(sent_requests, i, int);
+        CuAssertIntEquals(tc, i + 1, req_nr);
+    }
+
+    /* Check that the requests were received in the order we created them */
+    for (i = 0; i < handled_requests->nelts; i++) {
+        int req_nr = APR_ARRAY_IDX(handled_requests, i, int);
+        CuAssertIntEquals(tc, i + 1, req_nr);
+    }
+
+    test_server_destroy(tb, test_pool);
+}
+
+/* Validate that priority requests are sent and completed before normal
+   requests. */
+static void test_serf_connection_priority_request_create(CuTest *tc)
+{
+    test_baton_t *tb;
+    serf_request_t *request1, *request2, *request3;
+    handler_baton_t handler_ctx, handler2_ctx, handler3_ctx;
+    apr_status_t status;
+    apr_pool_t *iter_pool;
+    apr_array_header_t *accepted_requests, *handled_requests, *sent_requests;
+    int i;
+    test_server_action_t action_list[] = {
+        {SERVER_RECV,
+         CHUNCKED_REQUEST(1, "1")
+         CHUNCKED_REQUEST(1, "2")
+         CHUNCKED_REQUEST(1, "3")
+        },
+        {SERVER_SEND,
+         CHUNKED_EMPTY_RESPONSE
+         CHUNKED_EMPTY_RESPONSE
+         CHUNKED_EMPTY_RESPONSE
+        }
+    };
+
+    accepted_requests = apr_array_make(test_pool, 3, sizeof(int));
+    sent_requests = apr_array_make(test_pool, 3, sizeof(int));
+    handled_requests = apr_array_make(test_pool, 3, sizeof(int));
+
+    /* Set up a test context with a server */
+    status = test_server_create(&tb, action_list, 2, 0, NULL, NULL, NULL,
+                                test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    handler_ctx.method = "GET";
+    handler_ctx.path = "/";
+    handler_ctx.done = FALSE;
+
+    handler_ctx.acceptor = accept_response;
+    handler_ctx.acceptor_baton = NULL;
+    handler_ctx.handler = handle_response;
+    handler_ctx.req_id = 2;
+    handler_ctx.accepted_requests = accepted_requests;
+    handler_ctx.sent_requests = sent_requests;
+    handler_ctx.handled_requests = handled_requests;
+    handler_ctx.use_proxy = FALSE;
+    handler_ctx.server_root = NULL;
+
+    request1 = serf_connection_request_create(tb->connection,
+                                              setup_request,
+                                              &handler_ctx);
+
+    handler2_ctx = handler_ctx;
+    handler2_ctx.req_id = 3;
+
+    request2 = serf_connection_request_create(tb->connection,
+                                              setup_request,
+                                              &handler2_ctx);
+    handler3_ctx = handler_ctx;
+    handler3_ctx.req_id = 1;
+
+    request3 = serf_connection_priority_request_create(tb->connection,
+                                                       setup_request,
+                                                       &handler3_ctx);
+
+    apr_pool_create(&iter_pool, test_pool);
+
+    while (!handler_ctx.done && !handler2_ctx.done && !handler3_ctx.done)
+    {
+        apr_pool_clear(iter_pool);
+
+        status = test_server_run(tb, 0, iter_pool);
+        if (APR_STATUS_IS_TIMEUP(status))
+            status = APR_SUCCESS;
+        CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+        status = serf_context_run(tb->context, 0, iter_pool);
+        if (APR_STATUS_IS_TIMEUP(status))
+            status = APR_SUCCESS;
+        CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+        /* Debugging purposes only! */
+        serf_debug__closed_conn(tb->bkt_alloc);
+    }
+    apr_pool_destroy(iter_pool);
+
+    /* Check that all requests were received */
+    CuAssertIntEquals(tc, 3, sent_requests->nelts);
+    CuAssertIntEquals(tc, 3, accepted_requests->nelts);
+    CuAssertIntEquals(tc, 3, handled_requests->nelts);
+
+    /* Check that the requests were sent in the order we created them */
+    for (i = 0; i < sent_requests->nelts; i++) {
+        int req_nr = APR_ARRAY_IDX(sent_requests, i, int);
+        CuAssertIntEquals(tc, i + 1, req_nr);
+    }
+
+    /* Check that the requests were received in the order we created them */
+    for (i = 0; i < handled_requests->nelts; i++) {
+        int req_nr = APR_ARRAY_IDX(handled_requests, i, int);
+        CuAssertIntEquals(tc, i + 1, req_nr);
+    }
+
+    test_server_destroy(tb, test_pool);
+}
+
+/* Test that serf correctly handles the 'Connection:close' header when the
+   server is planning to close the connection. */
+#define NUM_REQUESTS 10
+static void test_serf_closed_connection(CuTest *tc)
+{
+    test_baton_t *tb;
+    apr_array_header_t *accepted_requests, *handled_requests, *sent_requests;
+    apr_status_t status;
+    handler_baton_t handler_ctx[NUM_REQUESTS];
+    int done = FALSE, i;
+
+    test_server_action_t action_list[] = {
+        {SERVER_RECV,
+         CHUNCKED_REQUEST(1, "1")
+         CHUNCKED_REQUEST(1, "2")
+         CHUNCKED_REQUEST(1, "3")
+         CHUNCKED_REQUEST(1, "4")
+         CHUNCKED_REQUEST(1, "5")
+         CHUNCKED_REQUEST(1, "6")
+         CHUNCKED_REQUEST(1, "7")
+         CHUNCKED_REQUEST(1, "8")
+         CHUNCKED_REQUEST(1, "9")
+         CHUNCKED_REQUEST(2, "10")
+        },
+        {SERVER_SEND,
+         CHUNKED_EMPTY_RESPONSE
+         CHUNKED_EMPTY_RESPONSE
+         CHUNKED_EMPTY_RESPONSE
+         "HTTP/1.1 200 OK" CRLF
+         "Transfer-Encoding: chunked" CRLF
+         "Connection: close" CRLF
+         CRLF
+         "0" CRLF
+         CRLF
+        },
+        {SERVER_KILL_CONNECTION},
+        {SERVER_SEND,
+         CHUNKED_EMPTY_RESPONSE
+         CHUNKED_EMPTY_RESPONSE
+         CHUNKED_EMPTY_RESPONSE
+         "HTTP/1.1 200 OK" CRLF
+         "Transfer-Encoding: chunked" CRLF
+         "Connection: close" CRLF
+         CRLF
+         "0" CRLF
+         CRLF
+        },
+        {SERVER_KILL_CONNECTION},
+        {SERVER_SEND,
+         CHUNKED_EMPTY_RESPONSE
+         CHUNKED_EMPTY_RESPONSE
+        },
+    };
+
+    accepted_requests = apr_array_make(test_pool, NUM_REQUESTS, sizeof(int));
+    sent_requests = apr_array_make(test_pool, NUM_REQUESTS, sizeof(int));
+    handled_requests = apr_array_make(test_pool, NUM_REQUESTS, sizeof(int));
+
+    /* Set up a test context with a server. */
+    status = test_server_create(&tb, action_list, 6, 0, NULL, NULL, NULL,
+                                test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    for (i = 0 ; i < NUM_REQUESTS ; i++) {
+        /* Send some requests on the connections */
+        handler_ctx[i].method = "GET";
+        handler_ctx[i].path = "/";
+        handler_ctx[i].done = FALSE;
+
+        handler_ctx[i].acceptor = accept_response;
+        handler_ctx[i].acceptor_baton = NULL;
+        handler_ctx[i].handler = handle_response;
+        handler_ctx[i].req_id = i+1;
+        handler_ctx[i].accepted_requests = accepted_requests;
+        handler_ctx[i].sent_requests = sent_requests;
+        handler_ctx[i].handled_requests = handled_requests;
+        handler_ctx[i].tb = tb;
+        handler_ctx[i].use_proxy = FALSE;
+        handler_ctx[i].server_root = NULL;
+
+        serf_connection_request_create(tb->connection,
+                                       setup_request,
+                                       &handler_ctx[i]);
+    }
+
+    while (1) {
+        status = test_server_run(tb, 0, test_pool);
+        if (APR_STATUS_IS_TIMEUP(status))
+            status = APR_SUCCESS;
+        CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+        status = serf_context_run(tb->context, 0, test_pool);
+        if (APR_STATUS_IS_TIMEUP(status))
+            status = APR_SUCCESS;
+        CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+        /* Debugging purposes only! */
+        serf_debug__closed_conn(tb->bkt_alloc);
+
+        done = TRUE;
+        for (i = 0 ; i < NUM_REQUESTS ; i++)
+            if (handler_ctx[i].done == FALSE) {
+                done = FALSE;
+                break;
+            }
+        if (done)
+            break;
+    }
+
+    /* Check that all requests were received */
+    CuAssertTrue(tc, sent_requests->nelts >= NUM_REQUESTS);
+    CuAssertIntEquals(tc, NUM_REQUESTS, accepted_requests->nelts);
+    CuAssertIntEquals(tc, NUM_REQUESTS, handled_requests->nelts);
+
+    /* Cleanup */
+    test_server_destroy(tb, test_pool);
+}
+#undef NUM_REQUESTS
+
+/* Test if serf is sending the request to the proxy, not to the server
+   directly. */
+static void test_serf_setup_proxy(CuTest *tc)
+{
+    test_baton_t *tb_server, *tb_proxy;
+    serf_request_t *request;
+    handler_baton_t handler_ctx;
+    apr_status_t status;
+    apr_pool_t *iter_pool;
+    apr_array_header_t *accepted_requests, *handled_requests, *sent_requests;
+    int i;
+    int numrequests = 1;
+    apr_sockaddr_t *proxy_address;
+    test_server_action_t *action_list_server = NULL;
+    test_server_action_t action_list_proxy[] = {
+        {SERVER_RECV,
+         "GET http://localhost:" SERV_PORT_STR " HTTP/1.1" CRLF\
+         "Transfer-Encoding: chunked" CRLF\
+         "Host: localhost" CRLF\
+         CRLF\
+         "1" CRLF\
+         "1" CRLF\
+         "0" CRLF\
+         CRLF
+        },
+        {SERVER_SEND,
+         CHUNKED_EMPTY_RESPONSE
+        }
+    };
+
+    accepted_requests = apr_array_make(test_pool, numrequests, sizeof(int));
+    sent_requests = apr_array_make(test_pool, numrequests, sizeof(int));
+    handled_requests = apr_array_make(test_pool, numrequests, sizeof(int));
+
+    /* Set up a test context with a server */
+    status = test_server_create(&tb_server, action_list_server, 2, 0,
+                                "http://localhost:" SERV_PORT_STR, NULL,
+                                NULL, test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    /* Set up another test context for the proxy server */
+    status = apr_sockaddr_info_get(&proxy_address,
+                                   "localhost", APR_INET, 21212, 0,
+                                   test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    status = test_server_create(&tb_proxy, action_list_proxy, 2, 0,
+                                NULL, proxy_address, NULL,
+                                test_pool);
+
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    handler_ctx.method = "GET";
+    handler_ctx.path = "/";
+    handler_ctx.done = FALSE;
+
+    handler_ctx.acceptor = accept_response;
+    handler_ctx.acceptor_baton = NULL;
+    handler_ctx.handler = handle_response;
+    handler_ctx.req_id = 1;
+    handler_ctx.accepted_requests = accepted_requests;
+    handler_ctx.sent_requests = sent_requests;
+    handler_ctx.handled_requests = handled_requests;
+    handler_ctx.use_proxy = TRUE;
+    handler_ctx.server_root = "http://localhost:" SERV_PORT_STR;
+
+    /* Configure serf to use the proxy server */
+    serf_config_proxy(tb_server->context, proxy_address);
+
+    request = serf_connection_request_create(tb_server->connection,
+                                             setup_request,
+                                             &handler_ctx);
+
+    apr_pool_create(&iter_pool, test_pool);
+
+    while (!handler_ctx.done)
+    {
+        apr_pool_clear(iter_pool);
+
+        status = test_server_run(tb_server, 0, iter_pool);
+        if (APR_STATUS_IS_TIMEUP(status))
+            status = APR_SUCCESS;
+        CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+        status = test_server_run(tb_proxy, 0, iter_pool);
+        if (APR_STATUS_IS_TIMEUP(status))
+            status = APR_SUCCESS;
+        CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+        status = serf_context_run(tb_server->context, 0, iter_pool);
+        if (APR_STATUS_IS_TIMEUP(status))
+            status = APR_SUCCESS;
+        CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+        /* Debugging purposes only! */
+        serf_debug__closed_conn(tb_server->bkt_alloc);
+    }
+    apr_pool_destroy(iter_pool);
+
+    /* Check that all requests were received */
+    CuAssertIntEquals(tc, numrequests, sent_requests->nelts);
+    CuAssertIntEquals(tc, numrequests, accepted_requests->nelts);
+    CuAssertIntEquals(tc, numrequests, handled_requests->nelts);
+
+    /* Check that the requests were sent in the order we created them */
+    for (i = 0; i < sent_requests->nelts; i++) {
+        int req_nr = APR_ARRAY_IDX(sent_requests, i, int);
+        CuAssertIntEquals(tc, i + 1, req_nr);
+    }
+
+    /* Check that the requests were received in the order we created them */
+    for (i = 0; i < handled_requests->nelts; i++) {
+        int req_nr = APR_ARRAY_IDX(handled_requests, i, int);
+        CuAssertIntEquals(tc, i + 1, req_nr);
+    }
+
+    test_server_destroy(tb_server, test_pool);
+}
+
+/*****************************************************************************
+ * Test if we can make serf send requests one by one.
+ *****************************************************************************/
+
+/* Resend the first request 4 times by reducing the pipeline bandwidth to
+   one request at a time, and by adding the first request again at the start of
+   the outgoing queue. */
+static apr_status_t
+handle_response_keepalive_limit(serf_request_t *request,
+                                serf_bucket_t *response,
+                                void *handler_baton,
+                                apr_pool_t *pool)
+{
+    handler_baton_t *ctx = handler_baton;
+
+    if (! response) {
+        return APR_SUCCESS;
+    }
+
+    while (1) {
+        apr_status_t status;
+        const char *data;
+        apr_size_t len;
+
+        status = serf_bucket_read(response, 2048, &data, &len);
+        if (SERF_BUCKET_READ_ERROR(status)) {
+            return status;
+        }
+
+        if (APR_STATUS_IS_EOF(status)) {
+            APR_ARRAY_PUSH(ctx->handled_requests, int) = ctx->req_id;
+            ctx->done = TRUE;
+            if (ctx->req_id == 1 && ctx->handled_requests->nelts < 3) {
+                serf_connection_priority_request_create(ctx->tb->connection,
+                                                        setup_request,
+                                                        ctx);
+                ctx->done = FALSE;
+            }
+            return APR_EOF;
+        }
+    }
+
+    return APR_SUCCESS;
+}
+
+#define SEND_REQUESTS 5
+#define RCVD_REQUESTS 7
+static void test_keepalive_limit_one_by_one(CuTest *tc)
+{
+    test_baton_t *tb;
+    apr_array_header_t *accepted_requests, *handled_requests, *sent_requests;
+    apr_status_t status;
+    handler_baton_t handler_ctx[SEND_REQUESTS];
+    int done = FALSE, i;
+
+    test_server_action_t action_list[] = {
+        {SERVER_RECV,
+         CHUNCKED_REQUEST(1, "1")
+        },
+        {SERVER_SEND,
+         CHUNKED_EMPTY_RESPONSE
+        },
+        {SERVER_RECV,
+         CHUNCKED_REQUEST(1, "1")
+        },
+        {SERVER_SEND,
+         CHUNKED_EMPTY_RESPONSE
+        },
+        {SERVER_RECV,
+         CHUNCKED_REQUEST(1, "1")
+        },
+        {SERVER_SEND,
+         CHUNKED_EMPTY_RESPONSE
+        },
+        {SERVER_RECV,
+         CHUNCKED_REQUEST(1, "2")
+        },
+        {SERVER_SEND,
+         CHUNKED_EMPTY_RESPONSE
+        },
+        {SERVER_RECV,
+         CHUNCKED_REQUEST(1, "3")
+        },
+        {SERVER_SEND,
+         CHUNKED_EMPTY_RESPONSE
+        },
+        {SERVER_RECV,
+         CHUNCKED_REQUEST(1, "4")
+        },
+        {SERVER_SEND,
+         CHUNKED_EMPTY_RESPONSE
+        },
+        {SERVER_RECV,
+         CHUNCKED_REQUEST(1, "5")
+        },
+        {SERVER_SEND,
+         CHUNKED_EMPTY_RESPONSE
+        },
+    };
+
+    accepted_requests = apr_array_make(test_pool, RCVD_REQUESTS, sizeof(int));
+    sent_requests = apr_array_make(test_pool, RCVD_REQUESTS, sizeof(int));
+    handled_requests = apr_array_make(test_pool, RCVD_REQUESTS, sizeof(int));
+
+    /* Set up a test context with a server. */
+    status = test_server_create(&tb, action_list, 14, 0, NULL, NULL, NULL,
+                                test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    for (i = 0 ; i < SEND_REQUESTS ; i++) {
+        /* Send some requests on the connections */
+        handler_ctx[i].method = "GET";
+        handler_ctx[i].path = "/";
+        handler_ctx[i].done = FALSE;
+
+        handler_ctx[i].acceptor = accept_response;
+        handler_ctx[i].acceptor_baton = NULL;
+        handler_ctx[i].handler = handle_response_keepalive_limit;
+        handler_ctx[i].req_id = i+1;
+        handler_ctx[i].accepted_requests = accepted_requests;
+        handler_ctx[i].sent_requests = sent_requests;
+        handler_ctx[i].handled_requests = handled_requests;
+        handler_ctx[i].tb = tb;
+        handler_ctx[i].use_proxy = FALSE;
+        handler_ctx[i].server_root = NULL;
+
+        serf_connection_request_create(tb->connection,
+                                       setup_request,
+                                       &handler_ctx[i]);
+        serf_connection_set_max_outstanding_requests(tb->connection, 1);
+    }
+
+    while (1) {
+        status = test_server_run(tb, 0, test_pool);
+        if (APR_STATUS_IS_TIMEUP(status))
+            status = APR_SUCCESS;
+        CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+        status = serf_context_run(tb->context, 0, test_pool);
+        if (APR_STATUS_IS_TIMEUP(status))
+            status = APR_SUCCESS;
+        CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+        /* Debugging purposes only! */
+        serf_debug__closed_conn(tb->bkt_alloc);
+
+        done = TRUE;
+        for (i = 0 ; i < SEND_REQUESTS ; i++)
+            if (handler_ctx[i].done == FALSE) {
+                done = FALSE;
+                break;
+            }
+        if (done)
+            break;
+    }
+
+    /* Check that all requests were received */
+    CuAssertIntEquals(tc, RCVD_REQUESTS, sent_requests->nelts);
+    CuAssertIntEquals(tc, RCVD_REQUESTS, accepted_requests->nelts);
+    CuAssertIntEquals(tc, RCVD_REQUESTS, handled_requests->nelts);
+
+    /* Cleanup */
+    test_server_destroy(tb, test_pool);
+}
+#undef SEND_REQUESTS
+#undef RCVD_REQUESTS
+
+/*****************************************************************************
+ * Test if we can make serf first send requests one by one, and then change
+ * back to burst mode.
+ *****************************************************************************/
+#define SEND_REQUESTS 5
+#define RCVD_REQUESTS 7
+/* Resend the first request 2 times by reducing the pipeline bandwidth to
+   one request at a time, and by adding the first request again at the start of
+   the outgoing queue. */
+static apr_status_t
+handle_response_keepalive_limit_burst(serf_request_t *request,
+                                      serf_bucket_t *response,
+                                      void *handler_baton,
+                                      apr_pool_t *pool)
+{
+    handler_baton_t *ctx = handler_baton;
+
+    if (! response) {
+        return APR_SUCCESS;
+    }
+
+    while (1) {
+        apr_status_t status;
+        const char *data;
+        apr_size_t len;
+
+        status = serf_bucket_read(response, 2048, &data, &len);
+        if (SERF_BUCKET_READ_ERROR(status)) {
+            return status;
+        }
+
+        if (APR_STATUS_IS_EOF(status)) {
+            APR_ARRAY_PUSH(ctx->handled_requests, int) = ctx->req_id;
+            ctx->done = TRUE;
+            if (ctx->req_id == 1 && ctx->handled_requests->nelts < 3) {
+                serf_connection_priority_request_create(ctx->tb->connection,
+                                                        setup_request,
+                                                        ctx);
+                ctx->done = FALSE;
+            }
+            else  {
+                /* No more one-by-one. */
+                serf_connection_set_max_outstanding_requests(ctx->tb->connection,
+                                                             0);
+            }
+            return APR_EOF;
+        }
+    }
+
+    return APR_SUCCESS;
+}
+
+static void test_keepalive_limit_one_by_one_and_burst(CuTest *tc)
+{
+    test_baton_t *tb;
+    apr_array_header_t *accepted_requests, *handled_requests, *sent_requests;
+    apr_status_t status;
+    handler_baton_t handler_ctx[SEND_REQUESTS];
+    int done = FALSE, i;
+
+    test_server_action_t action_list[] = {
+        {SERVER_RECV,
+         CHUNCKED_REQUEST(1, "1")
+        },
+        {SERVER_SEND,
+         CHUNKED_EMPTY_RESPONSE
+        },
+        {SERVER_RECV,
+         CHUNCKED_REQUEST(1, "1")
+        },
+        {SERVER_SEND,
+         CHUNKED_EMPTY_RESPONSE
+        },
+        {SERVER_RECV,
+         CHUNCKED_REQUEST(1, "1")
+        },
+        {SERVER_SEND,
+         CHUNKED_EMPTY_RESPONSE
+        },
+        {SERVER_RECV,
+         CHUNCKED_REQUEST(1, "2")
+         CHUNCKED_REQUEST(1, "3")
+         CHUNCKED_REQUEST(1, "4")
+         CHUNCKED_REQUEST(1, "5")
+        },
+        {SERVER_SEND,
+         CHUNKED_EMPTY_RESPONSE
+         CHUNKED_EMPTY_RESPONSE
+         CHUNKED_EMPTY_RESPONSE
+         CHUNKED_EMPTY_RESPONSE
+        },
+    };
+
+    accepted_requests = apr_array_make(test_pool, RCVD_REQUESTS, sizeof(int));
+    sent_requests = apr_array_make(test_pool, RCVD_REQUESTS, sizeof(int));
+    handled_requests = apr_array_make(test_pool, RCVD_REQUESTS, sizeof(int));
+
+    /* Set up a test context with a server. */
+    status = test_server_create(&tb, action_list, 8, 0, NULL, NULL, NULL,
+                                test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    for (i = 0 ; i < SEND_REQUESTS ; i++) {
+        /* Send some requests on the connections */
+        handler_ctx[i].method = "GET";
+        handler_ctx[i].path = "/";
+        handler_ctx[i].done = FALSE;
+
+        handler_ctx[i].acceptor = accept_response;
+        handler_ctx[i].acceptor_baton = NULL;
+        handler_ctx[i].handler = handle_response_keepalive_limit_burst;
+        handler_ctx[i].req_id = i+1;
+        handler_ctx[i].accepted_requests = accepted_requests;
+        handler_ctx[i].sent_requests = sent_requests;
+        handler_ctx[i].handled_requests = handled_requests;
+        handler_ctx[i].tb = tb;
+        handler_ctx[i].use_proxy = FALSE;
+        handler_ctx[i].server_root = NULL;
+
+        serf_connection_request_create(tb->connection,
+                                       setup_request,
+                                       &handler_ctx[i]);
+        serf_connection_set_max_outstanding_requests(tb->connection, 1);
+    }
+
+    while (1) {
+        status = test_server_run(tb, 0, test_pool);
+        if (APR_STATUS_IS_TIMEUP(status))
+            status = APR_SUCCESS;
+        CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+        status = serf_context_run(tb->context, 0, test_pool);
+        if (APR_STATUS_IS_TIMEUP(status))
+            status = APR_SUCCESS;
+        CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+        /* Debugging purposes only! */
+        serf_debug__closed_conn(tb->bkt_alloc);
+
+        done = TRUE;
+        for (i = 0 ; i < SEND_REQUESTS ; i++)
+            if (handler_ctx[i].done == FALSE) {
+                done = FALSE;
+                break;
+            }
+        if (done)
+            break;
+    }
+
+    /* Check that all requests were received */
+    CuAssertIntEquals(tc, RCVD_REQUESTS, sent_requests->nelts);
+    CuAssertIntEquals(tc, RCVD_REQUESTS, accepted_requests->nelts);
+    CuAssertIntEquals(tc, RCVD_REQUESTS, handled_requests->nelts);
+
+    /* Cleanup */
+    test_server_destroy(tb, test_pool);
+}
+#undef SEND_REQUESTS
+#undef RCVD_REQUESTS
+
+#define NUM_REQUESTS 5
+typedef struct {
+  apr_off_t read;
+  apr_off_t written;
+} progress_baton_t;
+
+static void
+progress_cb(void *progress_baton, apr_off_t read, apr_off_t written)
+{
+    test_baton_t *tb = progress_baton;
+    progress_baton_t *pb = tb->user_baton;
+
+    pb->read = read;
+    pb->written = written;
+}
+
+static serf_bucket_t* progress_conn_setup(apr_socket_t *skt,
+                                          void *setup_baton,
+                                          apr_pool_t *pool)
+{
+    test_baton_t *tb = setup_baton;
+
+    return serf_context_bucket_socket_create(tb->context, skt, tb->bkt_alloc);
+}
+
+static void test_serf_progress_callback(CuTest *tc)
+{
+    test_baton_t *tb;
+    apr_array_header_t *accepted_requests, *handled_requests, *sent_requests;
+    apr_status_t status;
+    handler_baton_t handler_ctx[NUM_REQUESTS];
+    int done = FALSE, i;
+    progress_baton_t *pb;
+
+    test_server_action_t action_list[] = {
+        {SERVER_RECV,
+         CHUNCKED_REQUEST(1, "1")
+         CHUNCKED_REQUEST(1, "2")
+         CHUNCKED_REQUEST(1, "3")
+         CHUNCKED_REQUEST(1, "4")
+         CHUNCKED_REQUEST(1, "5")
+        },
+        {SERVER_SEND,
+         CHUNKED_EMPTY_RESPONSE
+         CHUNKED_RESPONSE(1, "2")
+         CHUNKED_EMPTY_RESPONSE
+         CHUNKED_EMPTY_RESPONSE
+         CHUNKED_EMPTY_RESPONSE
+        },
+    };
+
+    accepted_requests = apr_array_make(test_pool, NUM_REQUESTS, sizeof(int));
+    sent_requests = apr_array_make(test_pool, NUM_REQUESTS, sizeof(int));
+    handled_requests = apr_array_make(test_pool, NUM_REQUESTS, sizeof(int));
+
+    /* Set up a test context with a server. */
+    status = test_server_create(&tb, action_list, 2, 0, NULL, NULL,
+                                progress_conn_setup, test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    /* Set up the progress callback. */
+    pb = apr_pcalloc(test_pool, sizeof(*pb));
+    tb->user_baton = pb;
+    serf_context_set_progress_cb(tb->context, progress_cb, tb);
+
+    for (i = 0 ; i < NUM_REQUESTS ; i++) {
+        /* Send some requests on the connections */
+        handler_ctx[i].method = "GET";
+        handler_ctx[i].path = "/";
+        handler_ctx[i].done = FALSE;
+
+        handler_ctx[i].acceptor = accept_response;
+        handler_ctx[i].acceptor_baton = NULL;
+        handler_ctx[i].handler = handle_response;
+        handler_ctx[i].req_id = i+1;
+        handler_ctx[i].accepted_requests = accepted_requests;
+        handler_ctx[i].sent_requests = sent_requests;
+        handler_ctx[i].handled_requests = handled_requests;
+        handler_ctx[i].tb = tb;
+        handler_ctx[i].use_proxy = FALSE;
+        handler_ctx[i].server_root = NULL;
+
+        serf_connection_request_create(tb->connection,
+                                       setup_request,
+                                       &handler_ctx[i]);
+    }
+
+    while (1) {
+        status = test_server_run(tb, 0, test_pool);
+        if (APR_STATUS_IS_TIMEUP(status))
+            status = APR_SUCCESS;
+        CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+        status = serf_context_run(tb->context, 0, test_pool);
+        if (APR_STATUS_IS_TIMEUP(status))
+            status = APR_SUCCESS;
+        CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+        /* Debugging purposes only! */
+        serf_debug__closed_conn(tb->bkt_alloc);
+
+        done = TRUE;
+        for (i = 0 ; i < NUM_REQUESTS ; i++)
+            if (handler_ctx[i].done == FALSE) {
+                done = FALSE;
+                break;
+            }
+        if (done)
+            break;
+    }
+
+    /* Check that all requests were received */
+    CuAssertTrue(tc, sent_requests->nelts >= NUM_REQUESTS);
+    CuAssertIntEquals(tc, NUM_REQUESTS, accepted_requests->nelts);
+    CuAssertIntEquals(tc, NUM_REQUESTS, handled_requests->nelts);
+
+    /* Check that progress was reported. */
+    CuAssertTrue(tc, pb->written > 0);
+    CuAssertTrue(tc, pb->read > 0);
+
+    /* Cleanup */
+    test_server_destroy(tb, test_pool);
+}
+#undef NUM_REQUESTS
+
+CuSuite *test_context(void)
+{
+    CuSuite *suite = CuSuiteNew();
+
+    SUITE_ADD_TEST(suite, test_serf_connection_request_create);
+    SUITE_ADD_TEST(suite, test_serf_connection_priority_request_create);
+    SUITE_ADD_TEST(suite, test_serf_closed_connection);
+    SUITE_ADD_TEST(suite, test_serf_setup_proxy);
+    SUITE_ADD_TEST(suite, test_keepalive_limit_one_by_one);
+    SUITE_ADD_TEST(suite, test_keepalive_limit_one_by_one_and_burst);
+    SUITE_ADD_TEST(suite, test_serf_progress_callback);
+
+    return suite;
+}
diff --git a/src/serf/test/test_serf.h b/src/serf/test/test_serf.h
new file mode 100644 (file)
index 0000000..c044e14
--- /dev/null
@@ -0,0 +1,150 @@
+/* Copyright 2002-2007 Justin Erenkrantz and Greg Stein
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TEST_SERF_H
+#define TEST_SERF_H
+
+#include "CuTest.h"
+
+#include <apr.h>
+#include <apr_pools.h>
+#include <apr_uri.h>
+
+#include "serf.h"
+
+/** These macros are provided by APR itself from version 1.3.
+ * Definitions are provided here for when using older versions of APR.
+ */
+
+/** index into an apr_array_header_t */
+#ifndef APR_ARRAY_IDX
+#define APR_ARRAY_IDX(ary,i,type) (((type *)(ary)->elts)[i])
+#endif
+
+/** easier array-pushing syntax */
+#ifndef APR_ARRAY_PUSH
+#define APR_ARRAY_PUSH(ary,type) (*((type *)apr_array_push(ary)))
+#endif
+
+extern apr_pool_t *test_pool;
+
+/* CuTest declarations */
+CuSuite *getsuite(void);
+
+CuSuite *test_context(void);
+CuSuite *test_buckets(void);
+CuSuite *test_ssl(void);
+
+/* Test setup declarations */
+
+#define CRLF "\r\n"
+
+#define CHUNCKED_REQUEST(len, body)\
+        "GET / HTTP/1.1" CRLF\
+        "Transfer-Encoding: chunked" CRLF\
+        CRLF\
+        #len CRLF\
+        body CRLF\
+        "0" CRLF\
+        CRLF
+
+#define CHUNKED_RESPONSE(len, body)\
+        "HTTP/1.1 200 OK" CRLF\
+        "Transfer-Encoding: chunked" CRLF\
+        CRLF\
+        #len CRLF\
+        body CRLF\
+        "0" CRLF\
+        CRLF
+
+#define CHUNKED_EMPTY_RESPONSE\
+        "HTTP/1.1 200 OK" CRLF\
+        "Transfer-Encoding: chunked" CRLF\
+        CRLF\
+        "0" CRLF\
+        CRLF
+
+typedef struct
+{
+    enum {
+        SERVER_RECV,
+        SERVER_SEND,
+        SERVER_KILL_CONNECTION
+    } kind;
+
+    const char *text;
+} test_server_action_t;
+
+typedef struct {
+    /* Pool for resource allocation. */
+    apr_pool_t *pool;
+
+    serf_context_t *context;
+    serf_connection_t *connection;
+    serf_bucket_alloc_t *bkt_alloc;
+    apr_int32_t options;
+
+    /* Array of actions which server will replay when client connected. */
+    test_server_action_t *action_list;
+    /* Size of action_list array. */
+    apr_size_t action_count;
+    /* Index of current action. */
+    apr_size_t cur_action;
+
+    /* Position in action buffer. */
+    apr_size_t action_buf_pos;
+
+    /* Address for server binding. */
+    apr_sockaddr_t *serv_addr;
+    apr_socket_t *serv_sock;
+
+    /* Accepted client socket. NULL if there is no client socket. */
+    apr_socket_t *client_sock;
+
+    /* An extra baton which can be freely used by tests. */
+    void *user_baton;
+
+} test_baton_t;
+
+#define TEST_SERVER_DUMP 1
+
+/* Default port for our test server. */
+#define SERV_PORT 12345
+#define SERV_PORT_STR "12345"
+
+apr_status_t test_server_create(test_baton_t **tb,
+                                test_server_action_t *action_list,
+                                apr_size_t action_count,
+                                apr_int32_t options,
+                                const char *host_url,
+                                apr_sockaddr_t *address,
+                                serf_connection_setup_t conn_setup,
+                                apr_pool_t *pool);
+
+apr_status_t test_server_run(test_baton_t *tb,
+                             apr_short_interval_time_t duration,
+                             apr_pool_t *pool);
+
+apr_status_t test_server_destroy(test_baton_t *tb, apr_pool_t *pool);
+
+#ifndef APR_VERSION_AT_LEAST /* Introduced in APR 1.3.0 */
+#define APR_VERSION_AT_LEAST(major,minor,patch)                  \
+(((major) < APR_MAJOR_VERSION)                                       \
+ || ((major) == APR_MAJOR_VERSION && (minor) < APR_MINOR_VERSION)    \
+ || ((major) == APR_MAJOR_VERSION && (minor) == APR_MINOR_VERSION && \
+     (patch) <= APR_PATCH_VERSION))
+#endif /* APR_VERSION_AT_LEAST */
+
+#endif /* TEST_SERF_H */
diff --git a/src/serf/test/test_ssl.c b/src/serf/test/test_ssl.c
new file mode 100644 (file)
index 0000000..23eefcf
--- /dev/null
@@ -0,0 +1,81 @@
+/* Copyright 2008 Justin Erenkrantz and Greg Stein
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr.h>
+#include <apr_pools.h>
+#include <apr_strings.h>
+
+#include "serf.h"
+#include "serf_bucket_types.h"
+
+#include "test_serf.h"
+
+#ifdef WIN32
+/* Include this file to allow running a Debug build of serf with a Release
+   build of OpenSSL. */
+#include <openssl/applink.c>
+#endif
+
+/* Test that loading a custom CA certificate file works. */
+static void test_ssl_load_cert_file(CuTest *tc)
+{
+    serf_ssl_certificate_t *cert = NULL;
+    apr_status_t status = serf_ssl_load_cert_file(&cert, "test/serftestca.pem",
+                                                  test_pool);
+
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    CuAssertPtrNotNull(tc, cert);
+}
+
+/* Test that reading a custom CA certificate file works. */
+static void test_ssl_cert_subject(CuTest *tc)
+{
+    apr_pool_t *subpool;
+    apr_hash_t *subject;
+    serf_ssl_certificate_t *cert = NULL;
+    apr_status_t status;
+
+    apr_pool_create(&subpool, test_pool);
+    status = serf_ssl_load_cert_file(&cert, "test/serftestca.pem", subpool);
+
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    CuAssertPtrNotNull(tc, cert);
+
+    subject = serf_ssl_cert_subject(cert, subpool);
+    CuAssertStrEquals(tc, "Test Suite",
+                      apr_hash_get(subject, "OU", APR_HASH_KEY_STRING));
+    CuAssertStrEquals(tc, "In Serf we trust, Inc.",
+                      apr_hash_get(subject, "O", APR_HASH_KEY_STRING));
+    CuAssertStrEquals(tc, "Mechelen",
+                      apr_hash_get(subject, "L", APR_HASH_KEY_STRING));
+    CuAssertStrEquals(tc, "Antwerp",
+                      apr_hash_get(subject, "ST", APR_HASH_KEY_STRING));
+    CuAssertStrEquals(tc, "BE",
+                      apr_hash_get(subject, "C", APR_HASH_KEY_STRING));
+    CuAssertStrEquals(tc, "serf@example.com",
+                      apr_hash_get(subject, "E", APR_HASH_KEY_STRING));
+
+    apr_pool_destroy(subpool);
+}
+
+CuSuite *test_ssl(void)
+{
+    CuSuite *suite = CuSuiteNew();
+
+    SUITE_ADD_TEST(suite, test_ssl_load_cert_file);
+    SUITE_ADD_TEST(suite, test_ssl_cert_subject);
+
+    return suite;
+}
diff --git a/src/serf/test/test_util.c b/src/serf/test/test_util.c
new file mode 100644 (file)
index 0000000..fef32dc
--- /dev/null
@@ -0,0 +1,359 @@
+/* Copyright 2002-2007 Justin Erenkrantz and Greg Stein
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr.h"
+#include "apr_pools.h"
+#include <apr_poll.h>
+#include <apr_version.h>
+#include <stdlib.h>
+
+#include "serf.h"
+
+#include "test_serf.h"
+
+/*****************************************************************************/
+/* Server setup functions
+ */
+
+/* Default implementation of a serf_connection_closed_t callback. */
+static void default_closed_connection(serf_connection_t *conn,
+                                      void *closed_baton,
+                                      apr_status_t why,
+                                      apr_pool_t *pool)
+{
+    if (why) {
+        abort();
+    }
+}
+
+/* Default implementation of a serf_connection_setup_t callback. */
+static serf_bucket_t* default_conn_setup(apr_socket_t *skt,
+                                         void *setup_baton,
+                                         apr_pool_t *pool)
+{
+    test_baton_t *ctx = setup_baton;
+
+    return serf_bucket_socket_create(skt, ctx->bkt_alloc);
+}
+
+static apr_status_t get_server_address(apr_sockaddr_t **address,
+                                       apr_pool_t *pool)
+{
+    return apr_sockaddr_info_get(address,
+                                 "localhost", APR_INET, SERV_PORT, 0,
+                                 pool);
+}
+
+static void next_action(test_baton_t *tb)
+{
+    tb->cur_action++;
+    tb->action_buf_pos = 0;
+}
+
+static apr_status_t replay(test_baton_t *tb,
+                           apr_pool_t *pool)
+{
+    apr_status_t status = APR_SUCCESS;
+    test_server_action_t *action;
+
+    if (tb->cur_action >= tb->action_count) {
+        char buf[128];
+        apr_size_t len = sizeof(buf);
+
+        status = apr_socket_recv(tb->client_sock, buf, &len);
+        if (! APR_STATUS_IS_EAGAIN(status)) {
+            /* we're out of actions! */
+            printf("Received more requests than expected\n");
+
+            return APR_EGENERAL;
+        }
+
+        return status;
+    }
+
+    if (tb->action_list == NULL)
+    {
+        /* we're not expecting any requests to reach this server! */
+        printf("Received request where none was expected\n");
+
+        return APR_EGENERAL;
+    }
+
+    action = &tb->action_list[tb->cur_action];
+
+    if (action->kind == SERVER_RECV)
+    {
+        apr_size_t msg_len, len;
+        char buf[128];
+
+        msg_len = strlen(action->text);
+
+        len = msg_len - tb->action_buf_pos;
+        if (len > sizeof(buf))
+            len = sizeof(buf);
+
+        status = apr_socket_recv(tb->client_sock, buf, &len);
+        if (status != APR_SUCCESS)
+            return status;
+
+        if (tb->options & TEST_SERVER_DUMP)
+            fwrite(buf, len, 1, stdout);
+
+        if (strncmp(buf, action->text + tb->action_buf_pos, len) != 0) {
+            /* ## TODO: Better diagnostics. */
+            printf("Expected: (\n");
+            fwrite(action->text + tb->action_buf_pos, len, 1, stdout);
+            printf(")\n");
+            printf("Actual: (\n");
+            fwrite(buf, len, 1, stdout);
+            printf(")\n");
+
+            return APR_EGENERAL;
+        }
+
+        tb->action_buf_pos += len;
+
+        if (tb->action_buf_pos >= msg_len)
+            next_action(tb);
+    }
+    else if (action->kind == SERVER_SEND) {
+        apr_size_t msg_len;
+        apr_size_t len;
+
+        msg_len = strlen(action->text);
+        len = msg_len - tb->action_buf_pos;
+
+        status = apr_socket_send(tb->client_sock,
+                                 action->text + tb->action_buf_pos, &len);
+        if (status != APR_SUCCESS)
+            return status;
+
+        if (tb->options & TEST_SERVER_DUMP)
+            fwrite(action->text + tb->action_buf_pos, len, 1, stdout);
+
+        tb->action_buf_pos += len;
+
+        if (tb->action_buf_pos >= msg_len)
+            next_action(tb);
+    }
+    else if (action->kind == SERVER_KILL_CONNECTION) {
+        apr_socket_close(tb->client_sock);
+        tb->client_sock = NULL;
+        next_action(tb);
+    }
+    else {
+        abort();
+    }
+
+    return status;
+}
+
+apr_status_t test_server_run(test_baton_t *tb,
+                             apr_short_interval_time_t duration,
+                             apr_pool_t *pool)
+{
+    apr_status_t status;
+    apr_pollset_t *pollset;
+    apr_int32_t num;
+    const apr_pollfd_t *desc;
+
+    /* create a new pollset */
+    status = apr_pollset_create(&pollset, 32, pool, 0);
+    if (status != APR_SUCCESS)
+        return status;
+
+    /* Don't accept new connection while processing client connection. At
+       least for present time.*/
+    if (tb->client_sock) {
+        apr_pollfd_t pfd = { pool, APR_POLL_SOCKET, APR_POLLIN | APR_POLLOUT, 0,
+                             { NULL }, NULL };
+        pfd.desc.s = tb->client_sock;
+        status = apr_pollset_add(pollset, &pfd);
+        if (status != APR_SUCCESS)
+            goto cleanup;
+    }
+    else {
+        apr_pollfd_t pfd = { pool, APR_POLL_SOCKET, APR_POLLIN, 0,
+                             { NULL }, NULL };
+        pfd.desc.s = tb->serv_sock;
+        status = apr_pollset_add(pollset, &pfd);
+        if (status != APR_SUCCESS)
+            goto cleanup;
+    }
+
+    status = apr_pollset_poll(pollset, APR_USEC_PER_SEC >> 1, &num, &desc);
+    if (status != APR_SUCCESS)
+        goto cleanup;
+
+    while (num--) {
+        if (desc->desc.s == tb->serv_sock) {
+            status = apr_socket_accept(&tb->client_sock, tb->serv_sock,
+                                       tb->pool);
+            if (status != APR_SUCCESS)
+                goto cleanup;
+
+            apr_socket_opt_set(tb->client_sock, APR_SO_NONBLOCK, 1);
+            apr_socket_timeout_set(tb->client_sock, 0);
+
+            status = APR_SUCCESS;
+            goto cleanup;
+        }
+
+        if (desc->desc.s == tb->client_sock) {
+            /* Replay data to socket. */
+            status = replay(tb, pool);
+
+            if (APR_STATUS_IS_EOF(status)) {
+                apr_socket_close(tb->client_sock);
+                tb->client_sock = NULL;
+            }
+            else if (APR_STATUS_IS_EAGAIN(status)) {
+                status = APR_SUCCESS;
+            }
+            else if (status != APR_SUCCESS) {
+                /* Real error. */
+                goto cleanup;
+            }
+        }
+
+        desc++;
+    }
+
+cleanup:
+    apr_pollset_destroy(pollset);
+
+    return status;
+}
+
+/* Start a TCP server on port SERV_PORT in thread THREAD. srv_replay is a array
+   of action to replay when connection started. replay_count is count of
+   actions in srv_replay. */
+static apr_status_t prepare_server(test_baton_t *tb,
+                                   apr_pool_t *pool)
+{
+    apr_status_t status;
+    apr_socket_t *serv_sock;
+
+    /* create server socket */
+#if APR_VERSION_AT_LEAST(1, 0, 0)
+    status = apr_socket_create(&serv_sock, APR_INET, SOCK_STREAM, 0, pool);
+#else
+    status = apr_socket_create(&serv_sock, APR_INET, SOCK_STREAM, pool);
+#endif
+
+    if (status != APR_SUCCESS)
+        return status;
+
+    apr_socket_opt_set(serv_sock, APR_SO_NONBLOCK, 1);
+    apr_socket_timeout_set(serv_sock, 0);
+    apr_socket_opt_set(serv_sock, APR_SO_REUSEADDR, 1);
+
+    status = apr_socket_bind(serv_sock, tb->serv_addr);
+    if (status != APR_SUCCESS)
+        return status;
+
+    /* Start replay from first action. */
+    tb->cur_action = 0;
+    tb->action_buf_pos = 0;
+
+    /* listen for clients */
+    apr_socket_listen(serv_sock, SOMAXCONN);
+    if (status != APR_SUCCESS)
+        return status;
+
+    tb->serv_sock = serv_sock;
+    tb->client_sock = NULL;
+    return APR_SUCCESS;
+}
+
+/*****************************************************************************/
+
+apr_status_t test_server_create(test_baton_t **tb_p,
+                                test_server_action_t *action_list,
+                                apr_size_t action_count,
+                                apr_int32_t options,
+                                const char *host_url,
+                                apr_sockaddr_t *address,
+                                serf_connection_setup_t conn_setup,
+                                apr_pool_t *pool)
+{
+    apr_status_t status;
+    test_baton_t *tb;
+
+    tb = apr_palloc(pool, sizeof(*tb));
+    *tb_p = tb;
+
+    if (address) {
+        tb->serv_addr = address;
+    }
+    else {
+        status = get_server_address(&tb->serv_addr, pool);
+        if (status != APR_SUCCESS)
+          return status;
+    }
+
+    tb->pool = pool;
+    tb->options = options;
+    tb->context = serf_context_create(pool);
+    tb->bkt_alloc = serf_bucket_allocator_create(pool, NULL, NULL);
+    if (host_url) {
+        apr_uri_t url;
+        status = apr_uri_parse(pool, host_url, &url);
+        if (status != APR_SUCCESS)
+            return status;
+
+        status = serf_connection_create2(&tb->connection, tb->context,
+                                         url,
+                                         conn_setup ? conn_setup :
+                                             default_conn_setup,
+                                         tb,
+                                         default_closed_connection,
+                                         tb,
+                                         pool);
+        if (status != APR_SUCCESS)
+          return status;
+    } else {
+        tb->connection = serf_connection_create(tb->context,
+                                                tb->serv_addr,
+                                                conn_setup ? conn_setup :
+                                                    default_conn_setup,
+                                                tb,
+                                                default_closed_connection,
+                                                tb,
+                                                pool);
+    }
+    tb->action_list = action_list;
+    tb->action_count = action_count;
+
+    /* Prepare a server. */
+    status = prepare_server(tb, pool);
+    if (status != APR_SUCCESS)
+      return status;
+
+    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;
+}
diff --git a/src/serf/test/testcases/deflate.response b/src/serf/test/testcases/deflate.response
new file mode 100644 (file)
index 0000000..0c277bf
Binary files /dev/null and b/src/serf/test/testcases/deflate.response differ