[Midnightbsd-cvs] src [9260] vendor/serf/1.3.9: serf 1.3.9

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Sun Feb 19 21:15:06 EST 2017


Revision: 9260
          http://svnweb.midnightbsd.org/src/?rev=9260
Author:   laffer1
Date:     2017-02-19 21:15:06 -0500 (Sun, 19 Feb 2017)
Log Message:
-----------
serf 1.3.9

Added Paths:
-----------
    vendor/serf/1.3.9/
    vendor/serf/1.3.9/CHANGES
    vendor/serf/1.3.9/NOTICE
    vendor/serf/1.3.9/README
    vendor/serf/1.3.9/SConstruct
    vendor/serf/1.3.9/auth/auth.c
    vendor/serf/1.3.9/auth/auth.h
    vendor/serf/1.3.9/auth/auth_basic.c
    vendor/serf/1.3.9/auth/auth_digest.c
    vendor/serf/1.3.9/auth/auth_spnego.c
    vendor/serf/1.3.9/auth/auth_spnego.h
    vendor/serf/1.3.9/auth/auth_spnego_gss.c
    vendor/serf/1.3.9/auth/auth_spnego_sspi.c
    vendor/serf/1.3.9/buckets/aggregate_buckets.c
    vendor/serf/1.3.9/buckets/allocator.c
    vendor/serf/1.3.9/buckets/barrier_buckets.c
    vendor/serf/1.3.9/buckets/buckets.c
    vendor/serf/1.3.9/buckets/bwtp_buckets.c
    vendor/serf/1.3.9/buckets/chunk_buckets.c
    vendor/serf/1.3.9/buckets/dechunk_buckets.c
    vendor/serf/1.3.9/buckets/deflate_buckets.c
    vendor/serf/1.3.9/buckets/file_buckets.c
    vendor/serf/1.3.9/buckets/headers_buckets.c
    vendor/serf/1.3.9/buckets/iovec_buckets.c
    vendor/serf/1.3.9/buckets/limit_buckets.c
    vendor/serf/1.3.9/buckets/mmap_buckets.c
    vendor/serf/1.3.9/buckets/request_buckets.c
    vendor/serf/1.3.9/buckets/response_body_buckets.c
    vendor/serf/1.3.9/buckets/response_buckets.c
    vendor/serf/1.3.9/buckets/simple_buckets.c
    vendor/serf/1.3.9/buckets/socket_buckets.c
    vendor/serf/1.3.9/buckets/ssl_buckets.c
    vendor/serf/1.3.9/build/check.py
    vendor/serf/1.3.9/build/gen_def.py
    vendor/serf/1.3.9/context.c
    vendor/serf/1.3.9/incoming.c
    vendor/serf/1.3.9/outgoing.c
    vendor/serf/1.3.9/serf.h
    vendor/serf/1.3.9/serf_bucket_types.h
    vendor/serf/1.3.9/serf_bucket_util.h
    vendor/serf/1.3.9/serf_private.h
    vendor/serf/1.3.9/ssltunnel.c
    vendor/serf/1.3.9/test/mock_buckets.c
    vendor/serf/1.3.9/test/serf_bwtp.c
    vendor/serf/1.3.9/test/serf_get.c
    vendor/serf/1.3.9/test/serf_request.c
    vendor/serf/1.3.9/test/serf_response.c
    vendor/serf/1.3.9/test/serf_server.c
    vendor/serf/1.3.9/test/serf_spider.c
    vendor/serf/1.3.9/test/server/test_server.c
    vendor/serf/1.3.9/test/server/test_server.h
    vendor/serf/1.3.9/test/server/test_sslserver.c
    vendor/serf/1.3.9/test/test_all.c
    vendor/serf/1.3.9/test/test_auth.c
    vendor/serf/1.3.9/test/test_buckets.c
    vendor/serf/1.3.9/test/test_context.c
    vendor/serf/1.3.9/test/test_serf.h
    vendor/serf/1.3.9/test/test_ssl.c
    vendor/serf/1.3.9/test/test_util.c

Removed Paths:
-------------
    vendor/serf/1.3.9/CHANGES
    vendor/serf/1.3.9/NOTICE
    vendor/serf/1.3.9/README
    vendor/serf/1.3.9/SConstruct
    vendor/serf/1.3.9/auth/auth.c
    vendor/serf/1.3.9/auth/auth.h
    vendor/serf/1.3.9/auth/auth_basic.c
    vendor/serf/1.3.9/auth/auth_digest.c
    vendor/serf/1.3.9/auth/auth_spnego.c
    vendor/serf/1.3.9/auth/auth_spnego.h
    vendor/serf/1.3.9/auth/auth_spnego_gss.c
    vendor/serf/1.3.9/auth/auth_spnego_sspi.c
    vendor/serf/1.3.9/buckets/aggregate_buckets.c
    vendor/serf/1.3.9/buckets/allocator.c
    vendor/serf/1.3.9/buckets/barrier_buckets.c
    vendor/serf/1.3.9/buckets/buckets.c
    vendor/serf/1.3.9/buckets/bwtp_buckets.c
    vendor/serf/1.3.9/buckets/chunk_buckets.c
    vendor/serf/1.3.9/buckets/dechunk_buckets.c
    vendor/serf/1.3.9/buckets/deflate_buckets.c
    vendor/serf/1.3.9/buckets/file_buckets.c
    vendor/serf/1.3.9/buckets/headers_buckets.c
    vendor/serf/1.3.9/buckets/iovec_buckets.c
    vendor/serf/1.3.9/buckets/limit_buckets.c
    vendor/serf/1.3.9/buckets/mmap_buckets.c
    vendor/serf/1.3.9/buckets/request_buckets.c
    vendor/serf/1.3.9/buckets/response_body_buckets.c
    vendor/serf/1.3.9/buckets/response_buckets.c
    vendor/serf/1.3.9/buckets/simple_buckets.c
    vendor/serf/1.3.9/buckets/socket_buckets.c
    vendor/serf/1.3.9/buckets/ssl_buckets.c
    vendor/serf/1.3.9/build/check.py
    vendor/serf/1.3.9/build/gen_def.py
    vendor/serf/1.3.9/context.c
    vendor/serf/1.3.9/incoming.c
    vendor/serf/1.3.9/outgoing.c
    vendor/serf/1.3.9/serf.h
    vendor/serf/1.3.9/serf_bucket_types.h
    vendor/serf/1.3.9/serf_bucket_util.h
    vendor/serf/1.3.9/serf_private.h
    vendor/serf/1.3.9/ssltunnel.c
    vendor/serf/1.3.9/test/mock_buckets.c
    vendor/serf/1.3.9/test/serf_bwtp.c
    vendor/serf/1.3.9/test/serf_get.c
    vendor/serf/1.3.9/test/serf_request.c
    vendor/serf/1.3.9/test/serf_response.c
    vendor/serf/1.3.9/test/serf_server.c
    vendor/serf/1.3.9/test/serf_spider.c
    vendor/serf/1.3.9/test/server/test_server.c
    vendor/serf/1.3.9/test/server/test_server.h
    vendor/serf/1.3.9/test/server/test_sslserver.c
    vendor/serf/1.3.9/test/test_all.c
    vendor/serf/1.3.9/test/test_auth.c
    vendor/serf/1.3.9/test/test_buckets.c
    vendor/serf/1.3.9/test/test_context.c
    vendor/serf/1.3.9/test/test_serf.h
    vendor/serf/1.3.9/test/test_ssl.c
    vendor/serf/1.3.9/test/test_util.c

Deleted: vendor/serf/1.3.9/CHANGES
===================================================================
--- vendor/serf/dist/CHANGES	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/CHANGES	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,291 +0,0 @@
-Serf 1.3.8 [2014-10-20, from /tags/1.3.8, rxxxx]
-Fix issue #152: CRC calculation error for gzipped http reponses > 4GB.
-Fix issue #153: SSPI CredHandle not freed when APR pool is destroyed.
-Fix issue #154: Disable SSLv2 and SSLv3 as both or broken.
-
-
-Serf 1.3.7 [2014-08-11, from /tags/1.3.7, r2411]
-  Handle NUL bytes in fields of an X.509 certificate. (r2393, r2399)
-
-
-Serf 1.3.6 [2014-06-09, from /tags/1.3.6, r2372]
-  Revert r2319 from serf 1.3.5: this change was making serf call handle_response
-    multiple times in case of an error response, leading to unexpected behavior.
-
-
-Serf 1.3.5 [2014-04-27, from /tags/1.3.5, r2355]
-  Fix issue #125: no reverse lookup during Negotiate authentication for proxies.
-  Fix a crash caused by incorrect reuse of the ssltunnel CONNECT request (r2316)
-  Cancel request if response parsing failed + authn callback set (r2319)
-  Update the expired certificates in the test suite.
-
-
-Serf 1.3.4 [2014-02-08, from /tags/1.3.4, r2310]
-  Fix issue #119: Endless loop during ssl tunnel setup with Negotiate authn
-  Fix issue #123: Can't setup ssl tunnel which sends Connection close header
-  Fix a race condition when initializing OpenSSL from multiple threads (r2263)
-  Fix issue #138: Incorrect pkg-config file when GSSAPI isn't configured
-
-
-Serf 1.3.3 [2013-12-09, from /tags/1.3.3, r2242]
-  Fix issue 129: Try more addresses of multihomed servers
-  Handle X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE correctly (r2225)
-  Return APR_TIMEUP from poll() to enable detecting connection timeouts (r2183)
-
-
-Serf 1.3.2 [2013-10-04, from /tags/1.3.2, r2195]
-  Fix issue 130: HTTP headers should be treated case-insensitively
-  Fix issue 126: Compilation breaks with Codewarrior compiler
-  Fix crash during cleanup of SSL buckets in apr_terminate() (r2145)
-  Fix Windows build: Also export functions with capital letters in .def file
-  Fix host header when url contains a username or password (r2170)
-  Ensure less TCP package fragmentation on Windows (r2145)
-  Handle authentication for responses to HEAD requests (r2178,-9)
-  Improve serf_get: add option to add request headers, allow url with query,
-     allow HEAD requests (r2143,r2175,-6)
-  Improve RFC conformance: don't expect body for certain responses (r2011,-2)
-  Do not invoke progress callback when no data was received (r2144)
-  And more test suite fixes and build warning cleanups
-  SCons-related fixes:
-   Fix build when GSSAPI not in default include path (2155)
-   Fix OpenBSD build: always map all LIBPATH entries into RPATH (r2156)
-   Checksum generation in Windows shared libraries for release builds (2162)
-   Mac OS X: Use MAJOR version only in dylib install name (r2161)
-   Use both MAJOR and MINOR version for the shared library name (2163)
-   Fix the .pc file when installing serf in a non-default LIBDIR (r2191)
-
-
-Serf 1.3.1 [2013-08-15, from /tags/1.3.1, r2138]
-  Fix issue 77: Endless loop if server doesn't accept Negotiate authentication.
-  Fix issue 114: ssl/tls renegotiation fails
-  Fix issue 120: error with ssl tunnel over proxy with KeepAlive off and
-                 Basic authentication.
-  Fixed bugs with authentication (r2057,2115,2118)
-  SCons-related fixes:
-   Fix issue 111: add flag to set custom library path
-   Fix issue 112: add soname
-   Fix issue 113: add gssapi libs in the serf pc file
-   Fix issue 115: Setting RPATH on Solaris broken in SConstruct
-   Fix issue 116: scons check should return non-zero exit staths
-   Fix issue 121: make CFLAGS, LIBS, LINKFLAGS and CPPFLAGS take a space-
-                   separated list of flags.
-   Fix issue 122: make scons PREFIX create the folder if it doesn't exist
-   Mac OS X: Fix scons --install-sandbox
-   Solaris: Fix build with cc, don't use unsupported compiler flags
-  Require SCons version 2.3.0 or higher now (for the soname support).
-
-
-Serf 1.3.0 [2013-07-23, from /tags/1.3.0, r2074]
-  Fix issue 83: use PATH rather than URI within an ssltunnel (r1952)
-  Fix issue 108: improved error reporting from the underlying socket (r1951)
-  NEW: Switch to the SCons build system; retire serfmake, serf.mak, autotools
-  Improved Basic and Digest authentication:
-    - remember credentials on a per-server basis
-    - properly manage authentication realms
-    - continue functioning when a server sets KeepAlive: off
-  Windows: add support for NTLM authentication
-  Improved 2617 compliance: always use strongest authentication (r1968,1971)
-  Fixed bugs with proxy authentication and SSL tunneling through a proxy
-  Fixed bugs the response parser (r2032,r2036)
-  SSL connection performance improvements
-  Huge expansion of the test suite
-
-
-Serf 1.2.1 [2013-06-03, from /tags/1.2.1, r1906]
-  Fix issue 95: add gssapi switches to configure (r1864, r1900)
-  Fix issue 97: skip mmap bucket if APR_HAS_MMAP is undefined (r1877)
-  Fix issue 100: building against an old Windows Platform SDK (r1881)
-  Fix issue 102: digest authentication failures (r1885)
-  Improve error return values in SSPI authentication (r1804)
-  Ensure serf-1.pc is constructed by serfmake (r1865)
-  Optimize SPNego authentication processing (r1868)
-  Reject certs that application does not like (r1794)
-  Fix possible endless loop in serf_linebuf_fetch() (r1816)
-  Windows build: dereference INTDIR in serf.mak (r1882)
-
-
-Serf 1.2.0 [2013-02-22, from /tags/1.2.0, r1726]
-  Fixed issue 94: Serf can enter an infinite loop when server aborts conn.
-  Fixed issue 91: Serf doesn't handle an incoming 408 Timeout Request
-  Fixed issue 80: Serf is not handling Negotiate authentication correctly
-  Fixed issue 77: Endless loop if server doesn't accept Negotiate authn
-  Fixed issue 93: cleanup-after-fork interferes with parent (r1714)
-  Fixed most of issue 89: Support REAL SPNEGO authentication
-  Enable Negotiate/Kerberos support for proxy servers.
-  Return error when C-L, chunked, gzip encoded response bodies were
-    truncated (due to aborted connection) (r1688)
-  Add a logging mechanism that can be enabled at compile-time.
-  Don't lookup server address if a proxy was configured. (r1706)
-  Fix an off-by-one in buffer sizing (r1695)
-  Disable SSL compression by default + API to enable it (r1692)
-  New serf_connection_get_latency() for estimated network latency (r1689)
-  New error code and RFC compliance for the HTTPS tunnel (r1701, r1644)
-  Handle EINTR when a user suspends and then backgrounds the app (r1708)
-  Minor fixes and test suite improvements.
-
-
-Serf 1.1.1 [2012-10-04, from /tags/1.1.1, r1657]
-  Fixed issue 86: ensure requeued requests are correctly handled.
-    This fixes:
-      - infinite loop with multiple connection resets or SIGPIPE errors
-      - "connection" hang where we would not re-queue requests that are
-        held after we re-connect
-  Fixed issue 74: test_all goes in an endless loop
-  Fix memleak when conn. is closed explicitly/due to pool cleanups (r1623)
-  Windows: Fix https connection aborts (r1628..-30,-33,-34,-37)
-  Add new error codes for the SSL bucket
-
-
-Serf 1.1.0 [2012-06-07, from /tags/1.1.0, r1617]
-  New: serf_bucket_request_set_CL() for C-L based, non-chunked requests
-  New: serf_ssl_server_cert_chain_callback_set() for full-chain validation
-
-
-Serf 1.0.3 [2012-03-20, from /tags/1.0.3, r1586]
-  Map more OpenSSL errors into SERF_SSL_CERT_UNKNOWNCA (r1573)
-
-
-Serf 1.0.2
-  Not released.
-
-
-Serf 1.0.1 [2012-02-15, from /tags/1.0.1, r1569]
-  FreeBSD fixes in the test suite (r1560, r1565)
-  Minor build fixes
-
-
-Serf 1.0.0 [2011-07-15, from /tags/1.0.0, r1540]
-  Fixed issue 38: enable builds using non-GNU make
-  Fixed issue 49: support SSL tunnels for HTTPS via a proxy
-  Fixed issue 56: allow Subject Alternative Name, and enable SNI
-  Fixed issue 61: include order dependencies
-  Fixed issue 66: improved error reporting when creating install dirs
-  Fixed issue 71: handle ECONNREFUSED on Windows
-  Fixed issue 79: destroy the APR allocator, if we create one
-  Fixed issue 81: build failed on APR 0.9.x
-  Major performance improvements and bug fixes for SSL buckets/handling (r1462)
-  Add a new "iovec" bucket type (r1434)
-  Minimize network packet writes based on ra_serf analysis (r1467, r1471)
-  Fix out of order issue with multiple priority requests (r1469)
-  Work around broken WSAPoll() impl on Windows introduced in APR 1.4.0 (r1506)
-  Fix 100% CPU usage with many pipelined requests (r1456)
-  Corrected contents of build/serf.def; it now includes bucket types (r1512)
-  Removed "snapshot" feature from buckets (r1503)
-  Various improvements to the test system
-  Various memory leak fixes
-
-
-Serf 0.7.2 [2011-03-12, from /tags/0.7.2, r1452]
-  Actually disable Nagle when creating a connection (r1441)
-  Return error when app asks for HTTPS over proxy connection (r1433)
-
-
-Serf 0.7.1 [2011-01-25, from /tags/0.7.1, r1432]
-  Fix memory leak when using SSL (r1408, r1416)
-  Fix build for blank apr-util directory (r1421)
-
-
-Serf 0.7.0 [2010-08-25, from /tags/0.7.0, r1407]
-  Fix double free abort when destroying request buckets
-  Fix test server in unit test framework to avoid random test failures
-  Allow older Serf programs which don't use the new authn framework to still
-    handle authn without forcing them to switch to the new framework. (r1401)
-  Remove the SERF_DECLARE macros, preferring a .DEF file for Windows
-  Barrier buckets now pass read_iovec to their wrapped bucket
-  Fix HTTP header parsing to allow for empty header values
-
-
-Serf 0.6.1 [2010-05-14, from /tags/0.6.1, r1370]
-  Generally: this release fixes problems with the 0.4.0 packaging
-  Small compilation fix in outgoing.c for Windows builds
-
-
-Serf 0.6.0
-  Not released.
-
-
-Serf 0.5.0
-  Not released.
-
-
-Serf 0.4.0
-  WITHDRAWN: this release misstated itself as 0.5.0; use a later release
-
-  Provide authn framework, supporting Basic, Digest, Kerberos (SSPI, GSS),
-    along with proxy authn using Basic or Digest
-  Added experimental listener framework, along with test_server.c
-  Improvements and fixes to SSL support, including connection setup changes
-  Experimental support for unrequested, arriving ("async") responses
-  Experimental BWTP support using the async arrival feature
-  Headers are combined on read (not write), to ease certian classes of parsing
-  Experimental feature on aggregate buckets for a callback-on-empty
-  Fix the bucket allocator for when APR is using its pool debugging features
-  Proxy support in the serf_get testing utility
-  Fix to include the port number in the Host header
-  serf_get propagates errors from the response, instead of aborting (Issue 52)
-  Added serf_lib_version() for runtime version tests
-
-
-Serf 0.3.1 [2010-02-14, from /tags/0.3.1, r1322]
-  Fix loss of error on request->setup() callback. (Issue 47)
-  Support APR 2.x. (Issue 48)
-  Fixed slowdown in aggregate bucket with millions of child buckets
-  Avoid hang in apr_pollset_poll() by unclosed connections after fork()
-
-
-Serf 0.3.0 [2009-01-26, from /tags/0.3.0, r1217]
-  Support LTFLAGS override as a config-time env. variable (Issue 44)
-  Fix CUTest test harness compilation on Solaris (Issue 43)
-  Fix small race condition in OpenSSL initialization (Issue 39)
-  Handle content streams larger than 4GB on 32-bit OSes (Issue 41)
-  Fix test_ssl.c compilation with mingw+msys
-  Fix conn close segfault by explicitly closing conn when pool is destroyed
-  Expose the depth of the SSL certificate so the validator can use that info
-  Fix socket address family issue when opening a connection to a proxy
-  Provide new API to take snapshots of buckets
-  Implement snapshot API for simple and aggregate buckets
-  Build with bundled apr and apr-util VPATH builds
-  Build with bundled OpenSSL builds
-
-
-Serf 0.2.0 [2008-06-06, from /tags/0.2.0, r1189]
-  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-06-18, from /tags/0.1.2, r1115]
-  Enable thread-safety with OpenSSL (Issue 19)
-  Teach serfmake to install headers into include/serf-0
-  Be more tolerant when servers close the connection without telling us
-  Do not open the connection until we have requests to deliver
-  Fix serfmake to produce the library that corresponds to the minor version
-  Fix a memory leak with the socket bucket (Issue 14)
-  Fix uninitialized branch in serf_spider (Issue 15)
-
-
-Serf 0.1.1 [2007-05-12, from /tags/0.1.1, r1105]
-  Add SSL client certificate support
-  Implement optimized iovec reads for header buckets
-  Fix up 'make clean' and 'make distclean' (Issues 9, 10)
-  Add SERF_VERSION_AT_LEAST macro
-  Remove abort() calls (Issue 13)
-
-
-Serf 0.1.0 [2006-12-14, from /tags/0.1.0, r1087]
-  Initial packaged release

Copied: vendor/serf/1.3.9/CHANGES (from rev 9259, vendor/serf/dist/CHANGES)
===================================================================
--- vendor/serf/1.3.9/CHANGES	                        (rev 0)
+++ vendor/serf/1.3.9/CHANGES	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,310 @@
+Apache Serf 1.3.9 [2016-09-01, from tags/1.3.9, rxxxx]
+  serf is now Apache Serf; apply header changes (r1700062)
+  Fix issue #151: SCons build broken when only one library in ENVPATH
+  Fix issue #153: avoid SSPI handle leak
+  Fix issue #167: Explicitly use the ANSI version of SSPI
+  Fix issue #170: Allow building with Microsoft Visual Studio 2015
+  Fix build of 'check' target when using VPATH-style builds (r1699858, ...)
+    (builddir != srcdir).
+  Resolve a bucket (aka "memory") leak when a request bucket is
+    destroyed before it is morphed into an aggregate bucket (r1699791)
+  Reset state variables when resetting connection (r1708849)
+  Fix types of passed, but unused batons (r1699986, r1699987)
+  Fix some usages of the openssl BIO api (r1699852)
+  Improve handling of bad data in the response state line. (r1699985)
+  Resolve several compiler issues with less common compilers
+  Support more overrides via SCons arguments (r1701836, ...)
+  Adapt to OpenSSL 1.1.x api (r1750819)
+
+
+Serf 1.3.8 [2014-10-20, from /tags/1.3.8, r2441]
+  Fix issue #152: CRC calculation error for gzipped http reponses > 4GB.
+  Fix issue #153: SSPI CredHandle not freed when APR pool is destroyed.
+  Fix issue #154: Disable SSLv2 and SSLv3 as both or broken.
+
+
+Serf 1.3.7 [2014-08-11, from /tags/1.3.7, r2411]
+  Handle NUL bytes in fields of an X.509 certificate. (r2393, r2399)
+
+
+Serf 1.3.6 [2014-06-09, from /tags/1.3.6, r2372]
+  Revert r2319 from serf 1.3.5: this change was making serf call handle_response
+    multiple times in case of an error response, leading to unexpected behavior.
+
+
+Serf 1.3.5 [2014-04-27, from /tags/1.3.5, r2355]
+  Fix issue #125: no reverse lookup during Negotiate authentication for proxies.
+  Fix a crash caused by incorrect reuse of the ssltunnel CONNECT request (r2316)
+  Cancel request if response parsing failed + authn callback set (r2319)
+  Update the expired certificates in the test suite.
+
+
+Serf 1.3.4 [2014-02-08, from /tags/1.3.4, r2310]
+  Fix issue #119: Endless loop during ssl tunnel setup with Negotiate authn
+  Fix issue #123: Can't setup ssl tunnel which sends Connection close header
+  Fix a race condition when initializing OpenSSL from multiple threads (r2263)
+  Fix issue #138: Incorrect pkg-config file when GSSAPI isn't configured
+
+
+Serf 1.3.3 [2013-12-09, from /tags/1.3.3, r2242]
+  Fix issue 129: Try more addresses of multihomed servers
+  Handle X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE correctly (r2225)
+  Return APR_TIMEUP from poll() to enable detecting connection timeouts (r2183)
+
+
+Serf 1.3.2 [2013-10-04, from /tags/1.3.2, r2195]
+  Fix issue 130: HTTP headers should be treated case-insensitively
+  Fix issue 126: Compilation breaks with Codewarrior compiler
+  Fix crash during cleanup of SSL buckets in apr_terminate() (r2145)
+  Fix Windows build: Also export functions with capital letters in .def file
+  Fix host header when url contains a username or password (r2170)
+  Ensure less TCP package fragmentation on Windows (r2145)
+  Handle authentication for responses to HEAD requests (r2178,-9)
+  Improve serf_get: add option to add request headers, allow url with query,
+     allow HEAD requests (r2143,r2175,-6)
+  Improve RFC conformance: don't expect body for certain responses (r2011,-2)
+  Do not invoke progress callback when no data was received (r2144)
+  And more test suite fixes and build warning cleanups
+  SCons-related fixes:
+   Fix build when GSSAPI not in default include path (2155)
+   Fix OpenBSD build: always map all LIBPATH entries into RPATH (r2156)
+   Checksum generation in Windows shared libraries for release builds (2162)
+   Mac OS X: Use MAJOR version only in dylib install name (r2161)
+   Use both MAJOR and MINOR version for the shared library name (2163)
+   Fix the .pc file when installing serf in a non-default LIBDIR (r2191)
+
+
+Serf 1.3.1 [2013-08-15, from /tags/1.3.1, r2138]
+  Fix issue 77: Endless loop if server doesn't accept Negotiate authentication.
+  Fix issue 114: ssl/tls renegotiation fails
+  Fix issue 120: error with ssl tunnel over proxy with KeepAlive off and
+                 Basic authentication.
+  Fixed bugs with authentication (r2057,2115,2118)
+  SCons-related fixes:
+   Fix issue 111: add flag to set custom library path
+   Fix issue 112: add soname
+   Fix issue 113: add gssapi libs in the serf pc file
+   Fix issue 115: Setting RPATH on Solaris broken in SConstruct
+   Fix issue 116: scons check should return non-zero exit staths
+   Fix issue 121: make CFLAGS, LIBS, LINKFLAGS and CPPFLAGS take a space-
+                   separated list of flags.
+   Fix issue 122: make scons PREFIX create the folder if it doesn't exist
+   Mac OS X: Fix scons --install-sandbox
+   Solaris: Fix build with cc, don't use unsupported compiler flags
+  Require SCons version 2.3.0 or higher now (for the soname support).
+
+
+Serf 1.3.0 [2013-07-23, from /tags/1.3.0, r2074]
+  Fix issue 83: use PATH rather than URI within an ssltunnel (r1952)
+  Fix issue 108: improved error reporting from the underlying socket (r1951)
+  NEW: Switch to the SCons build system; retire serfmake, serf.mak, autotools
+  Improved Basic and Digest authentication:
+    - remember credentials on a per-server basis
+    - properly manage authentication realms
+    - continue functioning when a server sets KeepAlive: off
+  Windows: add support for NTLM authentication
+  Improved 2617 compliance: always use strongest authentication (r1968,1971)
+  Fixed bugs with proxy authentication and SSL tunneling through a proxy
+  Fixed bugs the response parser (r2032,r2036)
+  SSL connection performance improvements
+  Huge expansion of the test suite
+
+
+Serf 1.2.1 [2013-06-03, from /tags/1.2.1, r1906]
+  Fix issue 95: add gssapi switches to configure (r1864, r1900)
+  Fix issue 97: skip mmap bucket if APR_HAS_MMAP is undefined (r1877)
+  Fix issue 100: building against an old Windows Platform SDK (r1881)
+  Fix issue 102: digest authentication failures (r1885)
+  Improve error return values in SSPI authentication (r1804)
+  Ensure serf-1.pc is constructed by serfmake (r1865)
+  Optimize SPNego authentication processing (r1868)
+  Reject certs that application does not like (r1794)
+  Fix possible endless loop in serf_linebuf_fetch() (r1816)
+  Windows build: dereference INTDIR in serf.mak (r1882)
+
+
+Serf 1.2.0 [2013-02-22, from /tags/1.2.0, r1726]
+  Fixed issue 94: Serf can enter an infinite loop when server aborts conn.
+  Fixed issue 91: Serf doesn't handle an incoming 408 Timeout Request
+  Fixed issue 80: Serf is not handling Negotiate authentication correctly
+  Fixed issue 77: Endless loop if server doesn't accept Negotiate authn
+  Fixed issue 93: cleanup-after-fork interferes with parent (r1714)
+  Fixed most of issue 89: Support REAL SPNEGO authentication
+  Enable Negotiate/Kerberos support for proxy servers.
+  Return error when C-L, chunked, gzip encoded response bodies were
+    truncated (due to aborted connection) (r1688)
+  Add a logging mechanism that can be enabled at compile-time.
+  Don't lookup server address if a proxy was configured. (r1706)
+  Fix an off-by-one in buffer sizing (r1695)
+  Disable SSL compression by default + API to enable it (r1692)
+  New serf_connection_get_latency() for estimated network latency (r1689)
+  New error code and RFC compliance for the HTTPS tunnel (r1701, r1644)
+  Handle EINTR when a user suspends and then backgrounds the app (r1708)
+  Minor fixes and test suite improvements.
+
+
+Serf 1.1.1 [2012-10-04, from /tags/1.1.1, r1657]
+  Fixed issue 86: ensure requeued requests are correctly handled.
+    This fixes:
+      - infinite loop with multiple connection resets or SIGPIPE errors
+      - "connection" hang where we would not re-queue requests that are
+        held after we re-connect
+  Fixed issue 74: test_all goes in an endless loop
+  Fix memleak when conn. is closed explicitly/due to pool cleanups (r1623)
+  Windows: Fix https connection aborts (r1628..-30,-33,-34,-37)
+  Add new error codes for the SSL bucket
+
+
+Serf 1.1.0 [2012-06-07, from /tags/1.1.0, r1617]
+  New: serf_bucket_request_set_CL() for C-L based, non-chunked requests
+  New: serf_ssl_server_cert_chain_callback_set() for full-chain validation
+
+
+Serf 1.0.3 [2012-03-20, from /tags/1.0.3, r1586]
+  Map more OpenSSL errors into SERF_SSL_CERT_UNKNOWNCA (r1573)
+
+
+Serf 1.0.2
+  Not released.
+
+
+Serf 1.0.1 [2012-02-15, from /tags/1.0.1, r1569]
+  FreeBSD fixes in the test suite (r1560, r1565)
+  Minor build fixes
+
+
+Serf 1.0.0 [2011-07-15, from /tags/1.0.0, r1540]
+  Fixed issue 38: enable builds using non-GNU make
+  Fixed issue 49: support SSL tunnels for HTTPS via a proxy
+  Fixed issue 56: allow Subject Alternative Name, and enable SNI
+  Fixed issue 61: include order dependencies
+  Fixed issue 66: improved error reporting when creating install dirs
+  Fixed issue 71: handle ECONNREFUSED on Windows
+  Fixed issue 79: destroy the APR allocator, if we create one
+  Fixed issue 81: build failed on APR 0.9.x
+  Major performance improvements and bug fixes for SSL buckets/handling (r1462)
+  Add a new "iovec" bucket type (r1434)
+  Minimize network packet writes based on ra_serf analysis (r1467, r1471)
+  Fix out of order issue with multiple priority requests (r1469)
+  Work around broken WSAPoll() impl on Windows introduced in APR 1.4.0 (r1506)
+  Fix 100% CPU usage with many pipelined requests (r1456)
+  Corrected contents of build/serf.def; it now includes bucket types (r1512)
+  Removed "snapshot" feature from buckets (r1503)
+  Various improvements to the test system
+  Various memory leak fixes
+
+
+Serf 0.7.2 [2011-03-12, from /tags/0.7.2, r1452]
+  Actually disable Nagle when creating a connection (r1441)
+  Return error when app asks for HTTPS over proxy connection (r1433)
+
+
+Serf 0.7.1 [2011-01-25, from /tags/0.7.1, r1432]
+  Fix memory leak when using SSL (r1408, r1416)
+  Fix build for blank apr-util directory (r1421)
+
+
+Serf 0.7.0 [2010-08-25, from /tags/0.7.0, r1407]
+  Fix double free abort when destroying request buckets
+  Fix test server in unit test framework to avoid random test failures
+  Allow older Serf programs which don't use the new authn framework to still
+    handle authn without forcing them to switch to the new framework. (r1401)
+  Remove the SERF_DECLARE macros, preferring a .DEF file for Windows
+  Barrier buckets now pass read_iovec to their wrapped bucket
+  Fix HTTP header parsing to allow for empty header values
+
+
+Serf 0.6.1 [2010-05-14, from /tags/0.6.1, r1370]
+  Generally: this release fixes problems with the 0.4.0 packaging
+  Small compilation fix in outgoing.c for Windows builds
+
+
+Serf 0.6.0
+  Not released.
+
+
+Serf 0.5.0
+  Not released.
+
+
+Serf 0.4.0
+  WITHDRAWN: this release misstated itself as 0.5.0; use a later release
+
+  Provide authn framework, supporting Basic, Digest, Kerberos (SSPI, GSS),
+    along with proxy authn using Basic or Digest
+  Added experimental listener framework, along with test_server.c
+  Improvements and fixes to SSL support, including connection setup changes
+  Experimental support for unrequested, arriving ("async") responses
+  Experimental BWTP support using the async arrival feature
+  Headers are combined on read (not write), to ease certian classes of parsing
+  Experimental feature on aggregate buckets for a callback-on-empty
+  Fix the bucket allocator for when APR is using its pool debugging features
+  Proxy support in the serf_get testing utility
+  Fix to include the port number in the Host header
+  serf_get propagates errors from the response, instead of aborting (Issue 52)
+  Added serf_lib_version() for runtime version tests
+
+
+Serf 0.3.1 [2010-02-14, from /tags/0.3.1, r1322]
+  Fix loss of error on request->setup() callback. (Issue 47)
+  Support APR 2.x. (Issue 48)
+  Fixed slowdown in aggregate bucket with millions of child buckets
+  Avoid hang in apr_pollset_poll() by unclosed connections after fork()
+
+
+Serf 0.3.0 [2009-01-26, from /tags/0.3.0, r1217]
+  Support LTFLAGS override as a config-time env. variable (Issue 44)
+  Fix CUTest test harness compilation on Solaris (Issue 43)
+  Fix small race condition in OpenSSL initialization (Issue 39)
+  Handle content streams larger than 4GB on 32-bit OSes (Issue 41)
+  Fix test_ssl.c compilation with mingw+msys
+  Fix conn close segfault by explicitly closing conn when pool is destroyed
+  Expose the depth of the SSL certificate so the validator can use that info
+  Fix socket address family issue when opening a connection to a proxy
+  Provide new API to take snapshots of buckets
+  Implement snapshot API for simple and aggregate buckets
+  Build with bundled apr and apr-util VPATH builds
+  Build with bundled OpenSSL builds
+
+
+Serf 0.2.0 [2008-06-06, from /tags/0.2.0, r1189]
+  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-06-18, from /tags/0.1.2, r1115]
+  Enable thread-safety with OpenSSL (Issue 19)
+  Teach serfmake to install headers into include/serf-0
+  Be more tolerant when servers close the connection without telling us
+  Do not open the connection until we have requests to deliver
+  Fix serfmake to produce the library that corresponds to the minor version
+  Fix a memory leak with the socket bucket (Issue 14)
+  Fix uninitialized branch in serf_spider (Issue 15)
+
+
+Serf 0.1.1 [2007-05-12, from /tags/0.1.1, r1105]
+  Add SSL client certificate support
+  Implement optimized iovec reads for header buckets
+  Fix up 'make clean' and 'make distclean' (Issues 9, 10)
+  Add SERF_VERSION_AT_LEAST macro
+  Remove abort() calls (Issue 13)
+
+
+Serf 0.1.0 [2006-12-14, from /tags/0.1.0, r1087]
+  Initial packaged release

Deleted: vendor/serf/1.3.9/NOTICE
===================================================================
--- vendor/serf/dist/NOTICE	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/NOTICE	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,2 +0,0 @@
-This product includes software developed by
-The Apache Software Foundation (http://www.apache.org/).

Copied: vendor/serf/1.3.9/NOTICE (from rev 9259, vendor/serf/dist/NOTICE)
===================================================================
--- vendor/serf/1.3.9/NOTICE	                        (rev 0)
+++ vendor/serf/1.3.9/NOTICE	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,7 @@
+Apache Serf
+Copyright 2015 The Apache Software Foundation
+
+This product includes software developed by many people, and distributed
+under Contributor License Agreements to The Apache Software Foundation
+(http://www.apache.org/).  See the revision logs for an exact contribution
+history.

Deleted: vendor/serf/1.3.9/README
===================================================================
--- vendor/serf/dist/README	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/README	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,93 +0,0 @@
-Welcome to serf, a high-performance asynchronous HTTP client library.
-
-The serf library is a C-based HTTP client library built upon the Apache
-Portable Runtime (APR) library. It multiplexes connections, running the
-read/write communication asynchronously. Memory copies and transformations are
-kept to a minimum to provide high performance operation.
-
-  * Status: http://code.google.com/p/serf/wiki/
-  * Site: http://code.google.com/p/serf/
-  * Code: http://serf.googlecode.com/svn/
-  * Issues: http://code.google.com/p/serf/issues/list
-  * Mail: serf-dev at googlegroups.com
-  * People: Justin Erenkrantz, Greg Stein 
-
-----
-
-1. INSTALL
-
-1.1. SCons build system
-
-serf uses SCons 2.3 for its build system. If it is not installed on
-your system, then you can install it onto your system. If you do not
-have permissions, then you can download and install the "local"
-version into your home directory. When installed privately, simply
-create a symlink for 'scons' in your PATH to /path/to/scons/scons.py.
-
-Fetch the scons-local package:
-  http://prdownloads.sourceforge.net/scons/scons-local-2.3.0.tar.gz
-
-
-1.2 Building serf
-
-To build serf:
-
-$ scons APR=/path/to/apr APU=/path/to/apu OPENSSL=/openssl/base PREFIX=/path/to/prefix
-
-The switches are recorded into .saved_config, so they only need to be
-specified the first time scons is run.
-
-PREFIX should specify where serf should be installed.  PREFIX defaults to
-/usr/local.
-
-The default for the other three switches (APR, APU, OPENSSL) is /usr.
-
-The build system looks for apr-1-config at $APR/bin/apr-1-config, or
-the path should indicate apr-1-config itself. Similarly for the path
-to apu-1-config.
-
-OPENSSL should specify the root of the install (eg. /opt/local). The
-includes will be found OPENSSL/include and libraries at OPENSSL/lib.
-
-If you wish to use VPATH-style builds (where objects are created in a
-distinct directory from the source), you can use:
-
-$ scons -Y /path/to/serf/source
-
-If you plan to install the library on a system that uses different
-paths for architecture dependent files, specify LIBDIR. LIBDIR defaults
-to /usr/local/lib otherwise. Example for a 64 bit GNU/Linux system:
-
-$ scons PREFIX=/usr/ LIBDIR=/usr/lib64
-
-At any point, the current settings can be examined:
-
-$ scons --help
-
-
-1.3 Running the test suite
-
-$ scons check
-
-
-1.4 Installing serf
-
-$ scons install
-
-Note that the PREFIX variable should have been specified in a previous
-invocation of scons (and saved into .saved_config), or it can be
-specified on the install command line:
-
-$ scons PREFIX=/some/path install
-
-Distribution package maintainers regulary install to a buildroot, and
-would normally use something like below in their build systems, with
-placeholders for the specific paths:
-
-$ scons PREFIX=/usr/ LIBDIR=/usr/lib64
-$ scons install --install-sandbox=/path/to/buildroot
-
-
-1.4 Cleaning up the build
-
-$ scons -c

Copied: vendor/serf/1.3.9/README (from rev 9259, vendor/serf/dist/README)
===================================================================
--- vendor/serf/1.3.9/README	                        (rev 0)
+++ vendor/serf/1.3.9/README	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,92 @@
+Welcome to Apache Serf, a high-performance asynchronous HTTP client library.
+
+The Apache Serf library is a C-based HTTP client library built upon the Apache
+Portable Runtime (APR) library. It multiplexes connections, running the
+read/write communication asynchronously. Memory copies and transformations are
+kept to a minimum to provide high performance operation.
+
+  * Site: http://serf.apache.org//
+  * Code: http://svn.apache.org/repos/asf/serf/
+  * Issues: https://issues.apache.org/jira/browse/SERF
+  * Mail: dev at serf.apache.org
+  * People: Justin Erenkrantz, Greg Stein 
+
+----
+
+1. INSTALL
+
+1.1. SCons build system
+
+Apache Serf uses SCons 2.3 for its build system. If it is not installed
+on your system, then you can install it onto your system. If you do not
+have permissions, then you can download and install the "local"
+version into your home directory. When installed privately, simply
+create a symlink for 'scons' in your PATH to /path/to/scons/scons.py.
+
+Fetch the scons-local package:
+  http://prdownloads.sourceforge.net/scons/scons-local-2.3.0.tar.gz
+
+
+1.2 Building Apache Serf
+
+To build serf:
+
+$ scons APR=/path/to/apr APU=/path/to/apu OPENSSL=/openssl/base PREFIX=/path/to/prefix
+
+The switches are recorded into .saved_config, so they only need to be
+specified the first time scons is run.
+
+PREFIX should specify where serf should be installed.  PREFIX defaults to
+/usr/local.
+
+The default for the other three switches (APR, APU, OPENSSL) is /usr.
+
+The build system looks for apr-1-config at $APR/bin/apr-1-config, or
+the path should indicate apr-1-config itself. Similarly for the path
+to apu-1-config.
+
+OPENSSL should specify the root of the install (eg. /opt/local). The
+includes will be found OPENSSL/include and libraries at OPENSSL/lib.
+
+If you wish to use VPATH-style builds (where objects are created in a
+distinct directory from the source), you can use:
+
+$ scons -Y /path/to/serf/source
+
+If you plan to install the library on a system that uses different
+paths for architecture dependent files, specify LIBDIR. LIBDIR defaults
+to /usr/local/lib otherwise. Example for a 64 bit GNU/Linux system:
+
+$ scons PREFIX=/usr/ LIBDIR=/usr/lib64
+
+At any point, the current settings can be examined:
+
+$ scons --help
+
+
+1.3 Running the test suite
+
+$ scons check
+
+
+1.4 Installing Apache Serf
+
+$ scons install
+
+Note that the PREFIX variable should have been specified in a previous
+invocation of scons (and saved into .saved_config), or it can be
+specified on the install command line:
+
+$ scons PREFIX=/some/path install
+
+Distribution package maintainers regulary install to a buildroot, and
+would normally use something like below in their build systems, with
+placeholders for the specific paths:
+
+$ scons PREFIX=/usr/ LIBDIR=/usr/lib64
+$ scons install --install-sandbox=/path/to/buildroot
+
+
+1.4 Cleaning up the build
+
+$ scons -c

Deleted: vendor/serf/1.3.9/SConstruct
===================================================================
--- vendor/serf/dist/SConstruct	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/SConstruct	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,471 +0,0 @@
-# -*- python -*-
-#
-# Copyright 2011-2012 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.
-#
-
-import sys
-import os
-import re
-
-EnsureSConsVersion(2,3,0)
-
-HEADER_FILES = ['serf.h',
-                'serf_bucket_types.h',
-                'serf_bucket_util.h',
-                ]
-
-# where we save the configuration variables
-SAVED_CONFIG = '.saved_config'
-
-# Variable class that does no validation on the input
-def _converter(val):
-    """
-    """
-    if val == 'none':
-      val = []
-    else:
-      val = val.split(' ')
-    return val
-
-def RawListVariable(key, help, default):
-    """
-    The input parameters describe a 'raw string list' option. This class
-    accepts a space-separated string and converts it to a list.
-    """
-    return (key, '%s' % (help), default, None, lambda val: _converter(val))
-
-# Custom path validator, creates directory when a specified option is set.
-# To be used to ensure a PREFIX directory is only created when installing.
-def createPathIsDirCreateWithTarget(target):
-  def my_validator(key, val, env):
-    build_targets = (map(str, BUILD_TARGETS))
-    if target in build_targets:
-      return PathVariable.PathIsDirCreate(key, val, env)
-    else:
-      return PathVariable.PathAccept(key, val, env)
-  return my_validator
-
-# default directories
-if sys.platform == 'win32':
-  default_incdir='..'
-  default_libdir='..'
-  default_prefix='Debug'
-else:
-  default_incdir='/usr'
-  default_libdir='$PREFIX/lib'
-  default_prefix='/usr/local'
-
-opts = Variables(files=[SAVED_CONFIG])
-opts.AddVariables(
-  PathVariable('PREFIX',
-               'Directory to install under',
-               default_prefix,
-               createPathIsDirCreateWithTarget('install')),
-  PathVariable('LIBDIR',
-               'Directory to install architecture dependent libraries under',
-               default_libdir,
-               createPathIsDirCreateWithTarget('install')),
-  PathVariable('APR',
-               "Path to apr-1-config, or to APR's install area",
-               default_incdir,
-               PathVariable.PathAccept),
-  PathVariable('APU',
-               "Path to apu-1-config, or to APR's install area",
-               default_incdir,
-               PathVariable.PathAccept),
-  PathVariable('OPENSSL',
-               "Path to OpenSSL's install area",
-               default_incdir,
-               PathVariable.PathIsDir),
-  PathVariable('ZLIB',
-               "Path to zlib's install area",
-               default_incdir,
-               PathVariable.PathIsDir),
-  PathVariable('GSSAPI',
-               "Path to GSSAPI's install area",
-               None,
-               None),
-  BoolVariable('DEBUG',
-               "Enable debugging info and strict compile warnings",
-               False),
-  BoolVariable('APR_STATIC',
-               "Enable using a static compiled APR",
-               False),
-  RawListVariable('CC', "Command name or path of the C compiler", None),
-  RawListVariable('CFLAGS', "Extra flags for the C compiler (space-separated)",
-                  None),
-  RawListVariable('LIBS', "Extra libraries passed to the linker, "
-                  "e.g. \"-l<library1> -l<library2>\" (space separated)", None),
-  RawListVariable('LINKFLAGS', "Extra flags for the linker (space-separated)",
-                  None),
-  RawListVariable('CPPFLAGS', "Extra flags for the C preprocessor "
-                  "(space separated)", None), 
-  )
-
-if sys.platform == 'win32':
-  opts.AddVariables(
-    # By default SCons builds for the host platform on Windows, when using
-    # a supported compiler (E.g. VS2010/VS2012). Allow overriding
-
-    # Note that Scons 1.3 only supports this on Windows and only when
-    # constructing Environment(). Later changes to TARGET_ARCH are ignored
-    EnumVariable('TARGET_ARCH',
-                 "Platform to build for (x86|x64|win32|x86_64)",
-                 'x86',
-                 allowed_values=('x86', 'x86_64', 'ia64'),
-                 map={'X86'  : 'x86',
-                      'win32': 'x86',
-                      'Win32': 'x86',
-                      'x64'  : 'x86_64',
-                      'X64'  : 'x86_64'
-                     }),
-
-    EnumVariable('MSVC_VERSION',
-                 "Visual C++ to use for building (E.g. 11.0, 9.0)",
-                 None,
-                 allowed_values=('12.0', '11.0', '10.0', '9.0', '8.0', '6.0')
-                ),
-
-    # We always documented that we handle an install layout, but in fact we
-    # hardcoded source layouts. Allow disabling this behavior.
-    # ### Fix default?
-    BoolVariable('SOURCE_LAYOUT',
-                 "Assume a source layout instead of install layout",
-                 True),
-    )
-
-env = Environment(variables=opts,
-                  tools=('default', 'textfile',),
-                  CPPPATH=['.', ],
-                  )
-
-env.Append(BUILDERS = {
-    'GenDef' : 
-      Builder(action = sys.executable + ' build/gen_def.py $SOURCES > $TARGET',
-              suffix='.def', src_suffix='.h')
-  })
-
-match = re.search('SERF_MAJOR_VERSION ([0-9]+).*'
-                  'SERF_MINOR_VERSION ([0-9]+).*'
-                  'SERF_PATCH_VERSION ([0-9]+)',
-                  env.File('serf.h').get_contents(),
-                  re.DOTALL)
-MAJOR, MINOR, PATCH = [int(x) for x in match.groups()]
-env.Append(MAJOR=str(MAJOR))
-env.Append(MINOR=str(MINOR))
-env.Append(PATCH=str(PATCH))
-
-# Calling external programs is okay if we're not cleaning or printing help.
-# (cleaning: no sense in fetching information; help: we may not know where
-# they are)
-CALLOUT_OKAY = not (env.GetOption('clean') or env.GetOption('help'))
-
-
-# HANDLING OF OPTION VARIABLES
-
-unknown = opts.UnknownVariables()
-if unknown:
-  print 'Unknown variables:', ', '.join(unknown.keys())
-  Exit(1)
-
-apr = str(env['APR'])
-apu = str(env['APU'])
-zlib = str(env['ZLIB'])
-gssapi = env.get('GSSAPI', None)
-
-if gssapi and os.path.isdir(gssapi):
-  krb5_config = os.path.join(gssapi, 'bin', 'krb5-config')
-  if os.path.isfile(krb5_config):
-    gssapi = krb5_config
-    env['GSSAPI'] = krb5_config
-
-debug = env.get('DEBUG', None)
-aprstatic = env.get('APR_STATIC', None)
-
-Help(opts.GenerateHelpText(env))
-opts.Save(SAVED_CONFIG, env)
-
-
-# PLATFORM-SPECIFIC BUILD TWEAKS
-
-thisdir = os.getcwd()
-libdir = '$LIBDIR'
-incdir = '$PREFIX/include/serf-$MAJOR'
-
-# This version string is used in the dynamic library name, and for Mac OS X also
-# for the current_version and compatibility_version options in the .dylib
-#
-# Unfortunately we can't set the .dylib compatibility_version option separately
-# from current_version, so don't use the PATCH level to avoid that build and
-# runtime patch levels have to be identical.
-env['SHLIBVERSION'] = '%d.%d.%d' % (MAJOR, MINOR, 0)
-
-LIBNAME = 'libserf-%d' % (MAJOR,)
-if sys.platform != 'win32':
-  LIBNAMESTATIC = LIBNAME
-else:
-  LIBNAMESTATIC = 'serf-${MAJOR}'
-
-env.Append(RPATH=libdir,
-           PDB='${TARGET.filebase}.pdb')
-
-if sys.platform == 'darwin':
-#  linkflags.append('-Wl,-install_name, at executable_path/%s.dylib' % (LIBNAME,))
-  env.Append(LINKFLAGS='-Wl,-install_name,%s/%s.dylib' % (thisdir, LIBNAME,))
-
-if sys.platform != 'win32':
-  ### gcc only. figure out appropriate test / better way to check these
-  ### flags, and check for gcc.
-  env.Append(CFLAGS='-std=c89')
-
-  ### These warnings are not available on Solaris
-  if sys.platform != 'sunos5': 
-    env.Append(CCFLAGS=['-Wdeclaration-after-statement',
-                        '-Wmissing-prototypes',
-                        '-Wall'])
-
-  if debug:
-    env.Append(CCFLAGS='-g')
-    env.Append(CPPDEFINES=['DEBUG', '_DEBUG'])
-  else:
-    env.Append(CCFLAGS='-O2')
-    env.Append(CPPDEFINES='NDEBUG')
-
-  ### works for Mac OS. probably needs to change
-  env.Append(LIBS=['ssl', 'crypto', 'z', ])
-
-  if sys.platform == 'sunos5':
-    env.Append(LIBS='m')
-else:
-  # Warning level 4, no unused argument warnings
-  env.Append(CCFLAGS=['/W4', '/wd4100'])
-
-  # Choose runtime and optimization
-  if debug:
-    # Disable optimizations for debugging, use debug DLL runtime
-    env.Append(CCFLAGS=['/Od', '/MDd'])
-    env.Append(CPPDEFINES=['DEBUG', '_DEBUG'])
-  else:
-    # Optimize for speed, use DLL runtime
-    env.Append(CCFLAGS=['/O2', '/MD'])
-    env.Append(CPPDEFINES='NDEBUG')
-    env.Append(LINKFLAGS='/RELEASE')
-
-# PLAN THE BUILD
-SHARED_SOURCES = []
-if sys.platform == 'win32':
-  env.GenDef(['serf.h','serf_bucket_types.h', 'serf_bucket_util.h'])
-  SHARED_SOURCES.append(['serf.def'])
-
-SOURCES = Glob('*.c') + Glob('buckets/*.c') + Glob('auth/*.c')
-
-lib_static = env.StaticLibrary(LIBNAMESTATIC, SOURCES)
-lib_shared = env.SharedLibrary(LIBNAME, SOURCES + SHARED_SOURCES)
-
-if aprstatic:
-  env.Append(CPPDEFINES=['APR_DECLARE_STATIC', 'APU_DECLARE_STATIC'])
-
-if sys.platform == 'win32':
-  env.Append(LIBS=['user32.lib', 'advapi32.lib', 'gdi32.lib', 'ws2_32.lib',
-                   'crypt32.lib', 'mswsock.lib', 'rpcrt4.lib', 'secur32.lib'])
-
-  # Get apr/apu information into our build
-  env.Append(CPPDEFINES=['WIN32','WIN32_LEAN_AND_MEAN','NOUSER',
-                         'NOGDI', 'NONLS','NOCRYPT'])
-
-  if env.get('TARGET_ARCH', None) == 'x86_64':
-    env.Append(CPPDEFINES=['WIN64'])
-
-  if aprstatic:
-    apr_libs='apr-1.lib'
-    apu_libs='aprutil-1.lib'
-  else:
-    apr_libs='libapr-1.lib'
-    apu_libs='libaprutil-1.lib'
-
-  env.Append(LIBS=[apr_libs, apu_libs])
-  if not env.get('SOURCE_LAYOUT', None):
-    env.Append(LIBPATH=['$APR/lib', '$APU/lib'],
-               CPPPATH=['$APR/include/apr-1', '$APU/include/apr-1'])
-  elif aprstatic:
-    env.Append(LIBPATH=['$APR/LibR','$APU/LibR'],
-               CPPPATH=['$APR/include', '$APU/include'])
-  else:
-    env.Append(LIBPATH=['$APR/Release','$APU/Release'],
-               CPPPATH=['$APR/include', '$APU/include'])
-
-  # zlib
-  env.Append(LIBS='zlib.lib')
-  if not env.get('SOURCE_LAYOUT', None):
-    env.Append(CPPPATH='$ZLIB/include',
-               LIBPATH='$ZLIB/lib')
-  else:
-    env.Append(CPPPATH='$ZLIB',
-               LIBPATH='$ZLIB')
-
-  # openssl
-  env.Append(LIBS=['libeay32.lib', 'ssleay32.lib'])
-  if not env.get('SOURCE_LAYOUT', None):
-    env.Append(CPPPATH='$OPENSSL/include/openssl',
-               LIBPATH='$OPENSSL/lib')
-  elif 0: # opensslstatic:
-    env.Append(CPPPATH='$OPENSSL/inc32',
-               LIBPATH='$OPENSSL/out32')
-  else:
-    env.Append(CPPPATH='$OPENSSL/inc32',
-               LIBPATH='$OPENSSL/out32dll')
-else:
-  if os.path.isdir(apr):
-    apr = os.path.join(apr, 'bin', 'apr-1-config')
-    env['APR'] = apr
-  if os.path.isdir(apu):
-    apu = os.path.join(apu, 'bin', 'apu-1-config')
-    env['APU'] = apu
-
-  ### we should use --cc, but that is giving some scons error about an implict
-  ### dependency upon gcc. probably ParseConfig doesn't know what to do with
-  ### the apr-1-config output
-  if CALLOUT_OKAY:
-    env.ParseConfig('$APR --cflags --cppflags --ldflags --includes'
-                    ' --link-ld --libs')
-    env.ParseConfig('$APU --ldflags --includes --link-ld --libs')
-
-  ### there is probably a better way to run/capture output.
-  ### env.ParseConfig() may be handy for getting this stuff into the build
-  if CALLOUT_OKAY:
-    apr_libs = os.popen(env.subst('$APR --link-libtool --libs')).read().strip()
-    apu_libs = os.popen(env.subst('$APU --link-libtool --libs')).read().strip()
-  else:
-    apr_libs = ''
-    apu_libs = ''
-
-  env.Append(CPPPATH='$OPENSSL/include')
-  env.Append(LIBPATH='$OPENSSL/lib')
-
-
-# If build with gssapi, get its information and define SERF_HAVE_GSSAPI
-if gssapi and CALLOUT_OKAY:
-    env.ParseConfig('$GSSAPI --cflags gssapi')
-    def parse_libs(env, cmd, unique=1):
-        env['GSSAPI_LIBS'] = cmd.strip()
-        return env.MergeFlags(cmd, unique)
-    env.ParseConfig('$GSSAPI --libs gssapi', parse_libs)
-    env.Append(CPPDEFINES='SERF_HAVE_GSSAPI')
-if sys.platform == 'win32':
-  env.Append(CPPDEFINES=['SERF_HAVE_SSPI'])
-
-# On some systems, the -R values that APR describes never make it into actual
-# RPATH flags. We'll manually map all directories in LIBPATH into new
-# flags to set RPATH values.
-for d in env['LIBPATH']:
-  env.Append(RPATH=':'+d)
-
-# Set up the construction of serf-*.pc
-pkgconfig = env.Textfile('serf-%d.pc' % (MAJOR,),
-                         env.File('build/serf.pc.in'),
-                         SUBST_DICT = {
-                           '@MAJOR@': str(MAJOR),
-                           '@PREFIX@': '$PREFIX',
-                           '@LIBDIR@': '$LIBDIR',
-                           '@INCLUDE_SUBDIR@': 'serf-%d' % (MAJOR,),
-                           '@VERSION@': '%d.%d.%d' % (MAJOR, MINOR, PATCH),
-                           '@LIBS@': '%s %s %s -lz' % (apu_libs, apr_libs,
-                                                       env.get('GSSAPI_LIBS', '')),
-                           })
-
-env.Default(lib_static, lib_shared, pkgconfig)
-
-if CALLOUT_OKAY:
-  conf = Configure(env)
-
-  ### some configuration stuffs
-
-  env = conf.Finish()
-
-
-# INSTALLATION STUFF
-
-install_static = env.Install(libdir, lib_static)
-install_shared = env.InstallVersionedLib(libdir, lib_shared)
-
-if sys.platform == 'darwin':
-  # Change the shared library install name (id) to its final name and location.
-  # Notes:
-  # If --install-sandbox=<path> is specified, install_shared_path will point
-  # to a path in the sandbox. We can't use that path because the sandbox is
-  # only a temporary location. The id should be the final target path.
-  # Also, we shouldn't use the complete version number for id, as that'll
-  # make applications depend on the exact major.minor.patch version of serf.
-
-  install_shared_path = install_shared[0].abspath
-  target_install_shared_path = os.path.join(libdir, '%s.dylib' % LIBNAME)
-  env.AddPostAction(install_shared, ('install_name_tool -id %s %s'
-                                     % (target_install_shared_path,
-                                        install_shared_path)))
-
-env.Alias('install-lib', [install_static, install_shared,
-                          ])
-env.Alias('install-inc', env.Install(incdir, HEADER_FILES))
-env.Alias('install-pc', env.Install(os.path.join(libdir, 'pkgconfig'),
-                                    pkgconfig))
-env.Alias('install', ['install-lib', 'install-inc', 'install-pc', ])
-
-
-# TESTS
-### make move to a separate scons file in the test/ subdir?
-
-tenv = env.Clone()
-
-TEST_PROGRAMS = [ 'serf_get', 'serf_response', 'serf_request', 'serf_spider',
-                  'test_all', 'serf_bwtp' ]
-if sys.platform == 'win32':
-  TEST_EXES = [ os.path.join('test', '%s.exe' % (prog)) for prog in TEST_PROGRAMS ]
-else:
-  TEST_EXES = [ os.path.join('test', '%s' % (prog)) for prog in TEST_PROGRAMS ]
-
-env.AlwaysBuild(env.Alias('check', TEST_EXES, sys.executable + ' build/check.py',
-                          ENV={'PATH' : os.environ['PATH']}))
-
-# Find the (dynamic) library in this directory
-tenv.Replace(RPATH=thisdir)
-tenv.Prepend(LIBS=[LIBNAMESTATIC, ],
-             LIBPATH=[thisdir, ])
-
-testall_files = [
-        'test/test_all.c',
-        'test/CuTest.c',
-        'test/test_util.c',
-        'test/test_context.c',
-        'test/test_buckets.c',
-        'test/test_auth.c',
-        'test/mock_buckets.c',
-        'test/test_ssl.c',
-        'test/server/test_server.c',
-        'test/server/test_sslserver.c',
-        ]
-
-for proggie in TEST_EXES:
-  if 'test_all' in proggie:
-    tenv.Program(proggie, testall_files )
-  else:
-    tenv.Program(target = proggie, source = [proggie.replace('.exe','') + '.c'])
-
-
-# HANDLE CLEANING
-
-if env.GetOption('clean'):
-  # When we're cleaning, we want the dependency tree to include "everything"
-  # that could be built. Thus, include all of the tests.
-  env.Default('check')

Copied: vendor/serf/1.3.9/SConstruct (from rev 9259, vendor/serf/dist/SConstruct)
===================================================================
--- vendor/serf/1.3.9/SConstruct	                        (rev 0)
+++ vendor/serf/1.3.9/SConstruct	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,505 @@
+# -*- python -*-
+#
+# ====================================================================
+#    Licensed to the Apache Software Foundation (ASF) under one
+#    or more contributor license agreements.  See the NOTICE file
+#    distributed with this work for additional information
+#    regarding copyright ownership.  The ASF licenses this file
+#    to you 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.
+# ====================================================================
+#
+
+import sys
+import os
+import re
+
+EnsureSConsVersion(2,3,0)
+
+HEADER_FILES = ['serf.h',
+                'serf_bucket_types.h',
+                'serf_bucket_util.h',
+                ]
+
+# where we save the configuration variables
+SAVED_CONFIG = '.saved_config'
+
+# Variable class that does no validation on the input
+def _converter(val):
+    """
+    """
+    if val == 'none':
+      val = []
+    else:
+      val = val.split(' ')
+    return val
+
+def RawListVariable(key, help, default):
+    """
+    The input parameters describe a 'raw string list' option. This class
+    accepts a space-separated string and converts it to a list.
+    """
+    return (key, '%s' % (help), default, None, lambda val: _converter(val))
+
+# Custom path validator, creates directory when a specified option is set.
+# To be used to ensure a PREFIX directory is only created when installing.
+def createPathIsDirCreateWithTarget(target):
+  def my_validator(key, val, env):
+    build_targets = (map(str, BUILD_TARGETS))
+    if target in build_targets:
+      return PathVariable.PathIsDirCreate(key, val, env)
+    else:
+      return PathVariable.PathAccept(key, val, env)
+  return my_validator
+
+# default directories
+if sys.platform == 'win32':
+  default_incdir='..'
+  default_libdir='..'
+  default_prefix='Debug'
+else:
+  default_incdir='/usr'
+  default_libdir='$PREFIX/lib'
+  default_prefix='/usr/local'
+
+opts = Variables(files=[SAVED_CONFIG])
+opts.AddVariables(
+  PathVariable('PREFIX',
+               'Directory to install under',
+               default_prefix,
+               createPathIsDirCreateWithTarget('install')),
+  PathVariable('LIBDIR',
+               'Directory to install architecture dependent libraries under',
+               default_libdir,
+               createPathIsDirCreateWithTarget('install')),
+  PathVariable('APR',
+               "Path to apr-1-config, or to APR's install area",
+               default_incdir,
+               PathVariable.PathAccept),
+  PathVariable('APU',
+               "Path to apu-1-config, or to APR's install area",
+               default_incdir,
+               PathVariable.PathAccept),
+  PathVariable('OPENSSL',
+               "Path to OpenSSL's install area",
+               default_incdir,
+               PathVariable.PathIsDir),
+  PathVariable('ZLIB',
+               "Path to zlib's install area",
+               default_incdir,
+               PathVariable.PathIsDir),
+  PathVariable('GSSAPI',
+               "Path to GSSAPI's install area",
+               None,
+               None),
+  BoolVariable('DEBUG',
+               "Enable debugging info and strict compile warnings",
+               False),
+  BoolVariable('APR_STATIC',
+               "Enable using a static compiled APR",
+               False),
+  RawListVariable('CC', "Command name or path of the C compiler", None),
+  RawListVariable('CFLAGS', "Extra flags for the C compiler (space-separated)",
+                  None),
+  RawListVariable('LIBS', "Extra libraries passed to the linker, "
+                  "e.g. \"-l<library1> -l<library2>\" (space separated)", None),
+  RawListVariable('LINKFLAGS', "Extra flags for the linker (space-separated)",
+                  None),
+  RawListVariable('CPPFLAGS', "Extra flags for the C preprocessor "
+                  "(space separated)", None), 
+  )
+
+if sys.platform == 'win32':
+  opts.AddVariables(
+    # By default SCons builds for the host platform on Windows, when using
+    # a supported compiler (E.g. VS2010/VS2012). Allow overriding
+
+    # Note that Scons 1.3 only supports this on Windows and only when
+    # constructing Environment(). Later changes to TARGET_ARCH are ignored
+    EnumVariable('TARGET_ARCH',
+                 "Platform to build for (x86|x64|win32|x86_64)",
+                 'x86',
+                 allowed_values=('x86', 'x86_64', 'ia64'),
+                 map={'X86'  : 'x86',
+                      'win32': 'x86',
+                      'Win32': 'x86',
+                      'x64'  : 'x86_64',
+                      'X64'  : 'x86_64'
+                     }),
+
+    EnumVariable('MSVC_VERSION',
+                 "Visual C++ to use for building (E.g. 11.0, 9.0)",
+                 None,
+                 allowed_values=('14.0', '12.0',
+                                 '11.0', '10.0', '9.0', '8.0', '6.0')
+                ),
+
+    # We always documented that we handle an install layout, but in fact we
+    # hardcoded source layouts. Allow disabling this behavior.
+    # ### Fix default?
+    BoolVariable('SOURCE_LAYOUT',
+                 "Assume a source layout instead of install layout",
+                 True),
+    )
+
+env = Environment(variables=opts,
+                  tools=('default', 'textfile',),
+                  CPPPATH=['.', ],
+                  )
+
+env.Append(BUILDERS = {
+    'GenDef' : 
+      Builder(action = sys.executable + ' build/gen_def.py $SOURCES > $TARGET',
+              suffix='.def', src_suffix='.h')
+  })
+
+match = re.search('SERF_MAJOR_VERSION ([0-9]+).*'
+                  'SERF_MINOR_VERSION ([0-9]+).*'
+                  'SERF_PATCH_VERSION ([0-9]+)',
+                  env.File('serf.h').get_contents(),
+                  re.DOTALL)
+MAJOR, MINOR, PATCH = [int(x) for x in match.groups()]
+env.Append(MAJOR=str(MAJOR))
+env.Append(MINOR=str(MINOR))
+env.Append(PATCH=str(PATCH))
+
+# Calling external programs is okay if we're not cleaning or printing help.
+# (cleaning: no sense in fetching information; help: we may not know where
+# they are)
+CALLOUT_OKAY = not (env.GetOption('clean') or env.GetOption('help'))
+
+
+# HANDLING OF OPTION VARIABLES
+
+unknown = opts.UnknownVariables()
+if unknown:
+  print 'Warning: Used unknown variables:', ', '.join(unknown.keys())
+
+apr = str(env['APR'])
+apu = str(env['APU'])
+zlib = str(env['ZLIB'])
+gssapi = env.get('GSSAPI', None)
+
+if gssapi and os.path.isdir(gssapi):
+  krb5_config = os.path.join(gssapi, 'bin', 'krb5-config')
+  if os.path.isfile(krb5_config):
+    gssapi = krb5_config
+    env['GSSAPI'] = krb5_config
+
+debug = env.get('DEBUG', None)
+aprstatic = env.get('APR_STATIC', None)
+
+Help(opts.GenerateHelpText(env))
+opts.Save(SAVED_CONFIG, env)
+
+
+# PLATFORM-SPECIFIC BUILD TWEAKS
+
+thisdir = os.getcwd()
+libdir = '$LIBDIR'
+incdir = '$PREFIX/include/serf-$MAJOR'
+
+# This version string is used in the dynamic library name, and for Mac OS X also
+# for the current_version and compatibility_version options in the .dylib
+#
+# Unfortunately we can't set the .dylib compatibility_version option separately
+# from current_version, so don't use the PATCH level to avoid that build and
+# runtime patch levels have to be identical.
+if sys.platform != 'sunos5':
+  env['SHLIBVERSION'] = '%d.%d.%d' % (MAJOR, MINOR, 0)
+
+LIBNAME = 'libserf-%d' % (MAJOR,)
+if sys.platform != 'win32':
+  LIBNAMESTATIC = LIBNAME
+else:
+  LIBNAMESTATIC = 'serf-${MAJOR}'
+
+env.Append(RPATH=libdir,
+           PDB='${TARGET.filebase}.pdb')
+
+if sys.platform == 'darwin':
+#  linkflags.append('-Wl,-install_name, at executable_path/%s.dylib' % (LIBNAME,))
+  env.Append(LINKFLAGS=['-Wl,-install_name,%s/%s.dylib' % (thisdir, LIBNAME,)])
+
+if sys.platform != 'win32':
+  def CheckGnuCC(context):
+    src = '''
+    #ifndef __GNUC__
+    oh noes!
+    #endif
+    '''
+    context.Message('Checking for GNU-compatible C compiler...')
+    result = context.TryCompile(src, '.c')
+    context.Result(result)
+    return result
+
+  conf = Configure(env, custom_tests = dict(CheckGnuCC=CheckGnuCC))
+  have_gcc = conf.CheckGnuCC()
+  env = conf.Finish()
+
+  if have_gcc:
+    env.Append(CFLAGS=['-std=c89'])
+    env.Append(CCFLAGS=['-Wdeclaration-after-statement',
+                        '-Wmissing-prototypes',
+                        '-Wall'])
+
+  if debug:
+    env.Append(CCFLAGS=['-g'])
+    env.Append(CPPDEFINES=['DEBUG', '_DEBUG'])
+  else:
+    env.Append(CCFLAGS=['-O2'])
+    env.Append(CPPDEFINES=['NDEBUG'])
+
+  ### works for Mac OS. probably needs to change
+  env.Append(LIBS=['ssl', 'crypto', 'z', ])
+
+  if sys.platform == 'sunos5':
+    env.Append(LIBS=['m'])
+    env.Append(PLATFORM='posix')
+else:
+  # Warning level 4, no unused argument warnings
+  env.Append(CCFLAGS=['/W4', '/wd4100'])
+
+  # Choose runtime and optimization
+  if debug:
+    # Disable optimizations for debugging, use debug DLL runtime
+    env.Append(CCFLAGS=['/Od', '/MDd'])
+    env.Append(CPPDEFINES=['DEBUG', '_DEBUG'])
+  else:
+    # Optimize for speed, use DLL runtime
+    env.Append(CCFLAGS=['/O2', '/MD'])
+    env.Append(CPPDEFINES=['NDEBUG'])
+    env.Append(LINKFLAGS=['/RELEASE'])
+
+# PLAN THE BUILD
+SHARED_SOURCES = []
+if sys.platform == 'win32':
+  env.GenDef(['serf.h','serf_bucket_types.h', 'serf_bucket_util.h'])
+  SHARED_SOURCES.append(['serf.def'])
+
+SOURCES = Glob('*.c') + Glob('buckets/*.c') + Glob('auth/*.c')
+
+lib_static = env.StaticLibrary(LIBNAMESTATIC, SOURCES)
+lib_shared = env.SharedLibrary(LIBNAME, SOURCES + SHARED_SOURCES)
+
+if aprstatic:
+  env.Append(CPPDEFINES=['APR_DECLARE_STATIC', 'APU_DECLARE_STATIC'])
+
+if sys.platform == 'win32':
+  env.Append(LIBS=['user32.lib', 'advapi32.lib', 'gdi32.lib', 'ws2_32.lib',
+                   'crypt32.lib', 'mswsock.lib', 'rpcrt4.lib', 'secur32.lib'])
+
+  # Get apr/apu information into our build
+  env.Append(CPPDEFINES=['WIN32','WIN32_LEAN_AND_MEAN','NOUSER',
+                         'NOGDI', 'NONLS','NOCRYPT'])
+
+  if env.get('TARGET_ARCH', None) == 'x86_64':
+    env.Append(CPPDEFINES=['WIN64'])
+
+  if aprstatic:
+    apr_libs='apr-1.lib'
+    apu_libs='aprutil-1.lib'
+    env.Append(LIBS=['shell32.lib', 'xml.lib'])
+  else:
+    apr_libs='libapr-1.lib'
+    apu_libs='libaprutil-1.lib'
+
+  env.Append(LIBS=[apr_libs, apu_libs])
+  if not env.get('SOURCE_LAYOUT', None):
+    env.Append(LIBPATH=['$APR/lib', '$APU/lib'],
+               CPPPATH=['$APR/include/apr-1', '$APU/include/apr-1'])
+  elif aprstatic:
+    env.Append(LIBPATH=['$APR/LibR','$APU/LibR'],
+               CPPPATH=['$APR/include', '$APU/include'])
+  else:
+    env.Append(LIBPATH=['$APR/Release','$APU/Release'],
+               CPPPATH=['$APR/include', '$APU/include'])
+
+  # zlib
+  env.Append(LIBS=['zlib.lib'])
+  if not env.get('SOURCE_LAYOUT', None):
+    env.Append(CPPPATH=['$ZLIB/include'],
+               LIBPATH=['$ZLIB/lib'])
+  else:
+    env.Append(CPPPATH=['$ZLIB'],
+               LIBPATH=['$ZLIB'])
+
+  # openssl
+  env.Append(LIBS=['libeay32.lib', 'ssleay32.lib'])
+  if not env.get('SOURCE_LAYOUT', None):
+    env.Append(CPPPATH=['$OPENSSL/include/openssl'],
+               LIBPATH=['$OPENSSL/lib'])
+  elif 0: # opensslstatic:
+    env.Append(CPPPATH=['$OPENSSL/inc32'],
+               LIBPATH=['$OPENSSL/out32'])
+  else:
+    env.Append(CPPPATH=['$OPENSSL/inc32'],
+               LIBPATH=['$OPENSSL/out32dll'])
+else:
+  if os.path.isdir(apr):
+    apr = os.path.join(apr, 'bin', 'apr-1-config')
+    env['APR'] = apr
+  if os.path.isdir(apu):
+    apu = os.path.join(apu, 'bin', 'apu-1-config')
+    env['APU'] = apu
+
+  ### we should use --cc, but that is giving some scons error about an implict
+  ### dependency upon gcc. probably ParseConfig doesn't know what to do with
+  ### the apr-1-config output
+  if CALLOUT_OKAY:
+    env.ParseConfig('$APR --cflags --cppflags --ldflags --includes'
+                    ' --link-ld --libs')
+    env.ParseConfig('$APU --ldflags --includes --link-ld --libs')
+
+  ### there is probably a better way to run/capture output.
+  ### env.ParseConfig() may be handy for getting this stuff into the build
+  if CALLOUT_OKAY:
+    apr_libs = os.popen(env.subst('$APR --link-libtool --libs')).read().strip()
+    apu_libs = os.popen(env.subst('$APU --link-libtool --libs')).read().strip()
+  else:
+    apr_libs = ''
+    apu_libs = ''
+
+  env.Append(CPPPATH=['$OPENSSL/include'])
+  env.Append(LIBPATH=['$OPENSSL/lib'])
+
+
+# If build with gssapi, get its information and define SERF_HAVE_GSSAPI
+if gssapi and CALLOUT_OKAY:
+    env.ParseConfig('$GSSAPI --cflags gssapi')
+    def parse_libs(env, cmd, unique=1):
+        env['GSSAPI_LIBS'] = cmd.strip()
+        return env.MergeFlags(cmd, unique)
+    env.ParseConfig('$GSSAPI --libs gssapi', parse_libs)
+    env.Append(CPPDEFINES=['SERF_HAVE_GSSAPI'])
+if sys.platform == 'win32':
+  env.Append(CPPDEFINES=['SERF_HAVE_SSPI'])
+
+# On some systems, the -R values that APR describes never make it into actual
+# RPATH flags. We'll manually map all directories in LIBPATH into new
+# flags to set RPATH values.
+for d in env['LIBPATH']:
+  env.Append(RPATH=':'+d)
+
+# Set up the construction of serf-*.pc
+pkgconfig = env.Textfile('serf-%d.pc' % (MAJOR,),
+                         env.File('build/serf.pc.in'),
+                         SUBST_DICT = {
+                           '@MAJOR@': str(MAJOR),
+                           '@PREFIX@': '$PREFIX',
+                           '@LIBDIR@': '$LIBDIR',
+                           '@INCLUDE_SUBDIR@': 'serf-%d' % (MAJOR,),
+                           '@VERSION@': '%d.%d.%d' % (MAJOR, MINOR, PATCH),
+                           '@LIBS@': '%s %s %s -lz' % (apu_libs, apr_libs,
+                                                       env.get('GSSAPI_LIBS', '')),
+                           })
+
+env.Default(lib_static, lib_shared, pkgconfig)
+
+if CALLOUT_OKAY:
+  conf = Configure(env)
+
+  ### some configuration stuffs
+
+  env = conf.Finish()
+
+
+# INSTALLATION STUFF
+
+install_static = env.Install(libdir, lib_static)
+install_shared = env.InstallVersionedLib(libdir, lib_shared)
+
+if sys.platform == 'darwin':
+  # Change the shared library install name (id) to its final name and location.
+  # Notes:
+  # If --install-sandbox=<path> is specified, install_shared_path will point
+  # to a path in the sandbox. We can't use that path because the sandbox is
+  # only a temporary location. The id should be the final target path.
+  # Also, we shouldn't use the complete version number for id, as that'll
+  # make applications depend on the exact major.minor.patch version of serf.
+
+  install_shared_path = install_shared[0].abspath
+  target_install_shared_path = os.path.join(libdir, '%s.dylib' % LIBNAME)
+  env.AddPostAction(install_shared, ('install_name_tool -id %s %s'
+                                     % (target_install_shared_path,
+                                        install_shared_path)))
+
+env.Alias('install-lib', [install_static, install_shared,
+                          ])
+env.Alias('install-inc', env.Install(incdir, HEADER_FILES))
+env.Alias('install-pc', env.Install(os.path.join(libdir, 'pkgconfig'),
+                                    pkgconfig))
+env.Alias('install', ['install-lib', 'install-inc', 'install-pc', ])
+
+
+# TESTS
+### make move to a separate scons file in the test/ subdir?
+
+tenv = env.Clone()
+
+# MockHTTP requires C99 standard, so use it for the test suite.
+cflags = tenv['CFLAGS']
+tenv.Replace(CFLAGS = [f.replace('-std=c89', '-std=c99') for f in cflags])
+
+tenv.Append(CPPDEFINES=['MOCKHTTP_OPENSSL'])
+
+TEST_PROGRAMS = [ 'serf_get', 'serf_response', 'serf_request', 'serf_spider',
+                  'test_all', 'serf_bwtp' ]
+if sys.platform == 'win32':
+  TEST_EXES = [ os.path.join('test', '%s.exe' % (prog)) for prog in TEST_PROGRAMS ]
+else:
+  TEST_EXES = [ os.path.join('test', '%s' % (prog)) for prog in TEST_PROGRAMS ]
+
+# Find the (dynamic) library in this directory
+tenv.Replace(RPATH=thisdir)
+tenv.Prepend(LIBS=[LIBNAMESTATIC, ],
+             LIBPATH=[thisdir, ])
+
+check_script = env.File('build/check.py').rstr()
+test_dir = env.File('test/test_all.c').rfile().get_dir()
+src_dir = env.File('serf.h').rfile().get_dir()
+test_app = ("%s %s %s %s") % (sys.executable, check_script, test_dir, 'test')
+
+# Set the library search path for the test programs
+test_env = {'PATH' : os.environ['PATH'],
+            'srcdir' : src_dir}
+if sys.platform != 'win32':
+  test_env['LD_LIBRARY_PATH'] = ':'.join(tenv.get('LIBPATH', []))
+env.AlwaysBuild(env.Alias('check', TEST_EXES, test_app, ENV=test_env))
+
+testall_files = [
+        'test/test_all.c',
+        'test/CuTest.c',
+        'test/test_util.c',
+        'test/test_context.c',
+        'test/test_buckets.c',
+        'test/test_auth.c',
+        'test/mock_buckets.c',
+        'test/test_ssl.c',
+        'test/server/test_server.c',
+        'test/server/test_sslserver.c',
+        ]
+
+for proggie in TEST_EXES:
+  if 'test_all' in proggie:
+    tenv.Program(proggie, testall_files )
+  else:
+    tenv.Program(target = proggie, source = [proggie.replace('.exe','') + '.c'])
+
+
+# HANDLE CLEANING
+
+if env.GetOption('clean'):
+  # When we're cleaning, we want the dependency tree to include "everything"
+  # that could be built. Thus, include all of the tests.
+  env.Default('check')

Deleted: vendor/serf/1.3.9/auth/auth.c
===================================================================
--- vendor/serf/dist/auth/auth.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/auth/auth.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,485 +0,0 @@
-/* Copyright 2009 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 "serf.h"
-#include "serf_private.h"
-#include "auth.h"
-
-#include <apr.h>
-#include <apr_base64.h>
-#include <apr_strings.h>
-#include <apr_lib.h>
-
-static apr_status_t
-default_auth_response_handler(const serf__authn_scheme_t *scheme,
-                              peer_t peer,
-                              int code,
-                              serf_connection_t *conn,
-                              serf_request_t *request,
-                              serf_bucket_t *response,
-                              apr_pool_t *pool)
-{
-    return APR_SUCCESS;
-}
-
-/* These authentication schemes are in order of decreasing security, the topmost
-   scheme will be used first when the server supports it.
- 
-   Each set of handlers should support both server (401) and proxy (407)
-   authentication.
- 
-   Use lower case for the scheme names to enable case insensitive matching.
- */
-static const serf__authn_scheme_t serf_authn_schemes[] = {
-#ifdef SERF_HAVE_SPNEGO
-    {
-        "Negotiate",
-        "negotiate",
-        SERF_AUTHN_NEGOTIATE,
-        serf__init_spnego,
-        serf__init_spnego_connection,
-        serf__handle_spnego_auth,
-        serf__setup_request_spnego_auth,
-        serf__validate_response_spnego_auth,
-    },
-#ifdef WIN32
-    {
-        "NTLM",
-        "ntlm",
-        SERF_AUTHN_NTLM,
-        serf__init_spnego,
-        serf__init_spnego_connection,
-        serf__handle_spnego_auth,
-        serf__setup_request_spnego_auth,
-        serf__validate_response_spnego_auth,
-    },
-#endif /* #ifdef WIN32 */
-#endif /* SERF_HAVE_SPNEGO */
-    {
-        "Digest",
-        "digest",
-        SERF_AUTHN_DIGEST,
-        serf__init_digest,
-        serf__init_digest_connection,
-        serf__handle_digest_auth,
-        serf__setup_request_digest_auth,
-        serf__validate_response_digest_auth,
-    },
-    {
-        "Basic",
-        "basic",
-        SERF_AUTHN_BASIC,
-        serf__init_basic,
-        serf__init_basic_connection,
-        serf__handle_basic_auth,
-        serf__setup_request_basic_auth,
-        default_auth_response_handler,
-    },
-    /* ADD NEW AUTHENTICATION IMPLEMENTATIONS HERE (as they're written) */
-
-    /* sentinel */
-    { 0 }
-};
-
-
-/* Reads and discards all bytes in the response body. */
-static apr_status_t discard_body(serf_bucket_t *response)
-{
-    apr_status_t status;
-    const char *data;
-    apr_size_t len;
-
-    while (1) {
-        status = serf_bucket_read(response, SERF_READ_ALL_AVAIL, &data, &len);
-
-        if (status) {
-            return status;
-        }
-
-        /* feed me */
-    }
-}
-
-/**
- * handle_auth_header is called for each header in the response. It filters
- * out the Authenticate headers (WWW or Proxy depending on what's needed) and
- * tries to find a matching scheme handler.
- *
- * Returns a non-0 value of a matching handler was found.
- */
-static int handle_auth_headers(int code,
-                               void *baton,
-                               apr_hash_t *hdrs,
-                               serf_request_t *request,
-                               serf_bucket_t *response,
-                               apr_pool_t *pool)
-{
-    const serf__authn_scheme_t *scheme;
-    serf_connection_t *conn = request->conn;
-    serf_context_t *ctx = conn->ctx;
-    apr_status_t status;
-
-    status = SERF_ERROR_AUTHN_NOT_SUPPORTED;
-
-    /* Find the matching authentication handler.
-       Note that we don't reuse the auth scheme stored in the context,
-       as that may have changed. (ex. fallback from ntlm to basic.) */
-    for (scheme = serf_authn_schemes; scheme->name != 0; ++scheme) {
-        const char *auth_hdr;
-        serf__auth_handler_func_t handler;
-        serf__authn_info_t *authn_info;
-
-        if (! (ctx->authn_types & scheme->type))
-            continue;
-
-        serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
-                      "Client supports: %s\n", scheme->name);
-
-        auth_hdr = apr_hash_get(hdrs, scheme->key, APR_HASH_KEY_STRING);
-
-        if (!auth_hdr)
-            continue;
-
-        if (code == 401) {
-            authn_info = serf__get_authn_info_for_server(conn);
-        } else {
-            authn_info = &ctx->proxy_authn_info;
-        }
-
-        if (authn_info->failed_authn_types & scheme->type) {
-            /* Skip this authn type since we already tried it before. */
-            continue;
-        }
-
-        /* Found a matching scheme */
-        status = APR_SUCCESS;
-
-        handler = scheme->handle_func;
-
-        serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
-                      "... matched: %s\n", scheme->name);
-
-        /* If this is the first time we use this scheme on this context and/or
-           this connection, make sure to initialize the authentication handler 
-           first. */
-        if (authn_info->scheme != scheme) {
-            status = scheme->init_ctx_func(code, ctx, ctx->pool);
-            if (!status) {
-                status = scheme->init_conn_func(scheme, code, conn,
-                                                conn->pool);
-                if (!status)
-                    authn_info->scheme = scheme;
-                else
-                    authn_info->scheme = NULL;
-            }
-        }
-
-        if (!status) {
-            const char *auth_attr = strchr(auth_hdr, ' ');
-            if (auth_attr) {
-                auth_attr++;
-            }
-
-            status = handler(code, request, response,
-                             auth_hdr, auth_attr, baton, ctx->pool);
-        }
-
-        if (status == APR_SUCCESS)
-            break;
-
-        /* No success authenticating with this scheme, try the next.
-           If no more authn schemes are found the status of this scheme will be
-           returned.
-        */
-        serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
-                      "%s authentication failed.\n", scheme->name);
-
-        /* Clear per-request auth_baton when switching to next auth scheme. */
-        request->auth_baton = NULL;
-
-        /* Remember failed auth types to skip in future. */
-        authn_info->failed_authn_types |= scheme->type;
-    }
-
-    return status;
-}
-
-/**
- * Baton passed to the store_header_in_dict callback function
- */
-typedef struct {
-    const char *header;
-    apr_pool_t *pool;
-    apr_hash_t *hdrs;
-} auth_baton_t;
-
-static int store_header_in_dict(void *baton,
-                                const char *key,
-                                const char *header)
-{
-    auth_baton_t *ab = baton;
-    const char *auth_attr;
-    char *auth_name, *c;
-
-    /* We're only interested in xxxx-Authenticate headers. */
-    if (strcasecmp(key, ab->header) != 0)
-        return 0;
-
-    /* Extract the authentication scheme name.  */
-    auth_attr = strchr(header, ' ');
-    if (auth_attr) {
-        auth_name = apr_pstrmemdup(ab->pool, header, auth_attr - header);
-    }
-    else
-        auth_name = apr_pstrmemdup(ab->pool, header, strlen(header));
-
-    /* Convert scheme name to lower case to enable case insensitive matching. */
-    for (c = auth_name; *c != '\0'; c++)
-        *c = (char)apr_tolower(*c);
-
-    apr_hash_set(ab->hdrs, auth_name, APR_HASH_KEY_STRING,
-                 apr_pstrdup(ab->pool, header));
-
-    return 0;
-}
-
-/* Dispatch authentication handling. This function matches the possible
-   authentication mechanisms with those available. Server and proxy
-   authentication are evaluated separately. */
-static apr_status_t dispatch_auth(int code,
-                                  serf_request_t *request,
-                                  serf_bucket_t *response,
-                                  void *baton,
-                                  apr_pool_t *pool)
-{
-    serf_bucket_t *hdrs;
-
-    if (code == 401 || code == 407) {
-        auth_baton_t ab = { 0 };
-        const char *auth_hdr;
-
-        ab.hdrs = apr_hash_make(pool);
-        ab.pool = pool;
-
-        /* Before iterating over all authn headers, check if there are any. */
-        if (code == 401)
-            ab.header = "WWW-Authenticate";
-        else
-            ab.header = "Proxy-Authenticate";
-
-        hdrs = serf_bucket_response_get_headers(response);
-        auth_hdr = serf_bucket_headers_get(hdrs, ab.header);
-
-        if (!auth_hdr) {
-            return SERF_ERROR_AUTHN_FAILED;
-        }
-        serf__log_skt(AUTH_VERBOSE, __FILE__, request->conn->skt,
-                      "%s authz required. Response header(s): %s\n",
-                      code == 401 ? "Server" : "Proxy", auth_hdr);
-
-
-        /* Store all WWW- or Proxy-Authenticate headers in a dictionary.
-
-           Note: it is possible to have multiple Authentication: headers. We do
-           not want to combine them (per normal header combination rules) as that
-           would make it hard to parse. Instead, we want to individually parse
-           and handle each header in the response, looking for one that we can
-           work with.
-        */
-        serf_bucket_headers_do(hdrs,
-                               store_header_in_dict,
-                               &ab);
-
-        /* Iterate over all authentication schemes, in order of decreasing
-           security. Try to find a authentication schema the server support. */
-        return handle_auth_headers(code, baton, ab.hdrs,
-                                   request, response, pool);
-    }
-
-    return APR_SUCCESS;
-}
-
-/* Read the headers of the response and try the available
-   handlers if authentication or validation is needed. */
-apr_status_t serf__handle_auth_response(int *consumed_response,
-                                        serf_request_t *request,
-                                        serf_bucket_t *response,
-                                        void *baton,
-                                        apr_pool_t *pool)
-{
-    apr_status_t status;
-    serf_status_line sl;
-
-    *consumed_response = 0;
-
-    /* TODO: the response bucket was created by the application, not at all
-       guaranteed that this is of type response_bucket!! */
-    status = serf_bucket_response_status(response, &sl);
-    if (SERF_BUCKET_READ_ERROR(status)) {
-        return status;
-    }
-    if (!sl.version && (APR_STATUS_IS_EOF(status) ||
-                        APR_STATUS_IS_EAGAIN(status))) {
-        return status;
-    }
-
-    status = serf_bucket_response_wait_for_headers(response);
-    if (status) {
-        if (!APR_STATUS_IS_EOF(status)) {
-            return status;
-        }
-
-        /* If status is APR_EOF, there were no headers to read.
-           This can be ok in some situations, and it definitely
-           means there's no authentication requested now. */
-        return APR_SUCCESS;
-    }
-
-    if (sl.code == 401 || sl.code == 407) {
-        /* Authentication requested. */
-
-        /* Don't bother handling the authentication request if the response
-           wasn't received completely yet. Serf will call serf__handle_auth_response
-           again when more data is received. */
-        status = discard_body(response);
-        *consumed_response = 1;
-        
-        /* Discard all response body before processing authentication. */
-        if (!APR_STATUS_IS_EOF(status)) {
-            return status;
-        }
-
-        status = dispatch_auth(sl.code, request, response, baton, pool);
-        if (status != APR_SUCCESS) {
-            return status;
-        }
-
-        /* Requeue the request with the necessary auth headers. */
-        /* ### Application doesn't know about this request! */
-        if (request->ssltunnel) {
-            serf__ssltunnel_request_create(request->conn,
-                                           request->setup,
-                                           request->setup_baton);
-        } else {
-            serf_connection_priority_request_create(request->conn,
-                                                    request->setup,
-                                                    request->setup_baton);
-        }
-
-        return APR_EOF;
-    } else {
-        serf__validate_response_func_t validate_resp;
-        serf_connection_t *conn = request->conn;
-        serf_context_t *ctx = conn->ctx;
-        serf__authn_info_t *authn_info;
-        apr_status_t resp_status = APR_SUCCESS;
-
-
-        /* Validate the response server authn headers. */
-        authn_info = serf__get_authn_info_for_server(conn);
-        if (authn_info->scheme) {
-            validate_resp = authn_info->scheme->validate_response_func;
-            resp_status = validate_resp(authn_info->scheme, HOST, sl.code,
-                                        conn, request, response, pool);
-        }
-
-        /* Validate the response proxy authn headers. */
-        authn_info = &ctx->proxy_authn_info;
-        if (!resp_status && authn_info->scheme) {
-            validate_resp = authn_info->scheme->validate_response_func;
-            resp_status = validate_resp(authn_info->scheme, PROXY, sl.code,
-                                        conn, request, response, pool);
-        }
-
-        if (resp_status) {
-            /* If there was an error in the final step of the authentication,
-               consider the reponse body as invalid and discard it. */
-            status = discard_body(response);
-            *consumed_response = 1;
-            if (!APR_STATUS_IS_EOF(status)) {
-                return status;
-            }
-            /* The whole body was discarded, now return our error. */
-            return resp_status;
-        }
-    }
-
-    return APR_SUCCESS;
-}
-
-/**
- * base64 encode the authentication data and build an authentication
- * header in this format:
- * [SCHEME] [BASE64 of auth DATA]
- */
-void serf__encode_auth_header(const char **header,
-                              const char *scheme,
-                              const char *data, apr_size_t data_len,
-                              apr_pool_t *pool)
-{
-    apr_size_t encoded_len, scheme_len;
-    char *ptr;
-
-    encoded_len = apr_base64_encode_len(data_len);
-    scheme_len = strlen(scheme);
-
-    ptr = apr_palloc(pool, encoded_len + scheme_len + 1);
-    *header = ptr;
-
-    apr_cpystrn(ptr, scheme, scheme_len + 1);
-    ptr += scheme_len;
-    *ptr++ = ' ';
-
-    apr_base64_encode(ptr, data, data_len);
-}
-
-const char *serf__construct_realm(peer_t peer,
-                                  serf_connection_t *conn,
-                                  const char *realm_name,
-                                  apr_pool_t *pool)
-{
-    if (peer == HOST) {
-        return apr_psprintf(pool, "<%s://%s:%d> %s",
-                            conn->host_info.scheme,
-                            conn->host_info.hostname,
-                            conn->host_info.port,
-                            realm_name);
-    } else {
-        serf_context_t *ctx = conn->ctx;
-
-        return apr_psprintf(pool, "<http://%s:%d> %s",
-                            ctx->proxy_address->hostname,
-                            ctx->proxy_address->port,
-                            realm_name);
-    }
-}
-
-serf__authn_info_t *serf__get_authn_info_for_server(serf_connection_t *conn)
-{
-    serf_context_t *ctx = conn->ctx;
-    serf__authn_info_t *authn_info;
-
-    authn_info = apr_hash_get(ctx->server_authn_info, conn->host_url,
-                              APR_HASH_KEY_STRING);
-
-    if (!authn_info) {
-        authn_info = apr_pcalloc(ctx->pool, sizeof(serf__authn_info_t));
-        apr_hash_set(ctx->server_authn_info,
-                     apr_pstrdup(ctx->pool, conn->host_url),
-                     APR_HASH_KEY_STRING, authn_info);
-    }
-
-    return authn_info;
-}

Copied: vendor/serf/1.3.9/auth/auth.c (from rev 9259, vendor/serf/dist/auth/auth.c)
===================================================================
--- vendor/serf/1.3.9/auth/auth.c	                        (rev 0)
+++ vendor/serf/1.3.9/auth/auth.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,490 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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 "serf.h"
+#include "serf_private.h"
+#include "auth.h"
+
+#include <apr.h>
+#include <apr_base64.h>
+#include <apr_strings.h>
+#include <apr_lib.h>
+
+static apr_status_t
+default_auth_response_handler(const serf__authn_scheme_t *scheme,
+                              peer_t peer,
+                              int code,
+                              serf_connection_t *conn,
+                              serf_request_t *request,
+                              serf_bucket_t *response,
+                              apr_pool_t *pool)
+{
+    return APR_SUCCESS;
+}
+
+/* These authentication schemes are in order of decreasing security, the topmost
+   scheme will be used first when the server supports it.
+ 
+   Each set of handlers should support both server (401) and proxy (407)
+   authentication.
+ 
+   Use lower case for the scheme names to enable case insensitive matching.
+ */
+static const serf__authn_scheme_t serf_authn_schemes[] = {
+#ifdef SERF_HAVE_SPNEGO
+    {
+        "Negotiate",
+        "negotiate",
+        SERF_AUTHN_NEGOTIATE,
+        serf__init_spnego,
+        serf__init_spnego_connection,
+        serf__handle_spnego_auth,
+        serf__setup_request_spnego_auth,
+        serf__validate_response_spnego_auth,
+    },
+#ifdef WIN32
+    {
+        "NTLM",
+        "ntlm",
+        SERF_AUTHN_NTLM,
+        serf__init_spnego,
+        serf__init_spnego_connection,
+        serf__handle_spnego_auth,
+        serf__setup_request_spnego_auth,
+        serf__validate_response_spnego_auth,
+    },
+#endif /* #ifdef WIN32 */
+#endif /* SERF_HAVE_SPNEGO */
+    {
+        "Digest",
+        "digest",
+        SERF_AUTHN_DIGEST,
+        serf__init_digest,
+        serf__init_digest_connection,
+        serf__handle_digest_auth,
+        serf__setup_request_digest_auth,
+        serf__validate_response_digest_auth,
+    },
+    {
+        "Basic",
+        "basic",
+        SERF_AUTHN_BASIC,
+        serf__init_basic,
+        serf__init_basic_connection,
+        serf__handle_basic_auth,
+        serf__setup_request_basic_auth,
+        default_auth_response_handler,
+    },
+    /* ADD NEW AUTHENTICATION IMPLEMENTATIONS HERE (as they're written) */
+
+    /* sentinel */
+    { 0 }
+};
+
+
+/* Reads and discards all bytes in the response body. */
+static apr_status_t discard_body(serf_bucket_t *response)
+{
+    apr_status_t status;
+    const char *data;
+    apr_size_t len;
+
+    while (1) {
+        status = serf_bucket_read(response, SERF_READ_ALL_AVAIL, &data, &len);
+
+        if (status) {
+            return status;
+        }
+
+        /* feed me */
+    }
+}
+
+/**
+ * handle_auth_header is called for each header in the response. It filters
+ * out the Authenticate headers (WWW or Proxy depending on what's needed) and
+ * tries to find a matching scheme handler.
+ *
+ * Returns a non-0 value of a matching handler was found.
+ */
+static int handle_auth_headers(int code,
+                               void *baton,
+                               apr_hash_t *hdrs,
+                               serf_request_t *request,
+                               serf_bucket_t *response,
+                               apr_pool_t *pool)
+{
+    const serf__authn_scheme_t *scheme;
+    serf_connection_t *conn = request->conn;
+    serf_context_t *ctx = conn->ctx;
+    apr_status_t status;
+
+    status = SERF_ERROR_AUTHN_NOT_SUPPORTED;
+
+    /* Find the matching authentication handler.
+       Note that we don't reuse the auth scheme stored in the context,
+       as that may have changed. (ex. fallback from ntlm to basic.) */
+    for (scheme = serf_authn_schemes; scheme->name != 0; ++scheme) {
+        const char *auth_hdr;
+        serf__auth_handler_func_t handler;
+        serf__authn_info_t *authn_info;
+
+        if (! (ctx->authn_types & scheme->type))
+            continue;
+
+        serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
+                      "Client supports: %s\n", scheme->name);
+
+        auth_hdr = apr_hash_get(hdrs, scheme->key, APR_HASH_KEY_STRING);
+
+        if (!auth_hdr)
+            continue;
+
+        if (code == 401) {
+            authn_info = serf__get_authn_info_for_server(conn);
+        } else {
+            authn_info = &ctx->proxy_authn_info;
+        }
+
+        if (authn_info->failed_authn_types & scheme->type) {
+            /* Skip this authn type since we already tried it before. */
+            continue;
+        }
+
+        /* Found a matching scheme */
+        status = APR_SUCCESS;
+
+        handler = scheme->handle_func;
+
+        serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
+                      "... matched: %s\n", scheme->name);
+
+        /* If this is the first time we use this scheme on this context and/or
+           this connection, make sure to initialize the authentication handler 
+           first. */
+        if (authn_info->scheme != scheme) {
+            status = scheme->init_ctx_func(code, ctx, ctx->pool);
+            if (!status) {
+                status = scheme->init_conn_func(scheme, code, conn,
+                                                conn->pool);
+                if (!status)
+                    authn_info->scheme = scheme;
+                else
+                    authn_info->scheme = NULL;
+            }
+        }
+
+        if (!status) {
+            const char *auth_attr = strchr(auth_hdr, ' ');
+            if (auth_attr) {
+                auth_attr++;
+            }
+
+            status = handler(code, request, response,
+                             auth_hdr, auth_attr, baton, ctx->pool);
+        }
+
+        if (status == APR_SUCCESS)
+            break;
+
+        /* No success authenticating with this scheme, try the next.
+           If no more authn schemes are found the status of this scheme will be
+           returned.
+        */
+        serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
+                      "%s authentication failed.\n", scheme->name);
+
+        /* Clear per-request auth_baton when switching to next auth scheme. */
+        request->auth_baton = NULL;
+
+        /* Remember failed auth types to skip in future. */
+        authn_info->failed_authn_types |= scheme->type;
+    }
+
+    return status;
+}
+
+/**
+ * Baton passed to the store_header_in_dict callback function
+ */
+typedef struct {
+    const char *header;
+    apr_pool_t *pool;
+    apr_hash_t *hdrs;
+} auth_baton_t;
+
+static int store_header_in_dict(void *baton,
+                                const char *key,
+                                const char *header)
+{
+    auth_baton_t *ab = baton;
+    const char *auth_attr;
+    char *auth_name, *c;
+
+    /* We're only interested in xxxx-Authenticate headers. */
+    if (strcasecmp(key, ab->header) != 0)
+        return 0;
+
+    /* Extract the authentication scheme name.  */
+    auth_attr = strchr(header, ' ');
+    if (auth_attr) {
+        auth_name = apr_pstrmemdup(ab->pool, header, auth_attr - header);
+    }
+    else
+        auth_name = apr_pstrmemdup(ab->pool, header, strlen(header));
+
+    /* Convert scheme name to lower case to enable case insensitive matching. */
+    for (c = auth_name; *c != '\0'; c++)
+        *c = (char)apr_tolower(*c);
+
+    apr_hash_set(ab->hdrs, auth_name, APR_HASH_KEY_STRING,
+                 apr_pstrdup(ab->pool, header));
+
+    return 0;
+}
+
+/* Dispatch authentication handling. This function matches the possible
+   authentication mechanisms with those available. Server and proxy
+   authentication are evaluated separately. */
+static apr_status_t dispatch_auth(int code,
+                                  serf_request_t *request,
+                                  serf_bucket_t *response,
+                                  void *baton,
+                                  apr_pool_t *pool)
+{
+    serf_bucket_t *hdrs;
+
+    if (code == 401 || code == 407) {
+        auth_baton_t ab = { 0 };
+        const char *auth_hdr;
+
+        ab.hdrs = apr_hash_make(pool);
+        ab.pool = pool;
+
+        /* Before iterating over all authn headers, check if there are any. */
+        if (code == 401)
+            ab.header = "WWW-Authenticate";
+        else
+            ab.header = "Proxy-Authenticate";
+
+        hdrs = serf_bucket_response_get_headers(response);
+        auth_hdr = serf_bucket_headers_get(hdrs, ab.header);
+
+        if (!auth_hdr) {
+            return SERF_ERROR_AUTHN_FAILED;
+        }
+        serf__log_skt(AUTH_VERBOSE, __FILE__, request->conn->skt,
+                      "%s authz required. Response header(s): %s\n",
+                      code == 401 ? "Server" : "Proxy", auth_hdr);
+
+
+        /* Store all WWW- or Proxy-Authenticate headers in a dictionary.
+
+           Note: it is possible to have multiple Authentication: headers. We do
+           not want to combine them (per normal header combination rules) as that
+           would make it hard to parse. Instead, we want to individually parse
+           and handle each header in the response, looking for one that we can
+           work with.
+        */
+        serf_bucket_headers_do(hdrs,
+                               store_header_in_dict,
+                               &ab);
+
+        /* Iterate over all authentication schemes, in order of decreasing
+           security. Try to find a authentication schema the server support. */
+        return handle_auth_headers(code, baton, ab.hdrs,
+                                   request, response, pool);
+    }
+
+    return APR_SUCCESS;
+}
+
+/* Read the headers of the response and try the available
+   handlers if authentication or validation is needed. */
+apr_status_t serf__handle_auth_response(int *consumed_response,
+                                        serf_request_t *request,
+                                        serf_bucket_t *response,
+                                        void *baton,
+                                        apr_pool_t *pool)
+{
+    apr_status_t status;
+    serf_status_line sl;
+
+    *consumed_response = 0;
+
+    /* TODO: the response bucket was created by the application, not at all
+       guaranteed that this is of type response_bucket!! */
+    status = serf_bucket_response_status(response, &sl);
+    if (SERF_BUCKET_READ_ERROR(status)) {
+        return status;
+    }
+    if (!sl.version && (APR_STATUS_IS_EOF(status) ||
+                        APR_STATUS_IS_EAGAIN(status))) {
+        return status;
+    }
+
+    status = serf_bucket_response_wait_for_headers(response);
+    if (status) {
+        if (!APR_STATUS_IS_EOF(status)) {
+            return status;
+        }
+
+        /* If status is APR_EOF, there were no headers to read.
+           This can be ok in some situations, and it definitely
+           means there's no authentication requested now. */
+        return APR_SUCCESS;
+    }
+
+    if (sl.code == 401 || sl.code == 407) {
+        /* Authentication requested. */
+
+        /* Don't bother handling the authentication request if the response
+           wasn't received completely yet. Serf will call serf__handle_auth_response
+           again when more data is received. */
+        status = discard_body(response);
+        *consumed_response = 1;
+        
+        /* Discard all response body before processing authentication. */
+        if (!APR_STATUS_IS_EOF(status)) {
+            return status;
+        }
+
+        status = dispatch_auth(sl.code, request, response, baton, pool);
+        if (status != APR_SUCCESS) {
+            return status;
+        }
+
+        /* Requeue the request with the necessary auth headers. */
+        /* ### Application doesn't know about this request! */
+        if (request->ssltunnel) {
+            serf__ssltunnel_request_create(request->conn,
+                                           request->setup,
+                                           request->setup_baton);
+        } else {
+            serf_connection_priority_request_create(request->conn,
+                                                    request->setup,
+                                                    request->setup_baton);
+        }
+
+        return APR_EOF;
+    } else {
+        serf__validate_response_func_t validate_resp;
+        serf_connection_t *conn = request->conn;
+        serf_context_t *ctx = conn->ctx;
+        serf__authn_info_t *authn_info;
+        apr_status_t resp_status = APR_SUCCESS;
+
+
+        /* Validate the response server authn headers. */
+        authn_info = serf__get_authn_info_for_server(conn);
+        if (authn_info->scheme) {
+            validate_resp = authn_info->scheme->validate_response_func;
+            resp_status = validate_resp(authn_info->scheme, HOST, sl.code,
+                                        conn, request, response, pool);
+        }
+
+        /* Validate the response proxy authn headers. */
+        authn_info = &ctx->proxy_authn_info;
+        if (!resp_status && authn_info->scheme) {
+            validate_resp = authn_info->scheme->validate_response_func;
+            resp_status = validate_resp(authn_info->scheme, PROXY, sl.code,
+                                        conn, request, response, pool);
+        }
+
+        if (resp_status) {
+            /* If there was an error in the final step of the authentication,
+               consider the reponse body as invalid and discard it. */
+            status = discard_body(response);
+            *consumed_response = 1;
+            if (!APR_STATUS_IS_EOF(status)) {
+                return status;
+            }
+            /* The whole body was discarded, now return our error. */
+            return resp_status;
+        }
+    }
+
+    return APR_SUCCESS;
+}
+
+/**
+ * base64 encode the authentication data and build an authentication
+ * header in this format:
+ * [SCHEME] [BASE64 of auth DATA]
+ */
+void serf__encode_auth_header(const char **header,
+                              const char *scheme,
+                              const char *data, apr_size_t data_len,
+                              apr_pool_t *pool)
+{
+    apr_size_t encoded_len, scheme_len;
+    char *ptr;
+
+    encoded_len = apr_base64_encode_len(data_len);
+    scheme_len = strlen(scheme);
+
+    ptr = apr_palloc(pool, encoded_len + scheme_len + 1);
+    *header = ptr;
+
+    apr_cpystrn(ptr, scheme, scheme_len + 1);
+    ptr += scheme_len;
+    *ptr++ = ' ';
+
+    apr_base64_encode(ptr, data, data_len);
+}
+
+const char *serf__construct_realm(peer_t peer,
+                                  serf_connection_t *conn,
+                                  const char *realm_name,
+                                  apr_pool_t *pool)
+{
+    if (peer == HOST) {
+        return apr_psprintf(pool, "<%s://%s:%d> %s",
+                            conn->host_info.scheme,
+                            conn->host_info.hostname,
+                            conn->host_info.port,
+                            realm_name);
+    } else {
+        serf_context_t *ctx = conn->ctx;
+
+        return apr_psprintf(pool, "<http://%s:%d> %s",
+                            ctx->proxy_address->hostname,
+                            ctx->proxy_address->port,
+                            realm_name);
+    }
+}
+
+serf__authn_info_t *serf__get_authn_info_for_server(serf_connection_t *conn)
+{
+    serf_context_t *ctx = conn->ctx;
+    serf__authn_info_t *authn_info;
+
+    authn_info = apr_hash_get(ctx->server_authn_info, conn->host_url,
+                              APR_HASH_KEY_STRING);
+
+    if (!authn_info) {
+        authn_info = apr_pcalloc(ctx->pool, sizeof(serf__authn_info_t));
+        apr_hash_set(ctx->server_authn_info,
+                     apr_pstrdup(ctx->pool, conn->host_url),
+                     APR_HASH_KEY_STRING, authn_info);
+    }
+
+    return authn_info;
+}

Deleted: vendor/serf/1.3.9/auth/auth.h
===================================================================
--- vendor/serf/dist/auth/auth.h	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/auth/auth.h	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,125 +0,0 @@
-/* Copyright 2009 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 AUTH_H
-#define AUTH_H
-
-#include "auth_spnego.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void serf__encode_auth_header(const char **header, const char *protocol,
-                              const char *data, apr_size_t data_len,
-                              apr_pool_t *pool);
-
-/* Prefixes the realm_name with a string containing scheme, hostname and port
-   of the connection, for providing it to the application. */
-const char *serf__construct_realm(peer_t peer,
-                                  serf_connection_t *conn,
-                                  const char *realm_name,
-                                  apr_pool_t *pool);
-
-/** Basic authentication **/
-apr_status_t serf__init_basic(int code,
-                              serf_context_t *ctx,
-                              apr_pool_t *pool);
-apr_status_t serf__init_basic_connection(const serf__authn_scheme_t *scheme,
-                                         int code,
-                                         serf_connection_t *conn,
-                                         apr_pool_t *pool);
-apr_status_t serf__handle_basic_auth(int code,
-                                     serf_request_t *request,
-                                     serf_bucket_t *response,
-                                     const char *auth_hdr,
-                                     const char *auth_attr,
-                                     void *baton,
-                                     apr_pool_t *pool);
-apr_status_t serf__setup_request_basic_auth(peer_t peer,
-                                            int code,
-                                            serf_connection_t *conn,
-                                            serf_request_t *request,
-                                            const char *method,
-                                            const char *uri,
-                                            serf_bucket_t *hdrs_bkt);
-
-/** Digest authentication **/
-apr_status_t serf__init_digest(int code,
-                               serf_context_t *ctx,
-                               apr_pool_t *pool);
-apr_status_t serf__init_digest_connection(const serf__authn_scheme_t *scheme,
-                                          int code,
-                                          serf_connection_t *conn,
-                                          apr_pool_t *pool);
-apr_status_t serf__handle_digest_auth(int code,
-                                      serf_request_t *request,
-                                      serf_bucket_t *response,
-                                      const char *auth_hdr,
-                                      const char *auth_attr,
-                                      void *baton,
-                                      apr_pool_t *pool);
-apr_status_t serf__setup_request_digest_auth(peer_t peer,
-                                             int code,
-                                             serf_connection_t *conn,
-                                             serf_request_t *request,
-                                             const char *method,
-                                             const char *uri,
-                                             serf_bucket_t *hdrs_bkt);
-apr_status_t serf__validate_response_digest_auth(const serf__authn_scheme_t *scheme,
-                                                 peer_t peer,
-                                                 int code,
-                                                 serf_connection_t *conn,
-                                                 serf_request_t *request,
-                                                 serf_bucket_t *response,
-                                                 apr_pool_t *pool);
-
-#ifdef SERF_HAVE_SPNEGO
-/** Kerberos authentication **/
-apr_status_t serf__init_spnego(int code,
-                               serf_context_t *ctx,
-                               apr_pool_t *pool);
-apr_status_t serf__init_spnego_connection(const serf__authn_scheme_t *scheme,
-                                          int code,
-                                          serf_connection_t *conn,
-                                          apr_pool_t *pool);
-apr_status_t serf__handle_spnego_auth(int code,
-                                     serf_request_t *request,
-                                     serf_bucket_t *response,
-                                     const char *auth_hdr,
-                                     const char *auth_attr,
-                                     void *baton,
-                                     apr_pool_t *pool);
-apr_status_t serf__setup_request_spnego_auth(peer_t peer,
-                                             int code,
-                                             serf_connection_t *conn,
-                                             serf_request_t *request,
-                                             const char *method,
-                                             const char *uri,
-                                             serf_bucket_t *hdrs_bkt);
-apr_status_t serf__validate_response_spnego_auth(const serf__authn_scheme_t *scheme,
-                                                 peer_t peer,
-                                                 int code,
-                                                 serf_connection_t *conn,
-                                                 serf_request_t *request,
-                                                 serf_bucket_t *response,
-                                                 apr_pool_t *pool);
-#endif /* SERF_HAVE_SPNEGO */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif    /* !AUTH_H */

Copied: vendor/serf/1.3.9/auth/auth.h (from rev 9259, vendor/serf/dist/auth/auth.h)
===================================================================
--- vendor/serf/1.3.9/auth/auth.h	                        (rev 0)
+++ vendor/serf/1.3.9/auth/auth.h	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,130 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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 AUTH_H
+#define AUTH_H
+
+#include "auth_spnego.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void serf__encode_auth_header(const char **header, const char *protocol,
+                              const char *data, apr_size_t data_len,
+                              apr_pool_t *pool);
+
+/* Prefixes the realm_name with a string containing scheme, hostname and port
+   of the connection, for providing it to the application. */
+const char *serf__construct_realm(peer_t peer,
+                                  serf_connection_t *conn,
+                                  const char *realm_name,
+                                  apr_pool_t *pool);
+
+/** Basic authentication **/
+apr_status_t serf__init_basic(int code,
+                              serf_context_t *ctx,
+                              apr_pool_t *pool);
+apr_status_t serf__init_basic_connection(const serf__authn_scheme_t *scheme,
+                                         int code,
+                                         serf_connection_t *conn,
+                                         apr_pool_t *pool);
+apr_status_t serf__handle_basic_auth(int code,
+                                     serf_request_t *request,
+                                     serf_bucket_t *response,
+                                     const char *auth_hdr,
+                                     const char *auth_attr,
+                                     void *baton,
+                                     apr_pool_t *pool);
+apr_status_t serf__setup_request_basic_auth(peer_t peer,
+                                            int code,
+                                            serf_connection_t *conn,
+                                            serf_request_t *request,
+                                            const char *method,
+                                            const char *uri,
+                                            serf_bucket_t *hdrs_bkt);
+
+/** Digest authentication **/
+apr_status_t serf__init_digest(int code,
+                               serf_context_t *ctx,
+                               apr_pool_t *pool);
+apr_status_t serf__init_digest_connection(const serf__authn_scheme_t *scheme,
+                                          int code,
+                                          serf_connection_t *conn,
+                                          apr_pool_t *pool);
+apr_status_t serf__handle_digest_auth(int code,
+                                      serf_request_t *request,
+                                      serf_bucket_t *response,
+                                      const char *auth_hdr,
+                                      const char *auth_attr,
+                                      void *baton,
+                                      apr_pool_t *pool);
+apr_status_t serf__setup_request_digest_auth(peer_t peer,
+                                             int code,
+                                             serf_connection_t *conn,
+                                             serf_request_t *request,
+                                             const char *method,
+                                             const char *uri,
+                                             serf_bucket_t *hdrs_bkt);
+apr_status_t serf__validate_response_digest_auth(const serf__authn_scheme_t *scheme,
+                                                 peer_t peer,
+                                                 int code,
+                                                 serf_connection_t *conn,
+                                                 serf_request_t *request,
+                                                 serf_bucket_t *response,
+                                                 apr_pool_t *pool);
+
+#ifdef SERF_HAVE_SPNEGO
+/** Kerberos authentication **/
+apr_status_t serf__init_spnego(int code,
+                               serf_context_t *ctx,
+                               apr_pool_t *pool);
+apr_status_t serf__init_spnego_connection(const serf__authn_scheme_t *scheme,
+                                          int code,
+                                          serf_connection_t *conn,
+                                          apr_pool_t *pool);
+apr_status_t serf__handle_spnego_auth(int code,
+                                     serf_request_t *request,
+                                     serf_bucket_t *response,
+                                     const char *auth_hdr,
+                                     const char *auth_attr,
+                                     void *baton,
+                                     apr_pool_t *pool);
+apr_status_t serf__setup_request_spnego_auth(peer_t peer,
+                                             int code,
+                                             serf_connection_t *conn,
+                                             serf_request_t *request,
+                                             const char *method,
+                                             const char *uri,
+                                             serf_bucket_t *hdrs_bkt);
+apr_status_t serf__validate_response_spnego_auth(const serf__authn_scheme_t *scheme,
+                                                 peer_t peer,
+                                                 int code,
+                                                 serf_connection_t *conn,
+                                                 serf_request_t *request,
+                                                 serf_bucket_t *response,
+                                                 apr_pool_t *pool);
+#endif /* SERF_HAVE_SPNEGO */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif    /* !AUTH_H */

Deleted: vendor/serf/1.3.9/auth/auth_basic.c
===================================================================
--- vendor/serf/dist/auth/auth_basic.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/auth/auth_basic.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,177 +0,0 @@
-/* Copyright 2009 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.
- */
-
-/*** Basic authentication ***/
-
-#include <serf.h>
-#include <serf_private.h>
-#include <auth/auth.h>
-
-#include <apr.h>
-#include <apr_base64.h>
-#include <apr_strings.h>
-
-/* Stores the context information related to Basic authentication.
-   This information is stored in the per server cache in the serf context. */
-typedef struct basic_authn_info_t {
-    const char *header;
-    const char *value;
-} basic_authn_info_t;
-
-apr_status_t
-serf__handle_basic_auth(int code,
-                        serf_request_t *request,
-                        serf_bucket_t *response,
-                        const char *auth_hdr,
-                        const char *auth_attr,
-                        void *baton,
-                        apr_pool_t *pool)
-{
-    const char *tmp;
-    apr_size_t tmp_len;
-    serf_connection_t *conn = request->conn;
-    serf_context_t *ctx = conn->ctx;
-    serf__authn_info_t *authn_info;
-    basic_authn_info_t *basic_info;
-    apr_status_t status;
-    apr_pool_t *cred_pool;
-    char *username, *password, *realm_name;
-    const char *eq, *realm = NULL;
-
-    /* Can't do Basic authentication if there's no callback to get
-       username & password. */
-    if (!ctx->cred_cb) {
-        return SERF_ERROR_AUTHN_FAILED;
-    }
-
-    if (code == 401) {
-        authn_info = serf__get_authn_info_for_server(conn);
-    } else {
-        authn_info = &ctx->proxy_authn_info;
-    }
-    basic_info = authn_info->baton;
-
-    realm_name = NULL;
-    eq = strchr(auth_attr, '=');
-
-    if (eq && strncasecmp(auth_attr, "realm", 5) == 0) {
-        realm_name = apr_pstrdup(pool, eq + 1);
-        if (realm_name[0] == '\"') {
-            apr_size_t realm_len;
-
-            realm_len = strlen(realm_name);
-            if (realm_name[realm_len - 1] == '\"') {
-                realm_name[realm_len - 1] = '\0';
-                realm_name++;
-            }
-        }
-
-        if (!realm_name) {
-            return SERF_ERROR_AUTHN_MISSING_ATTRIBUTE;
-        }
-
-        realm = serf__construct_realm(code == 401 ? HOST : PROXY,
-                                      conn, realm_name,
-                                      pool);
-    }
-
-    /* Ask the application for credentials */
-    apr_pool_create(&cred_pool, pool);
-    status = serf__provide_credentials(ctx,
-                                       &username, &password,
-                                       request, baton,
-                                       code, authn_info->scheme->name,
-                                       realm, cred_pool);
-    if (status) {
-        apr_pool_destroy(cred_pool);
-        return status;
-    }
-
-    tmp = apr_pstrcat(conn->pool, username, ":", password, NULL);
-    tmp_len = strlen(tmp);
-    apr_pool_destroy(cred_pool);
-
-    serf__encode_auth_header(&basic_info->value,
-                             authn_info->scheme->name,
-                             tmp, tmp_len, pool);
-    basic_info->header = (code == 401) ? "Authorization" : "Proxy-Authorization";
-
-    return APR_SUCCESS;
-}
-
-apr_status_t
-serf__init_basic(int code,
-                 serf_context_t *ctx,
-                 apr_pool_t *pool)
-{
-    return APR_SUCCESS;
-}
-
-/* For Basic authentication we expect all authn info to be the same for all
-   connections in the context to the same server (same realm, username,
-   password). Therefore we can keep the header value in the per-server store
-   context instead of per connection.
-   TODO: we currently don't cache this info per realm, so each time a request
-   'switches realms', we have to ask the application for new credentials. */
-apr_status_t
-serf__init_basic_connection(const serf__authn_scheme_t *scheme,
-                            int code,
-                            serf_connection_t *conn,
-                            apr_pool_t *pool)
-{
-    serf_context_t *ctx = conn->ctx;
-    serf__authn_info_t *authn_info;
-
-    if (code == 401) {
-        authn_info = serf__get_authn_info_for_server(conn);
-    } else {
-        authn_info = &ctx->proxy_authn_info;
-    }
-
-    if (!authn_info->baton) {
-        authn_info->baton = apr_pcalloc(pool, sizeof(basic_authn_info_t));
-    }
-
-    return APR_SUCCESS;
-}
-
-apr_status_t
-serf__setup_request_basic_auth(peer_t peer,
-                               int code,
-                               serf_connection_t *conn,
-                               serf_request_t *request,
-                               const char *method,
-                               const char *uri,
-                               serf_bucket_t *hdrs_bkt)
-{
-    serf_context_t *ctx = conn->ctx;
-    serf__authn_info_t *authn_info;
-    basic_authn_info_t *basic_info;
-
-    if (peer == HOST) {
-        authn_info = serf__get_authn_info_for_server(conn);
-    } else {
-        authn_info = &ctx->proxy_authn_info;
-    }
-    basic_info = authn_info->baton;
-
-    if (basic_info && basic_info->header && basic_info->value) {
-        serf_bucket_headers_setn(hdrs_bkt, basic_info->header,
-                                 basic_info->value);
-        return APR_SUCCESS;
-    }
-
-    return SERF_ERROR_AUTHN_FAILED;
-}

Copied: vendor/serf/1.3.9/auth/auth_basic.c (from rev 9259, vendor/serf/dist/auth/auth_basic.c)
===================================================================
--- vendor/serf/1.3.9/auth/auth_basic.c	                        (rev 0)
+++ vendor/serf/1.3.9/auth/auth_basic.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,182 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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.
+ * ====================================================================
+ */
+
+/*** Basic authentication ***/
+
+#include <serf.h>
+#include <serf_private.h>
+#include <auth/auth.h>
+
+#include <apr.h>
+#include <apr_base64.h>
+#include <apr_strings.h>
+
+/* Stores the context information related to Basic authentication.
+   This information is stored in the per server cache in the serf context. */
+typedef struct basic_authn_info_t {
+    const char *header;
+    const char *value;
+} basic_authn_info_t;
+
+apr_status_t
+serf__handle_basic_auth(int code,
+                        serf_request_t *request,
+                        serf_bucket_t *response,
+                        const char *auth_hdr,
+                        const char *auth_attr,
+                        void *baton,
+                        apr_pool_t *pool)
+{
+    const char *tmp;
+    apr_size_t tmp_len;
+    serf_connection_t *conn = request->conn;
+    serf_context_t *ctx = conn->ctx;
+    serf__authn_info_t *authn_info;
+    basic_authn_info_t *basic_info;
+    apr_status_t status;
+    apr_pool_t *cred_pool;
+    char *username, *password, *realm_name;
+    const char *eq, *realm = NULL;
+
+    /* Can't do Basic authentication if there's no callback to get
+       username & password. */
+    if (!ctx->cred_cb) {
+        return SERF_ERROR_AUTHN_FAILED;
+    }
+
+    if (code == 401) {
+        authn_info = serf__get_authn_info_for_server(conn);
+    } else {
+        authn_info = &ctx->proxy_authn_info;
+    }
+    basic_info = authn_info->baton;
+
+    realm_name = NULL;
+    eq = strchr(auth_attr, '=');
+
+    if (eq && strncasecmp(auth_attr, "realm", 5) == 0) {
+        realm_name = apr_pstrdup(pool, eq + 1);
+        if (realm_name[0] == '\"') {
+            apr_size_t realm_len;
+
+            realm_len = strlen(realm_name);
+            if (realm_name[realm_len - 1] == '\"') {
+                realm_name[realm_len - 1] = '\0';
+                realm_name++;
+            }
+        }
+
+        if (!realm_name) {
+            return SERF_ERROR_AUTHN_MISSING_ATTRIBUTE;
+        }
+
+        realm = serf__construct_realm(code == 401 ? HOST : PROXY,
+                                      conn, realm_name,
+                                      pool);
+    }
+
+    /* Ask the application for credentials */
+    apr_pool_create(&cred_pool, pool);
+    status = serf__provide_credentials(ctx,
+                                       &username, &password,
+                                       request, baton,
+                                       code, authn_info->scheme->name,
+                                       realm, cred_pool);
+    if (status) {
+        apr_pool_destroy(cred_pool);
+        return status;
+    }
+
+    tmp = apr_pstrcat(conn->pool, username, ":", password, NULL);
+    tmp_len = strlen(tmp);
+    apr_pool_destroy(cred_pool);
+
+    serf__encode_auth_header(&basic_info->value,
+                             authn_info->scheme->name,
+                             tmp, tmp_len, pool);
+    basic_info->header = (code == 401) ? "Authorization" : "Proxy-Authorization";
+
+    return APR_SUCCESS;
+}
+
+apr_status_t
+serf__init_basic(int code,
+                 serf_context_t *ctx,
+                 apr_pool_t *pool)
+{
+    return APR_SUCCESS;
+}
+
+/* For Basic authentication we expect all authn info to be the same for all
+   connections in the context to the same server (same realm, username,
+   password). Therefore we can keep the header value in the per-server store
+   context instead of per connection.
+   TODO: we currently don't cache this info per realm, so each time a request
+   'switches realms', we have to ask the application for new credentials. */
+apr_status_t
+serf__init_basic_connection(const serf__authn_scheme_t *scheme,
+                            int code,
+                            serf_connection_t *conn,
+                            apr_pool_t *pool)
+{
+    serf_context_t *ctx = conn->ctx;
+    serf__authn_info_t *authn_info;
+
+    if (code == 401) {
+        authn_info = serf__get_authn_info_for_server(conn);
+    } else {
+        authn_info = &ctx->proxy_authn_info;
+    }
+
+    if (!authn_info->baton) {
+        authn_info->baton = apr_pcalloc(pool, sizeof(basic_authn_info_t));
+    }
+
+    return APR_SUCCESS;
+}
+
+apr_status_t
+serf__setup_request_basic_auth(peer_t peer,
+                               int code,
+                               serf_connection_t *conn,
+                               serf_request_t *request,
+                               const char *method,
+                               const char *uri,
+                               serf_bucket_t *hdrs_bkt)
+{
+    serf_context_t *ctx = conn->ctx;
+    serf__authn_info_t *authn_info;
+    basic_authn_info_t *basic_info;
+
+    if (peer == HOST) {
+        authn_info = serf__get_authn_info_for_server(conn);
+    } else {
+        authn_info = &ctx->proxy_authn_info;
+    }
+    basic_info = authn_info->baton;
+
+    if (basic_info && basic_info->header && basic_info->value) {
+        serf_bucket_headers_setn(hdrs_bkt, basic_info->header,
+                                 basic_info->value);
+        return APR_SUCCESS;
+    }
+
+    return SERF_ERROR_AUTHN_FAILED;
+}

Deleted: vendor/serf/1.3.9/auth/auth_digest.c
===================================================================
--- vendor/serf/dist/auth/auth_digest.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/auth/auth_digest.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,557 +0,0 @@
-/* Copyright 2009 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.
- */
-
-/*** Digest authentication ***/
-
-#include <serf.h>
-#include <serf_private.h>
-#include <auth/auth.h>
-
-#include <apr.h>
-#include <apr_base64.h>
-#include <apr_strings.h>
-#include <apr_uuid.h>
-#include <apr_md5.h>
-
-/** Digest authentication, implements RFC 2617. **/
-
-/* TODO: add support for the domain attribute. This defines the protection
-   space, so that serf can decide per URI if it should reuse the cached
-   credentials for the server, or not. */
-
-/* Stores the context information related to Digest authentication.
-   This information is stored in the per server cache in the serf context. */
-typedef struct digest_authn_info_t {
-    /* nonce-count for digest authentication */
-    unsigned int digest_nc;
-
-    const char *header;
-
-    const char *ha1;
-
-    const char *realm;
-    const char *cnonce;
-    const char *nonce;
-    const char *opaque;
-    const char *algorithm;
-    const char *qop;
-    const char *username;
-
-    apr_pool_t *pool;
-} digest_authn_info_t;
-
-static char
-int_to_hex(int v)
-{
-    return (v < 10) ? '0' + v : 'a' + (v - 10);
-}
-
-/**
- * Convert a string if ASCII characters HASHVAL to its hexadecimal
- * representation.
- *
- * The returned string will be allocated in the POOL and be null-terminated.
- */
-static const char *
-hex_encode(const unsigned char *hashval,
-           apr_pool_t *pool)
-{
-    int i;
-    char *hexval = apr_palloc(pool, (APR_MD5_DIGESTSIZE * 2) + 1);
-    for (i = 0; i < APR_MD5_DIGESTSIZE; i++) {
-        hexval[2 * i] = int_to_hex((hashval[i] >> 4) & 0xf);
-        hexval[2 * i + 1] = int_to_hex(hashval[i] & 0xf);
-    }
-    hexval[APR_MD5_DIGESTSIZE * 2] = '\0';
-    return hexval;
-}
-
-/**
- * Returns a 36-byte long string of random characters.
- * UUIDs are formatted as: 00112233-4455-6677-8899-AABBCCDDEEFF.
- *
- * The returned string will be allocated in the POOL and be null-terminated.
- */
-static const char *
-random_cnonce(apr_pool_t *pool)
-{
-    apr_uuid_t uuid;
-    char *buf = apr_palloc(pool, APR_UUID_FORMATTED_LENGTH + 1);
-
-    apr_uuid_get(&uuid);
-    apr_uuid_format(buf, &uuid);
-
-    return hex_encode((unsigned char*)buf, pool);
-}
-
-static apr_status_t
-build_digest_ha1(const char **out_ha1,
-                 const char *username,
-                 const char *password,
-                 const char *realm_name,
-                 apr_pool_t *pool)
-{
-    const char *tmp;
-    unsigned char ha1[APR_MD5_DIGESTSIZE];
-    apr_status_t status;
-
-    /* calculate ha1:
-       MD5 hash of the combined user name, authentication realm and password */
-    tmp = apr_psprintf(pool, "%s:%s:%s",
-                       username,
-                       realm_name,
-                       password);
-    status = apr_md5(ha1, tmp, strlen(tmp));
-    if (status)
-        return status;
-
-    *out_ha1 = hex_encode(ha1, pool);
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t
-build_digest_ha2(const char **out_ha2,
-                 const char *uri,
-                 const char *method,
-                 const char *qop,
-                 apr_pool_t *pool)
-{
-    if (!qop || strcmp(qop, "auth") == 0) {
-        const char *tmp;
-        unsigned char ha2[APR_MD5_DIGESTSIZE];
-        apr_status_t status;
-
-        /* calculate ha2:
-           MD5 hash of the combined method and URI */
-        tmp = apr_psprintf(pool, "%s:%s",
-                           method,
-                           uri);
-        status = apr_md5(ha2, tmp, strlen(tmp));
-        if (status)
-            return status;
-
-        *out_ha2 = hex_encode(ha2, pool);
-
-        return APR_SUCCESS;
-    } else {
-        /* TODO: auth-int isn't supported! */
-        return APR_ENOTIMPL;
-    }
-}
-
-static apr_status_t
-build_auth_header(const char **out_header,
-                  digest_authn_info_t *digest_info,
-                  const char *path,
-                  const char *method,
-                  apr_pool_t *pool)
-{
-    char *hdr;
-    const char *ha2;
-    const char *response;
-    unsigned char response_hdr[APR_MD5_DIGESTSIZE];
-    const char *response_hdr_hex;
-    apr_status_t status;
-
-    status = build_digest_ha2(&ha2, path, method, digest_info->qop, pool);
-    if (status)
-        return status;
-
-    hdr = apr_psprintf(pool,
-                       "Digest realm=\"%s\","
-                       " username=\"%s\","
-                       " nonce=\"%s\","
-                       " uri=\"%s\"",
-                       digest_info->realm, digest_info->username,
-                       digest_info->nonce,
-                       path);
-
-    if (digest_info->qop) {
-        if (! digest_info->cnonce)
-            digest_info->cnonce = random_cnonce(digest_info->pool);
-
-        hdr = apr_psprintf(pool, "%s, nc=%08x, cnonce=\"%s\", qop=\"%s\"",
-                           hdr,
-                           digest_info->digest_nc,
-                           digest_info->cnonce,
-                           digest_info->qop);
-
-        /* Build the response header:
-           MD5 hash of the combined HA1 result, server nonce (nonce),
-           request counter (nc), client nonce (cnonce),
-           quality of protection code (qop) and HA2 result. */
-        response = apr_psprintf(pool, "%s:%s:%08x:%s:%s:%s",
-                                digest_info->ha1, digest_info->nonce,
-                                digest_info->digest_nc,
-                                digest_info->cnonce, digest_info->qop, ha2);
-    } else {
-        /* Build the response header:
-           MD5 hash of the combined HA1 result, server nonce (nonce)
-           and HA2 result. */
-        response = apr_psprintf(pool, "%s:%s:%s",
-                                digest_info->ha1, digest_info->nonce, ha2);
-    }
-
-    status = apr_md5(response_hdr, response, strlen(response));
-    if (status)
-        return status;
-
-    response_hdr_hex = hex_encode(response_hdr, pool);
-
-    hdr = apr_psprintf(pool, "%s, response=\"%s\"", hdr, response_hdr_hex);
-
-    if (digest_info->opaque) {
-        hdr = apr_psprintf(pool, "%s, opaque=\"%s\"", hdr,
-                           digest_info->opaque);
-    }
-    if (digest_info->algorithm) {
-        hdr = apr_psprintf(pool, "%s, algorithm=\"%s\"", hdr,
-                           digest_info->algorithm);
-    }
-
-    *out_header = hdr;
-
-    return APR_SUCCESS;
-}
-
-apr_status_t
-serf__handle_digest_auth(int code,
-                         serf_request_t *request,
-                         serf_bucket_t *response,
-                         const char *auth_hdr,
-                         const char *auth_attr,
-                         void *baton,
-                         apr_pool_t *pool)
-{
-    char *attrs;
-    char *nextkv;
-    const char *realm, *realm_name = NULL;
-    const char *nonce = NULL;
-    const char *algorithm = NULL;
-    const char *qop = NULL;
-    const char *opaque = NULL;
-    const char *key;
-    serf_connection_t *conn = request->conn;
-    serf_context_t *ctx = conn->ctx;
-    serf__authn_info_t *authn_info;
-    digest_authn_info_t *digest_info;
-    apr_status_t status;
-    apr_pool_t *cred_pool;
-    char *username, *password;
-
-    /* Can't do Digest authentication if there's no callback to get
-       username & password. */
-    if (!ctx->cred_cb) {
-        return SERF_ERROR_AUTHN_FAILED;
-    }
-
-    if (code == 401) {
-        authn_info = serf__get_authn_info_for_server(conn);
-    } else {
-        authn_info = &ctx->proxy_authn_info;
-    }
-    digest_info = authn_info->baton;
-
-    /* Need a copy cuz we're going to write NUL characters into the string.  */
-    attrs = apr_pstrdup(pool, auth_attr);
-
-    /* We're expecting a list of key=value pairs, separated by a comma.
-       Ex. realm="SVN Digest",
-       nonce="f+zTl/leBAA=e371bd3070adfb47b21f5fc64ad8cc21adc371a5",
-       algorithm=MD5, qop="auth" */
-    for ( ; (key = apr_strtok(attrs, ",", &nextkv)) != NULL; attrs = NULL) {
-        char *val;
-
-        val = strchr(key, '=');
-        if (val == NULL)
-            continue;
-        *val++ = '\0';
-
-        /* skip leading spaces */
-        while (*key && *key == ' ')
-            key++;
-
-        /* If the value is quoted, then remove the quotes.  */
-        if (*val == '"') {
-            apr_size_t last = strlen(val) - 1;
-
-            if (val[last] == '"') {
-                val[last] = '\0';
-                val++;
-            }
-        }
-
-        if (strcmp(key, "realm") == 0)
-            realm_name = val;
-        else if (strcmp(key, "nonce") == 0)
-            nonce = val;
-        else if (strcmp(key, "algorithm") == 0)
-            algorithm = val;
-        else if (strcmp(key, "qop") == 0)
-            qop = val;
-        else if (strcmp(key, "opaque") == 0)
-            opaque = val;
-
-        /* Ignore all unsupported attributes. */
-    }
-
-    if (!realm_name) {
-        return SERF_ERROR_AUTHN_MISSING_ATTRIBUTE;
-    }
-
-    realm = serf__construct_realm(code == 401 ? HOST : PROXY,
-                                  conn, realm_name,
-                                  pool);
-
-    /* Ask the application for credentials */
-    apr_pool_create(&cred_pool, pool);
-    status = serf__provide_credentials(ctx,
-                                       &username, &password,
-                                       request, baton,
-                                       code, authn_info->scheme->name,
-                                       realm, cred_pool);
-    if (status) {
-        apr_pool_destroy(cred_pool);
-        return status;
-    }
-
-    digest_info->header = (code == 401) ? "Authorization" :
-                                          "Proxy-Authorization";
-
-    /* Store the digest authentication parameters in the context cached for
-       this server in the serf context, so we can use it to create the
-       Authorization header when setting up requests on the same or different
-       connections (e.g. in case of KeepAlive off on the server).
-       TODO: we currently don't cache this info per realm, so each time a request
-       'switches realms', we have to ask the application for new credentials. */
-    digest_info->pool = conn->pool;
-    digest_info->qop = apr_pstrdup(digest_info->pool, qop);
-    digest_info->nonce = apr_pstrdup(digest_info->pool, nonce);
-    digest_info->cnonce = NULL;
-    digest_info->opaque = apr_pstrdup(digest_info->pool, opaque);
-    digest_info->algorithm = apr_pstrdup(digest_info->pool, algorithm);
-    digest_info->realm = apr_pstrdup(digest_info->pool, realm_name);
-    digest_info->username = apr_pstrdup(digest_info->pool, username);
-    digest_info->digest_nc++;
-
-    status = build_digest_ha1(&digest_info->ha1, username, password,
-                              digest_info->realm, digest_info->pool);
-
-    apr_pool_destroy(cred_pool);
-
-    /* If the handshake is finished tell serf it can send as much requests as it
-       likes. */
-    serf_connection_set_max_outstanding_requests(conn, 0);
-
-    return status;
-}
-
-apr_status_t
-serf__init_digest(int code,
-                  serf_context_t *ctx,
-                  apr_pool_t *pool)
-{
-    return APR_SUCCESS;
-}
-
-apr_status_t
-serf__init_digest_connection(const serf__authn_scheme_t *scheme,
-                             int code,
-                             serf_connection_t *conn,
-                             apr_pool_t *pool)
-{
-    serf_context_t *ctx = conn->ctx;
-    serf__authn_info_t *authn_info;
-
-    if (code == 401) {
-        authn_info = serf__get_authn_info_for_server(conn);
-    } else {
-        authn_info = &ctx->proxy_authn_info;
-    }
-
-    if (!authn_info->baton) {
-        authn_info->baton = apr_pcalloc(pool, sizeof(digest_authn_info_t));
-    }
-
-    /* Make serf send the initial requests one by one */
-    serf_connection_set_max_outstanding_requests(conn, 1);
-
-    return APR_SUCCESS;
-}
-
-apr_status_t
-serf__setup_request_digest_auth(peer_t peer,
-                                int code,
-                                serf_connection_t *conn,
-                                serf_request_t *request,
-                                const char *method,
-                                const char *uri,
-                                serf_bucket_t *hdrs_bkt)
-{
-    serf_context_t *ctx = conn->ctx;
-    serf__authn_info_t *authn_info;
-    digest_authn_info_t *digest_info;
-    apr_status_t status;
-
-    if (peer == HOST) {
-        authn_info = serf__get_authn_info_for_server(conn);
-    } else {
-        authn_info = &ctx->proxy_authn_info;
-    }
-    digest_info = authn_info->baton;
-
-    if (digest_info && digest_info->realm) {
-        const char *value;
-        const char *path;
-
-        /* TODO: per request pool? */
-
-        /* for request 'CONNECT serf.googlecode.com:443', the uri also should be
-           serf.googlecode.com:443. apr_uri_parse can't handle this, so special
-           case. */
-        if (strcmp(method, "CONNECT") == 0)
-            path = uri;
-        else {
-            apr_uri_t parsed_uri;
-
-            /* Extract path from uri. */
-            status = apr_uri_parse(conn->pool, uri, &parsed_uri);
-            if (status)
-                return status;
-
-            path = parsed_uri.path;
-        }
-
-        /* Build a new Authorization header. */
-        digest_info->header = (peer == HOST) ? "Authorization" :
-            "Proxy-Authorization";
-        status = build_auth_header(&value, digest_info, path, method,
-                                   conn->pool);
-        if (status)
-            return status;
-
-        serf_bucket_headers_setn(hdrs_bkt, digest_info->header,
-                                 value);
-        digest_info->digest_nc++;
-
-        /* Store the uri of this request on the serf_request_t object, to make
-           it available when validating the Authentication-Info header of the
-           matching response. */
-        request->auth_baton = (void *)path;
-    }
-
-    return APR_SUCCESS;
-}
-
-apr_status_t
-serf__validate_response_digest_auth(const serf__authn_scheme_t *scheme,
-                                    peer_t peer,
-                                    int code,
-                                    serf_connection_t *conn,
-                                    serf_request_t *request,
-                                    serf_bucket_t *response,
-                                    apr_pool_t *pool)
-{
-    const char *key;
-    char *auth_attr;
-    char *nextkv;
-    const char *rspauth = NULL;
-    const char *qop = NULL;
-    const char *nc_str = NULL;
-    serf_bucket_t *hdrs;
-    serf_context_t *ctx = conn->ctx;
-    apr_status_t status;
-
-    hdrs = serf_bucket_response_get_headers(response);
-
-    /* Need a copy cuz we're going to write NUL characters into the string.  */
-    if (peer == HOST)
-        auth_attr = apr_pstrdup(pool,
-            serf_bucket_headers_get(hdrs, "Authentication-Info"));
-    else
-        auth_attr = apr_pstrdup(pool,
-            serf_bucket_headers_get(hdrs, "Proxy-Authentication-Info"));
-
-    /* If there's no Authentication-Info header there's nothing to validate. */
-    if (! auth_attr)
-        return APR_SUCCESS;
-
-    /* We're expecting a list of key=value pairs, separated by a comma.
-       Ex. rspauth="8a4b8451084b082be6b105e2b7975087",
-       cnonce="346531653132652d303033392d3435", nc=00000007,
-       qop=auth */
-    for ( ; (key = apr_strtok(auth_attr, ",", &nextkv)) != NULL; auth_attr = NULL) {
-        char *val;
-
-        val = strchr(key, '=');
-        if (val == NULL)
-            continue;
-        *val++ = '\0';
-
-        /* skip leading spaces */
-        while (*key && *key == ' ')
-            key++;
-
-        /* If the value is quoted, then remove the quotes.  */
-        if (*val == '"') {
-            apr_size_t last = strlen(val) - 1;
-
-            if (val[last] == '"') {
-                val[last] = '\0';
-                val++;
-            }
-        }
-
-        if (strcmp(key, "rspauth") == 0)
-            rspauth = val;
-        else if (strcmp(key, "qop") == 0)
-            qop = val;
-        else if (strcmp(key, "nc") == 0)
-            nc_str = val;
-    }
-
-    if (rspauth) {
-        const char *ha2, *tmp, *resp_hdr_hex;
-        unsigned char resp_hdr[APR_MD5_DIGESTSIZE];
-        const char *req_uri = request->auth_baton;
-        serf__authn_info_t *authn_info;
-        digest_authn_info_t *digest_info;
-
-        if (peer == HOST) {
-            authn_info = serf__get_authn_info_for_server(conn);
-        } else {
-            authn_info = &ctx->proxy_authn_info;
-        }
-        digest_info = authn_info->baton;
-
-        status = build_digest_ha2(&ha2, req_uri, "", qop, pool);
-        if (status)
-            return status;
-
-        tmp = apr_psprintf(pool, "%s:%s:%s:%s:%s:%s",
-                           digest_info->ha1, digest_info->nonce, nc_str,
-                           digest_info->cnonce, digest_info->qop, ha2);
-        apr_md5(resp_hdr, tmp, strlen(tmp));
-        resp_hdr_hex =  hex_encode(resp_hdr, pool);
-
-        /* Incorrect response-digest in Authentication-Info header. */
-        if (strcmp(rspauth, resp_hdr_hex) != 0) {
-            return SERF_ERROR_AUTHN_FAILED;
-        }
-    }
-
-    return APR_SUCCESS;
-}

Copied: vendor/serf/1.3.9/auth/auth_digest.c (from rev 9259, vendor/serf/dist/auth/auth_digest.c)
===================================================================
--- vendor/serf/1.3.9/auth/auth_digest.c	                        (rev 0)
+++ vendor/serf/1.3.9/auth/auth_digest.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,562 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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.
+ * ====================================================================
+ */
+
+/*** Digest authentication ***/
+
+#include <serf.h>
+#include <serf_private.h>
+#include <auth/auth.h>
+
+#include <apr.h>
+#include <apr_base64.h>
+#include <apr_strings.h>
+#include <apr_uuid.h>
+#include <apr_md5.h>
+
+/** Digest authentication, implements RFC 2617. **/
+
+/* TODO: add support for the domain attribute. This defines the protection
+   space, so that serf can decide per URI if it should reuse the cached
+   credentials for the server, or not. */
+
+/* Stores the context information related to Digest authentication.
+   This information is stored in the per server cache in the serf context. */
+typedef struct digest_authn_info_t {
+    /* nonce-count for digest authentication */
+    unsigned int digest_nc;
+
+    const char *header;
+
+    const char *ha1;
+
+    const char *realm;
+    const char *cnonce;
+    const char *nonce;
+    const char *opaque;
+    const char *algorithm;
+    const char *qop;
+    const char *username;
+
+    apr_pool_t *pool;
+} digest_authn_info_t;
+
+static char
+int_to_hex(int v)
+{
+    return (v < 10) ? '0' + v : 'a' + (v - 10);
+}
+
+/**
+ * Convert a string if ASCII characters HASHVAL to its hexadecimal
+ * representation.
+ *
+ * The returned string will be allocated in the POOL and be null-terminated.
+ */
+static const char *
+hex_encode(const unsigned char *hashval,
+           apr_pool_t *pool)
+{
+    int i;
+    char *hexval = apr_palloc(pool, (APR_MD5_DIGESTSIZE * 2) + 1);
+    for (i = 0; i < APR_MD5_DIGESTSIZE; i++) {
+        hexval[2 * i] = int_to_hex((hashval[i] >> 4) & 0xf);
+        hexval[2 * i + 1] = int_to_hex(hashval[i] & 0xf);
+    }
+    hexval[APR_MD5_DIGESTSIZE * 2] = '\0';
+    return hexval;
+}
+
+/**
+ * Returns a 36-byte long string of random characters.
+ * UUIDs are formatted as: 00112233-4455-6677-8899-AABBCCDDEEFF.
+ *
+ * The returned string will be allocated in the POOL and be null-terminated.
+ */
+static const char *
+random_cnonce(apr_pool_t *pool)
+{
+    apr_uuid_t uuid;
+    char *buf = apr_palloc(pool, APR_UUID_FORMATTED_LENGTH + 1);
+
+    apr_uuid_get(&uuid);
+    apr_uuid_format(buf, &uuid);
+
+    return hex_encode((unsigned char*)buf, pool);
+}
+
+static apr_status_t
+build_digest_ha1(const char **out_ha1,
+                 const char *username,
+                 const char *password,
+                 const char *realm_name,
+                 apr_pool_t *pool)
+{
+    const char *tmp;
+    unsigned char ha1[APR_MD5_DIGESTSIZE];
+    apr_status_t status;
+
+    /* calculate ha1:
+       MD5 hash of the combined user name, authentication realm and password */
+    tmp = apr_psprintf(pool, "%s:%s:%s",
+                       username,
+                       realm_name,
+                       password);
+    status = apr_md5(ha1, tmp, strlen(tmp));
+    if (status)
+        return status;
+
+    *out_ha1 = hex_encode(ha1, pool);
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t
+build_digest_ha2(const char **out_ha2,
+                 const char *uri,
+                 const char *method,
+                 const char *qop,
+                 apr_pool_t *pool)
+{
+    if (!qop || strcmp(qop, "auth") == 0) {
+        const char *tmp;
+        unsigned char ha2[APR_MD5_DIGESTSIZE];
+        apr_status_t status;
+
+        /* calculate ha2:
+           MD5 hash of the combined method and URI */
+        tmp = apr_psprintf(pool, "%s:%s",
+                           method,
+                           uri);
+        status = apr_md5(ha2, tmp, strlen(tmp));
+        if (status)
+            return status;
+
+        *out_ha2 = hex_encode(ha2, pool);
+
+        return APR_SUCCESS;
+    } else {
+        /* TODO: auth-int isn't supported! */
+        return APR_ENOTIMPL;
+    }
+}
+
+static apr_status_t
+build_auth_header(const char **out_header,
+                  digest_authn_info_t *digest_info,
+                  const char *path,
+                  const char *method,
+                  apr_pool_t *pool)
+{
+    char *hdr;
+    const char *ha2;
+    const char *response;
+    unsigned char response_hdr[APR_MD5_DIGESTSIZE];
+    const char *response_hdr_hex;
+    apr_status_t status;
+
+    status = build_digest_ha2(&ha2, path, method, digest_info->qop, pool);
+    if (status)
+        return status;
+
+    hdr = apr_psprintf(pool,
+                       "Digest realm=\"%s\","
+                       " username=\"%s\","
+                       " nonce=\"%s\","
+                       " uri=\"%s\"",
+                       digest_info->realm, digest_info->username,
+                       digest_info->nonce,
+                       path);
+
+    if (digest_info->qop) {
+        if (! digest_info->cnonce)
+            digest_info->cnonce = random_cnonce(digest_info->pool);
+
+        hdr = apr_psprintf(pool, "%s, nc=%08x, cnonce=\"%s\", qop=\"%s\"",
+                           hdr,
+                           digest_info->digest_nc,
+                           digest_info->cnonce,
+                           digest_info->qop);
+
+        /* Build the response header:
+           MD5 hash of the combined HA1 result, server nonce (nonce),
+           request counter (nc), client nonce (cnonce),
+           quality of protection code (qop) and HA2 result. */
+        response = apr_psprintf(pool, "%s:%s:%08x:%s:%s:%s",
+                                digest_info->ha1, digest_info->nonce,
+                                digest_info->digest_nc,
+                                digest_info->cnonce, digest_info->qop, ha2);
+    } else {
+        /* Build the response header:
+           MD5 hash of the combined HA1 result, server nonce (nonce)
+           and HA2 result. */
+        response = apr_psprintf(pool, "%s:%s:%s",
+                                digest_info->ha1, digest_info->nonce, ha2);
+    }
+
+    status = apr_md5(response_hdr, response, strlen(response));
+    if (status)
+        return status;
+
+    response_hdr_hex = hex_encode(response_hdr, pool);
+
+    hdr = apr_psprintf(pool, "%s, response=\"%s\"", hdr, response_hdr_hex);
+
+    if (digest_info->opaque) {
+        hdr = apr_psprintf(pool, "%s, opaque=\"%s\"", hdr,
+                           digest_info->opaque);
+    }
+    if (digest_info->algorithm) {
+        hdr = apr_psprintf(pool, "%s, algorithm=\"%s\"", hdr,
+                           digest_info->algorithm);
+    }
+
+    *out_header = hdr;
+
+    return APR_SUCCESS;
+}
+
+apr_status_t
+serf__handle_digest_auth(int code,
+                         serf_request_t *request,
+                         serf_bucket_t *response,
+                         const char *auth_hdr,
+                         const char *auth_attr,
+                         void *baton,
+                         apr_pool_t *pool)
+{
+    char *attrs;
+    char *nextkv;
+    const char *realm, *realm_name = NULL;
+    const char *nonce = NULL;
+    const char *algorithm = NULL;
+    const char *qop = NULL;
+    const char *opaque = NULL;
+    const char *key;
+    serf_connection_t *conn = request->conn;
+    serf_context_t *ctx = conn->ctx;
+    serf__authn_info_t *authn_info;
+    digest_authn_info_t *digest_info;
+    apr_status_t status;
+    apr_pool_t *cred_pool;
+    char *username, *password;
+
+    /* Can't do Digest authentication if there's no callback to get
+       username & password. */
+    if (!ctx->cred_cb) {
+        return SERF_ERROR_AUTHN_FAILED;
+    }
+
+    if (code == 401) {
+        authn_info = serf__get_authn_info_for_server(conn);
+    } else {
+        authn_info = &ctx->proxy_authn_info;
+    }
+    digest_info = authn_info->baton;
+
+    /* Need a copy cuz we're going to write NUL characters into the string.  */
+    attrs = apr_pstrdup(pool, auth_attr);
+
+    /* We're expecting a list of key=value pairs, separated by a comma.
+       Ex. realm="SVN Digest",
+       nonce="f+zTl/leBAA=e371bd3070adfb47b21f5fc64ad8cc21adc371a5",
+       algorithm=MD5, qop="auth" */
+    for ( ; (key = apr_strtok(attrs, ",", &nextkv)) != NULL; attrs = NULL) {
+        char *val;
+
+        val = strchr(key, '=');
+        if (val == NULL)
+            continue;
+        *val++ = '\0';
+
+        /* skip leading spaces */
+        while (*key && *key == ' ')
+            key++;
+
+        /* If the value is quoted, then remove the quotes.  */
+        if (*val == '"') {
+            apr_size_t last = strlen(val) - 1;
+
+            if (val[last] == '"') {
+                val[last] = '\0';
+                val++;
+            }
+        }
+
+        if (strcmp(key, "realm") == 0)
+            realm_name = val;
+        else if (strcmp(key, "nonce") == 0)
+            nonce = val;
+        else if (strcmp(key, "algorithm") == 0)
+            algorithm = val;
+        else if (strcmp(key, "qop") == 0)
+            qop = val;
+        else if (strcmp(key, "opaque") == 0)
+            opaque = val;
+
+        /* Ignore all unsupported attributes. */
+    }
+
+    if (!realm_name) {
+        return SERF_ERROR_AUTHN_MISSING_ATTRIBUTE;
+    }
+
+    realm = serf__construct_realm(code == 401 ? HOST : PROXY,
+                                  conn, realm_name,
+                                  pool);
+
+    /* Ask the application for credentials */
+    apr_pool_create(&cred_pool, pool);
+    status = serf__provide_credentials(ctx,
+                                       &username, &password,
+                                       request, baton,
+                                       code, authn_info->scheme->name,
+                                       realm, cred_pool);
+    if (status) {
+        apr_pool_destroy(cred_pool);
+        return status;
+    }
+
+    digest_info->header = (code == 401) ? "Authorization" :
+                                          "Proxy-Authorization";
+
+    /* Store the digest authentication parameters in the context cached for
+       this server in the serf context, so we can use it to create the
+       Authorization header when setting up requests on the same or different
+       connections (e.g. in case of KeepAlive off on the server).
+       TODO: we currently don't cache this info per realm, so each time a request
+       'switches realms', we have to ask the application for new credentials. */
+    digest_info->pool = conn->pool;
+    digest_info->qop = apr_pstrdup(digest_info->pool, qop);
+    digest_info->nonce = apr_pstrdup(digest_info->pool, nonce);
+    digest_info->cnonce = NULL;
+    digest_info->opaque = apr_pstrdup(digest_info->pool, opaque);
+    digest_info->algorithm = apr_pstrdup(digest_info->pool, algorithm);
+    digest_info->realm = apr_pstrdup(digest_info->pool, realm_name);
+    digest_info->username = apr_pstrdup(digest_info->pool, username);
+    digest_info->digest_nc++;
+
+    status = build_digest_ha1(&digest_info->ha1, username, password,
+                              digest_info->realm, digest_info->pool);
+
+    apr_pool_destroy(cred_pool);
+
+    /* If the handshake is finished tell serf it can send as much requests as it
+       likes. */
+    serf_connection_set_max_outstanding_requests(conn, 0);
+
+    return status;
+}
+
+apr_status_t
+serf__init_digest(int code,
+                  serf_context_t *ctx,
+                  apr_pool_t *pool)
+{
+    return APR_SUCCESS;
+}
+
+apr_status_t
+serf__init_digest_connection(const serf__authn_scheme_t *scheme,
+                             int code,
+                             serf_connection_t *conn,
+                             apr_pool_t *pool)
+{
+    serf_context_t *ctx = conn->ctx;
+    serf__authn_info_t *authn_info;
+
+    if (code == 401) {
+        authn_info = serf__get_authn_info_for_server(conn);
+    } else {
+        authn_info = &ctx->proxy_authn_info;
+    }
+
+    if (!authn_info->baton) {
+        authn_info->baton = apr_pcalloc(pool, sizeof(digest_authn_info_t));
+    }
+
+    /* Make serf send the initial requests one by one */
+    serf_connection_set_max_outstanding_requests(conn, 1);
+
+    return APR_SUCCESS;
+}
+
+apr_status_t
+serf__setup_request_digest_auth(peer_t peer,
+                                int code,
+                                serf_connection_t *conn,
+                                serf_request_t *request,
+                                const char *method,
+                                const char *uri,
+                                serf_bucket_t *hdrs_bkt)
+{
+    serf_context_t *ctx = conn->ctx;
+    serf__authn_info_t *authn_info;
+    digest_authn_info_t *digest_info;
+    apr_status_t status;
+
+    if (peer == HOST) {
+        authn_info = serf__get_authn_info_for_server(conn);
+    } else {
+        authn_info = &ctx->proxy_authn_info;
+    }
+    digest_info = authn_info->baton;
+
+    if (digest_info && digest_info->realm) {
+        const char *value;
+        const char *path;
+
+        /* TODO: per request pool? */
+
+        /* for request 'CONNECT serf.googlecode.com:443', the uri also should be
+           serf.googlecode.com:443. apr_uri_parse can't handle this, so special
+           case. */
+        if (strcmp(method, "CONNECT") == 0)
+            path = uri;
+        else {
+            apr_uri_t parsed_uri;
+
+            /* Extract path from uri. */
+            status = apr_uri_parse(conn->pool, uri, &parsed_uri);
+            if (status)
+                return status;
+
+            path = parsed_uri.path;
+        }
+
+        /* Build a new Authorization header. */
+        digest_info->header = (peer == HOST) ? "Authorization" :
+            "Proxy-Authorization";
+        status = build_auth_header(&value, digest_info, path, method,
+                                   conn->pool);
+        if (status)
+            return status;
+
+        serf_bucket_headers_setn(hdrs_bkt, digest_info->header,
+                                 value);
+        digest_info->digest_nc++;
+
+        /* Store the uri of this request on the serf_request_t object, to make
+           it available when validating the Authentication-Info header of the
+           matching response. */
+        request->auth_baton = (void *)path;
+    }
+
+    return APR_SUCCESS;
+}
+
+apr_status_t
+serf__validate_response_digest_auth(const serf__authn_scheme_t *scheme,
+                                    peer_t peer,
+                                    int code,
+                                    serf_connection_t *conn,
+                                    serf_request_t *request,
+                                    serf_bucket_t *response,
+                                    apr_pool_t *pool)
+{
+    const char *key;
+    char *auth_attr;
+    char *nextkv;
+    const char *rspauth = NULL;
+    const char *qop = NULL;
+    const char *nc_str = NULL;
+    serf_bucket_t *hdrs;
+    serf_context_t *ctx = conn->ctx;
+    apr_status_t status;
+
+    hdrs = serf_bucket_response_get_headers(response);
+
+    /* Need a copy cuz we're going to write NUL characters into the string.  */
+    if (peer == HOST)
+        auth_attr = apr_pstrdup(pool,
+            serf_bucket_headers_get(hdrs, "Authentication-Info"));
+    else
+        auth_attr = apr_pstrdup(pool,
+            serf_bucket_headers_get(hdrs, "Proxy-Authentication-Info"));
+
+    /* If there's no Authentication-Info header there's nothing to validate. */
+    if (! auth_attr)
+        return APR_SUCCESS;
+
+    /* We're expecting a list of key=value pairs, separated by a comma.
+       Ex. rspauth="8a4b8451084b082be6b105e2b7975087",
+       cnonce="346531653132652d303033392d3435", nc=00000007,
+       qop=auth */
+    for ( ; (key = apr_strtok(auth_attr, ",", &nextkv)) != NULL; auth_attr = NULL) {
+        char *val;
+
+        val = strchr(key, '=');
+        if (val == NULL)
+            continue;
+        *val++ = '\0';
+
+        /* skip leading spaces */
+        while (*key && *key == ' ')
+            key++;
+
+        /* If the value is quoted, then remove the quotes.  */
+        if (*val == '"') {
+            apr_size_t last = strlen(val) - 1;
+
+            if (val[last] == '"') {
+                val[last] = '\0';
+                val++;
+            }
+        }
+
+        if (strcmp(key, "rspauth") == 0)
+            rspauth = val;
+        else if (strcmp(key, "qop") == 0)
+            qop = val;
+        else if (strcmp(key, "nc") == 0)
+            nc_str = val;
+    }
+
+    if (rspauth) {
+        const char *ha2, *tmp, *resp_hdr_hex;
+        unsigned char resp_hdr[APR_MD5_DIGESTSIZE];
+        const char *req_uri = request->auth_baton;
+        serf__authn_info_t *authn_info;
+        digest_authn_info_t *digest_info;
+
+        if (peer == HOST) {
+            authn_info = serf__get_authn_info_for_server(conn);
+        } else {
+            authn_info = &ctx->proxy_authn_info;
+        }
+        digest_info = authn_info->baton;
+
+        status = build_digest_ha2(&ha2, req_uri, "", qop, pool);
+        if (status)
+            return status;
+
+        tmp = apr_psprintf(pool, "%s:%s:%s:%s:%s:%s",
+                           digest_info->ha1, digest_info->nonce, nc_str,
+                           digest_info->cnonce, digest_info->qop, ha2);
+        apr_md5(resp_hdr, tmp, strlen(tmp));
+        resp_hdr_hex =  hex_encode(resp_hdr, pool);
+
+        /* Incorrect response-digest in Authentication-Info header. */
+        if (strcmp(rspauth, resp_hdr_hex) != 0) {
+            return SERF_ERROR_AUTHN_FAILED;
+        }
+    }
+
+    return APR_SUCCESS;
+}

Deleted: vendor/serf/1.3.9/auth/auth_spnego.c
===================================================================
--- vendor/serf/dist/auth/auth_spnego.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/auth/auth_spnego.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,656 +0,0 @@
-/* Copyright 2009 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 "auth_spnego.h"
-
-#ifdef SERF_HAVE_SPNEGO
-
-/** These functions implement SPNEGO-based Kerberos and NTLM authentication,
- *  using either GSS-API (RFC 2743) or SSPI on Windows.
- *  The HTTP message exchange is documented in RFC 4559.
- **/
-
-#include <serf.h>
-#include <serf_private.h>
-#include <auth/auth.h>
-
-#include <apr.h>
-#include <apr_base64.h>
-#include <apr_strings.h>
-
-/** TODO:
- ** - send session key directly on new connections where we already know
- **   the server requires Kerberos authn.
- ** - Add a way for serf to give detailed error information back to the
- **   application.
- **/
-
-/* Authentication over HTTP using Kerberos
- *
- * Kerberos involves three servers:
- * - Authentication Server (AS): verifies users during login
- * - Ticket-Granting Server (TGS): issues proof of identity tickets
- * - HTTP server (S)
- *
- * Steps:
- * 0. User logs in to the AS and receives a TGS ticket. On workstations
- * where the login program doesn't support Kerberos, the user can use
- * 'kinit'.
- *
- * 1. C  --> S:    GET
- *
- *    C <--  S:    401 Authentication Required
- *                 WWW-Authenticate: Negotiate
- *
- * -> app contacts the TGS to request a session key for the HTTP service
- *    @ target host. The returned session key is encrypted with the HTTP
- *    service's secret key, so we can safely send it to the server.
- *
- * 2. C  --> S:    GET
- *                 Authorization: Negotiate <Base64 encoded session key>
- *                 gss_api_ctx->state = gss_api_auth_in_progress;
- *
- *    C <--  S:    200 OK
- *                 WWW-Authenticate: Negotiate <Base64 encoded server
- *                                              authentication data>
- *
- * -> The server returned an (optional) key to proof itself to us. We check this
- *    key with the TGS again. If it checks out, we can return the response
- *    body to the application.
- *
- * Note: It's possible that the server returns 401 again in step 2, if the
- *       Kerberos context isn't complete yet. This means there is 3rd step
- *       where we'll send a request with an Authorization header to the 
- *       server. Some (simple) tests with mod_auth_kerb and MIT Kerberos 5 show
- *       this never happens.
- *
- * Depending on the type of HTTP server, this handshake is required for either
- * every new connection, or for every new request! For more info see the next
- * comment on authn_persistence_state_t.
- *
- * Note: Step 1 of the handshake will only happen on the first connection, once
- * we know the server requires Kerberos authentication, the initial requests
- * on the other connections will include a session key, so we start at
- * step 2 in the handshake.
- * ### TODO: Not implemented yet!
- */
-
-/* Current state of the authentication of the current request. */
-typedef enum {
-    gss_api_auth_not_started,
-    gss_api_auth_in_progress,
-    gss_api_auth_completed,
-} gss_api_auth_state;
-
-/**
-   authn_persistence_state_t: state that indicates if we are talking with a
-   server that requires authentication only of the first request (stateful),
-   or of each request (stateless).
- 
-   INIT: Begin state. Authenticating the first request on this connection.
-   UNDECIDED: we haven't identified the server yet, assume STATEFUL for now.
-     Pipeline mode disabled, requests are sent only after the response off the
-     previous request arrived.
-   STATELESS: we know the server requires authentication for each request.
-     On all new requests add the Authorization header with an initial SPNEGO
-     token (created per request).
-     To keep things simple, keep the connection in one by one mode.
-     (otherwise we'd have to keep a queue of gssapi context objects to match
-      the Negotiate header of the response with the session initiated by the
-      mathing request).
-     This state is an final state.
-   STATEFUL: alright, we have authenticated the connection and for the server
-     that is enough. Don't add an Authorization header to new requests.
-     Serf will switch to pipelined mode.
-     This state is not a final state, although in practical scenario's it will
-     be. When we receive a 40x response from the server switch to STATELESS
-     mode.
-
-   We start in state init for the first request until it is authenticated.
-
-   The rest of the state machine starts with the arrival of the response to the
-   second request, and then goes on with each response:
-
-      --------
-      | INIT |     C --> S:    GET request in response to 40x of the server
-      --------                 add [Proxy]-Authorization header
-          |
-          |
-    ------------
-    | UNDECIDED|   C --> S:    GET request, assume stateful,
-    ------------               no [Proxy]-Authorization header
-          |
-          |
-          |------------------------------------------------
-          |                                               |
-          | C <-- S: 40x Authentication                   | C <-- S: 200 OK
-          |          Required                             |
-          |                                               |
-          v                                               v
-      -------------                               ------------
-    ->| STATELESS |<------------------------------| STATEFUL |<--
-    | -------------       C <-- S: 40x            ------------  |
-  * |    |                Authentication                  |     | 200 OK
-    |    /                Required                        |     |
-    -----                                                 -----/
-
- **/
-typedef enum {
-    pstate_init,
-    pstate_undecided,
-    pstate_stateless,
-    pstate_stateful,
-} authn_persistence_state_t;
-
-
-/* HTTP Service name, used to get the session key.  */
-#define KRB_HTTP_SERVICE "HTTP"
-
-/* Stores the context information related to Kerberos authentication. */
-typedef struct
-{
-    apr_pool_t *pool;
-
-    /* GSSAPI context */
-    serf__spnego_context_t *gss_ctx;
-
-    /* Current state of the authentication cycle. */
-    gss_api_auth_state state;
-
-    /* Current persistence state. */
-    authn_persistence_state_t pstate;
-
-    const char *header;
-    const char *value;
-} gss_authn_info_t;
-
-/* On the initial 401 response of the server, request a session key from
-   the Kerberos KDC to pass to the server, proving that we are who we
-   claim to be. The session key can only be used with the HTTP service
-   on the target host. */
-static apr_status_t
-gss_api_get_credentials(serf_connection_t *conn,
-                        char *token, apr_size_t token_len,
-                        const char *hostname,
-                        const char **buf, apr_size_t *buf_len,
-                        gss_authn_info_t *gss_info)
-{
-    serf__spnego_buffer_t input_buf;
-    serf__spnego_buffer_t output_buf;
-    apr_status_t status = APR_SUCCESS;
-
-    /* If the server sent us a token, pass it to gss_init_sec_token for
-       validation. */
-    if (token) {
-        input_buf.value = token;
-        input_buf.length = token_len;
-    } else {
-        input_buf.value = 0;
-        input_buf.length = 0;
-    }
-
-    /* Establish a security context to the server. */
-    status = serf__spnego_init_sec_context(
-         conn,
-         gss_info->gss_ctx,
-         KRB_HTTP_SERVICE, hostname,
-         &input_buf,
-         &output_buf,
-         gss_info->pool,
-         gss_info->pool
-        );
-
-    switch(status) {
-    case APR_SUCCESS:
-        if (output_buf.length == 0) {
-            gss_info->state = gss_api_auth_completed;
-        } else {
-            gss_info->state = gss_api_auth_in_progress;
-        }
-        break;
-    case APR_EAGAIN:
-        gss_info->state = gss_api_auth_in_progress;
-        status = APR_SUCCESS;
-        break;
-    default:
-        return status;
-    }
-
-    /* Return the session key to our caller. */
-    *buf = output_buf.value;
-    *buf_len = output_buf.length;
-
-    return status;
-}
-
-/* do_auth is invoked in two situations:
-   - when a response from a server is received that contains an authn header
-     (either from a 40x or 2xx response)
-   - when a request is prepared on a connection with stateless authentication.
-
-   Read the header sent by the server (if any), invoke the gssapi authn
-   code and use the resulting Server Ticket on the next request to the
-   server. */
-static apr_status_t
-do_auth(peer_t peer,
-        int code,
-        gss_authn_info_t *gss_info,
-        serf_connection_t *conn,
-        serf_request_t *request,
-        const char *auth_hdr,
-        apr_pool_t *pool)
-{
-    serf_context_t *ctx = conn->ctx;
-    serf__authn_info_t *authn_info;
-    const char *tmp = NULL;
-    char *token = NULL;
-    apr_size_t tmp_len = 0, token_len = 0;
-    apr_status_t status;
-
-    if (peer == HOST) {
-        authn_info = serf__get_authn_info_for_server(conn);
-    } else {
-        authn_info = &ctx->proxy_authn_info;
-    }
-
-    /* Is this a response from a host/proxy? auth_hdr should always be set. */
-    if (code && auth_hdr) {
-        const char *space = NULL;
-        /* The server will return a token as attribute to the Negotiate key.
-           Negotiate YGwGCSqGSIb3EgECAgIAb10wW6ADAgEFoQMCAQ+iTzBNoAMCARCiRgREa6
-           mouMBAMFqKVdTGtfpZNXKzyw4Yo1paphJdIA3VOgncaoIlXxZLnkHiIHS2v65pVvrp
-           bRIyjF8xve9HxpnNIucCY9c=
-
-           Read this base64 value, decode it and validate it so we're sure the
-           server is who we expect it to be. */
-        space = strchr(auth_hdr, ' ');
-
-        if (space) {
-            token = apr_palloc(pool, apr_base64_decode_len(space + 1));
-            token_len = apr_base64_decode(token, space + 1);
-        }
-    } else {
-        /* This is a new request, not a retry in response to a 40x of the
-           host/proxy. 
-           Only add the Authorization header if we know the server requires
-           per-request authentication (stateless). */
-        if (gss_info->pstate != pstate_stateless)
-            return APR_SUCCESS;
-    }
-
-    switch(gss_info->pstate) {
-        case pstate_init:
-            /* Nothing to do here */
-            break;
-        case pstate_undecided: /* Fall through */
-        case pstate_stateful:
-            {
-                /* Switch to stateless mode, from now on handle authentication
-                   of each request with a new gss context. This is easiest to
-                   manage when sending requests one by one. */
-                serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
-                              "Server requires per-request SPNEGO authn, "
-                              "switching to stateless mode.\n");
-
-                gss_info->pstate = pstate_stateless;
-                serf_connection_set_max_outstanding_requests(conn, 1);
-                break;
-            }
-        case pstate_stateless:
-            /* Nothing to do here */
-            break;
-    }
-
-    if (request->auth_baton && !token) {
-        /* We provided token with this request, but server responded with empty
-           authentication header. This means server rejected our credentials.
-           XXX: Probably we need separate error code for this case like
-           SERF_ERROR_AUTHN_CREDS_REJECTED? */
-        return SERF_ERROR_AUTHN_FAILED;
-    }
-
-    /* If the server didn't provide us with a token, start with a new initial
-       step in the SPNEGO authentication. */
-    if (!token) {
-        serf__spnego_reset_sec_context(gss_info->gss_ctx);
-        gss_info->state = gss_api_auth_not_started;
-    }
-
-    if (peer == HOST) {
-        status = gss_api_get_credentials(conn,
-                                         token, token_len,
-                                         conn->host_info.hostname,
-                                         &tmp, &tmp_len,
-                                         gss_info);
-    } else {
-        char *proxy_host = conn->ctx->proxy_address->hostname;
-        status = gss_api_get_credentials(conn,
-                                         token, token_len, proxy_host,
-                                         &tmp, &tmp_len,
-                                         gss_info);
-    }
-    if (status)
-        return status;
-
-    /* On the next request, add an Authorization header. */
-    if (tmp_len) {
-        serf__encode_auth_header(&gss_info->value, authn_info->scheme->name,
-                                 tmp,
-                                 tmp_len,
-                                 pool);
-        gss_info->header = (peer == HOST) ?
-            "Authorization" : "Proxy-Authorization";
-    }
-
-    return APR_SUCCESS;
-}
-
-apr_status_t
-serf__init_spnego(int code,
-                  serf_context_t *ctx,
-                  apr_pool_t *pool)
-{
-    return APR_SUCCESS;
-}
-
-/* A new connection is created to a server that's known to use
-   Kerberos. */
-apr_status_t
-serf__init_spnego_connection(const serf__authn_scheme_t *scheme,
-                             int code,
-                             serf_connection_t *conn,
-                             apr_pool_t *pool)
-{
-    serf_context_t *ctx = conn->ctx;
-    serf__authn_info_t *authn_info;
-    gss_authn_info_t *gss_info = NULL;
-
-    /* For proxy authentication, reuse the gss context for all connections. 
-       For server authentication, create a new gss context per connection. */
-    if (code == 401) {
-        authn_info = &conn->authn_info;
-    } else {
-        authn_info = &ctx->proxy_authn_info;
-    }
-    gss_info = authn_info->baton;
-
-    if (!gss_info) {
-        apr_status_t status;
-
-        gss_info = apr_pcalloc(conn->pool, sizeof(*gss_info));
-        gss_info->pool = conn->pool;
-        gss_info->state = gss_api_auth_not_started;
-        gss_info->pstate = pstate_init;
-        status = serf__spnego_create_sec_context(&gss_info->gss_ctx, scheme,
-                                                 gss_info->pool, pool);
-        if (status) {
-            return status;
-        }
-        authn_info->baton = gss_info;
-    }
-
-    /* Make serf send the initial requests one by one */
-    serf_connection_set_max_outstanding_requests(conn, 1);
-
-    serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
-                  "Initialized Kerberos context for this connection.\n");
-
-    return APR_SUCCESS;
-}
-
-/* A 40x response was received, handle the authentication. */
-apr_status_t
-serf__handle_spnego_auth(int code,
-                         serf_request_t *request,
-                         serf_bucket_t *response,
-                         const char *auth_hdr,
-                         const char *auth_attr,
-                         void *baton,
-                         apr_pool_t *pool)
-{
-    serf_connection_t *conn = request->conn;
-    serf_context_t *ctx = conn->ctx;
-    gss_authn_info_t *gss_info = (code == 401) ? conn->authn_info.baton :
-                                                 ctx->proxy_authn_info.baton;
-
-    return do_auth(code == 401 ? HOST : PROXY,
-                   code,
-                   gss_info,
-                   request->conn,
-                   request,
-                   auth_hdr,
-                   pool);
-}
-
-/* Setup the authn headers on this request message. */
-apr_status_t
-serf__setup_request_spnego_auth(peer_t peer,
-                                int code,
-                                serf_connection_t *conn,
-                                serf_request_t *request,
-                                const char *method,
-                                const char *uri,
-                                serf_bucket_t *hdrs_bkt)
-{
-    serf_context_t *ctx = conn->ctx;
-    gss_authn_info_t *gss_info = (peer == HOST) ? conn->authn_info.baton :
-                                                  ctx->proxy_authn_info.baton;
-
-    /* If we have an ongoing authentication handshake, the handler of the
-       previous response will have created the authn headers for this request
-       already. */
-    if (gss_info && gss_info->header && gss_info->value) {
-        serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
-                      "Set Negotiate authn header on retried request.\n");
-
-        serf_bucket_headers_setn(hdrs_bkt, gss_info->header,
-                                 gss_info->value);
-
-        /* Remember that we're using this request for authentication
-           handshake. */
-        request->auth_baton = (void*) TRUE;
-
-        /* We should send each token only once. */
-        gss_info->header = NULL;
-        gss_info->value = NULL;
-
-        return APR_SUCCESS;
-    }
-
-    switch (gss_info->pstate) {
-        case pstate_init:
-            /* We shouldn't normally arrive here, do nothing. */
-            break;
-        case pstate_undecided: /* fall through */
-            serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
-                          "Assume for now that the server supports persistent "
-                          "SPNEGO authentication.\n");
-            /* Nothing to do here. */
-            break;
-        case pstate_stateful:
-            serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
-                          "SPNEGO on this connection is persistent, "
-                          "don't set authn header on next request.\n");
-            /* Nothing to do here. */
-            break;
-        case pstate_stateless:
-            {
-                apr_status_t status;
-
-                /* Authentication on this connection is known to be stateless.
-                   Add an initial Negotiate token for the server, to bypass the
-                   40x response we know we'll otherwise receive.
-                  (RFC 4559 section 4.2) */
-                serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
-                              "Add initial Negotiate header to request.\n");
-
-                status = do_auth(peer,
-                                 code,
-                                 gss_info,
-                                 conn,
-                                 request,
-                                 0l,    /* no response authn header */
-                                 conn->pool);
-                if (status)
-                    return status;
-
-                serf_bucket_headers_setn(hdrs_bkt, gss_info->header,
-                                         gss_info->value);
-
-                /* Remember that we're using this request for authentication
-                   handshake. */
-                request->auth_baton = (void*) TRUE;
-
-                /* We should send each token only once. */
-                gss_info->header = NULL;
-                gss_info->value = NULL;
-                break;
-            }
-    }
-
-    return APR_SUCCESS;
-}
-
-/**
- * Baton passed to the get_auth_header callback function.
- */
-typedef struct {
-    const char *hdr_name;
-    const char *auth_name;
-    const char *hdr_value;
-    apr_pool_t *pool;
-} get_auth_header_baton_t;
-
-static int
-get_auth_header_cb(void *baton,
-                   const char *key,
-                   const char *header)
-{
-    get_auth_header_baton_t *b = baton;
-
-    /* We're only interested in xxxx-Authenticate headers. */
-    if (strcasecmp(key, b->hdr_name) != 0)
-        return 0;
-
-    /* Check if header value starts with interesting auth name. */
-    if (strncmp(header, b->auth_name, strlen(b->auth_name)) == 0) {
-        /* Save interesting header value and stop iteration. */
-        b->hdr_value = apr_pstrdup(b->pool,  header);
-        return 1;
-    }
-
-    return 0;
-}
-
-static const char *
-get_auth_header(serf_bucket_t *hdrs,
-                const char *hdr_name,
-                const char *auth_name,
-                apr_pool_t *pool)
-{
-    get_auth_header_baton_t b;
-
-    b.auth_name = hdr_name;
-    b.hdr_name = auth_name;
-    b.hdr_value = NULL;
-    b.pool = pool;
-
-    serf_bucket_headers_do(hdrs, get_auth_header_cb, &b);
-
-    return b.hdr_value;
-}
-
-/* Function is called when 2xx responses are received. Normally we don't
- * have to do anything, except for the first response after the
- * authentication handshake. This specific response includes authentication
- * data which should be validated by the client (mutual authentication).
- */
-apr_status_t
-serf__validate_response_spnego_auth(const serf__authn_scheme_t *scheme,
-                                    peer_t peer,
-                                    int code,
-                                    serf_connection_t *conn,
-                                    serf_request_t *request,
-                                    serf_bucket_t *response,
-                                    apr_pool_t *pool)
-{
-    serf_context_t *ctx = conn->ctx;
-    gss_authn_info_t *gss_info;
-    const char *auth_hdr_name;
-
-    /* TODO: currently this function is only called when a response includes
-       an Authenticate header. This header is optional. If the server does
-       not provide this header on the first 2xx response, we will not promote
-       the connection from undecided to stateful. This won't break anything,
-       but means we stay in non-pipelining mode. */
-    serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
-                  "Validate Negotiate response header.\n");
-
-    if (peer == HOST) {
-        gss_info = conn->authn_info.baton;
-        auth_hdr_name = "WWW-Authenticate";
-    } else {
-        gss_info = ctx->proxy_authn_info.baton;
-        auth_hdr_name = "Proxy-Authenticate";
-    }
-
-    if (gss_info->state != gss_api_auth_completed) {
-        serf_bucket_t *hdrs;
-        const char *auth_hdr_val;
-        apr_status_t status;
-
-        hdrs = serf_bucket_response_get_headers(response);
-        auth_hdr_val = get_auth_header(hdrs, auth_hdr_name, scheme->name,
-                                       pool);
-
-        if (auth_hdr_val) {
-            status = do_auth(peer, code, gss_info, conn, request, auth_hdr_val,
-                             pool);
-            if (status) {
-                return status;
-            }
-        } else {
-            /* No Authenticate headers, nothing to validate: authentication
-               completed.*/
-            gss_info->state = gss_api_auth_completed;
-
-            serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
-                          "SPNEGO handshake completed.\n");
-        }
-    }
-
-    if (gss_info->state == gss_api_auth_completed) {
-        switch(gss_info->pstate) {
-            case pstate_init:
-                /* Authentication of the first request is done. */
-                gss_info->pstate = pstate_undecided;
-                break;
-            case pstate_undecided:
-                /* The server didn't request for authentication even though
-                   we didn't add an Authorization header to previous
-                   request. That means it supports persistent authentication. */
-                gss_info->pstate = pstate_stateful;
-                serf_connection_set_max_outstanding_requests(conn, 0);
-                break;
-            default:
-                /* Nothing to do here. */
-                break;
-        }
-    }
-
-    return APR_SUCCESS;
-}
-
-#endif /* SERF_HAVE_SPNEGO */

Copied: vendor/serf/1.3.9/auth/auth_spnego.c (from rev 9259, vendor/serf/dist/auth/auth_spnego.c)
===================================================================
--- vendor/serf/1.3.9/auth/auth_spnego.c	                        (rev 0)
+++ vendor/serf/1.3.9/auth/auth_spnego.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,662 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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 "auth_spnego.h"
+
+#ifdef SERF_HAVE_SPNEGO
+
+/** These functions implement SPNEGO-based Kerberos and NTLM authentication,
+ *  using either GSS-API (RFC 2743) or SSPI on Windows.
+ *  The HTTP message exchange is documented in RFC 4559.
+ **/
+
+#include <serf.h>
+#include <serf_private.h>
+#include <auth/auth.h>
+
+#include <apr.h>
+#include <apr_base64.h>
+#include <apr_strings.h>
+
+/** TODO:
+ ** - send session key directly on new connections where we already know
+ **   the server requires Kerberos authn.
+ ** - Add a way for serf to give detailed error information back to the
+ **   application.
+ **/
+
+/* Authentication over HTTP using Kerberos
+ *
+ * Kerberos involves three servers:
+ * - Authentication Server (AS): verifies users during login
+ * - Ticket-Granting Server (TGS): issues proof of identity tickets
+ * - HTTP server (S)
+ *
+ * Steps:
+ * 0. User logs in to the AS and receives a TGS ticket. On workstations
+ * where the login program doesn't support Kerberos, the user can use
+ * 'kinit'.
+ *
+ * 1. C  --> S:    GET
+ *
+ *    C <--  S:    401 Authentication Required
+ *                 WWW-Authenticate: Negotiate
+ *
+ * -> app contacts the TGS to request a session key for the HTTP service
+ *    @ target host. The returned session key is encrypted with the HTTP
+ *    service's secret key, so we can safely send it to the server.
+ *
+ * 2. C  --> S:    GET
+ *                 Authorization: Negotiate <Base64 encoded session key>
+ *                 gss_api_ctx->state = gss_api_auth_in_progress;
+ *
+ *    C <--  S:    200 OK
+ *                 WWW-Authenticate: Negotiate <Base64 encoded server
+ *                                              authentication data>
+ *
+ * -> The server returned an (optional) key to proof itself to us. We check this
+ *    key with the TGS again. If it checks out, we can return the response
+ *    body to the application.
+ *
+ * Note: It's possible that the server returns 401 again in step 2, if the
+ *       Kerberos context isn't complete yet. This means there is 3rd step
+ *       where we'll send a request with an Authorization header to the 
+ *       server. Some (simple) tests with mod_auth_kerb and MIT Kerberos 5 show
+ *       this never happens.
+ *
+ * Depending on the type of HTTP server, this handshake is required for either
+ * every new connection, or for every new request! For more info see the next
+ * comment on authn_persistence_state_t.
+ *
+ * Note: Step 1 of the handshake will only happen on the first connection, once
+ * we know the server requires Kerberos authentication, the initial requests
+ * on the other connections will include a session key, so we start at
+ * step 2 in the handshake.
+ * ### TODO: Not implemented yet!
+ */
+
+/* Current state of the authentication of the current request. */
+typedef enum {
+    gss_api_auth_not_started,
+    gss_api_auth_in_progress,
+    gss_api_auth_completed,
+} gss_api_auth_state;
+
+/**
+   authn_persistence_state_t: state that indicates if we are talking with a
+   server that requires authentication only of the first request (stateful),
+   or of each request (stateless).
+ 
+   INIT: Begin state. Authenticating the first request on this connection.
+   UNDECIDED: we haven't identified the server yet, assume STATEFUL for now.
+     Pipeline mode disabled, requests are sent only after the response off the
+     previous request arrived.
+   STATELESS: we know the server requires authentication for each request.
+     On all new requests add the Authorization header with an initial SPNEGO
+     token (created per request).
+     To keep things simple, keep the connection in one by one mode.
+     (otherwise we'd have to keep a queue of gssapi context objects to match
+      the Negotiate header of the response with the session initiated by the
+      mathing request).
+     This state is an final state.
+   STATEFUL: alright, we have authenticated the connection and for the server
+     that is enough. Don't add an Authorization header to new requests.
+     Serf will switch to pipelined mode.
+     This state is not a final state, although in practical scenario's it will
+     be. When we receive a 40x response from the server switch to STATELESS
+     mode.
+
+   We start in state init for the first request until it is authenticated.
+
+   The rest of the state machine starts with the arrival of the response to the
+   second request, and then goes on with each response:
+
+      --------
+      | INIT |     C --> S:    GET request in response to 40x of the server
+      --------                 add [Proxy]-Authorization header
+          |
+          |
+    ------------
+    | UNDECIDED|   C --> S:    GET request, assume stateful,
+    ------------               no [Proxy]-Authorization header
+          |
+          |
+          |------------------------------------------------
+          |                                               |
+          | C <-- S: 40x Authentication                   | C <-- S: 200 OK
+          |          Required                             |
+          |                                               |
+          v                                               v
+      -------------                               ------------
+    ->| STATELESS |<------------------------------| STATEFUL |<--
+    | -------------       C <-- S: 40x            ------------  |
+  * |    |                Authentication                  |     | 200 OK
+    |    /                Required                        |     |
+    -----                                                 -----/
+
+ **/
+typedef enum {
+    pstate_init,
+    pstate_undecided,
+    pstate_stateless,
+    pstate_stateful,
+} authn_persistence_state_t;
+
+
+/* HTTP Service name, used to get the session key.  */
+#define KRB_HTTP_SERVICE "HTTP"
+
+/* Stores the context information related to Kerberos authentication. */
+typedef struct
+{
+    apr_pool_t *pool;
+
+    /* GSSAPI context */
+    serf__spnego_context_t *gss_ctx;
+
+    /* Current state of the authentication cycle. */
+    gss_api_auth_state state;
+
+    /* Current persistence state. */
+    authn_persistence_state_t pstate;
+
+    const char *header;
+    const char *value;
+} gss_authn_info_t;
+
+/* On the initial 401 response of the server, request a session key from
+   the Kerberos KDC to pass to the server, proving that we are who we
+   claim to be. The session key can only be used with the HTTP service
+   on the target host. */
+static apr_status_t
+gss_api_get_credentials(serf_connection_t *conn,
+                        char *token, apr_size_t token_len,
+                        const char *hostname,
+                        const char **buf, apr_size_t *buf_len,
+                        gss_authn_info_t *gss_info)
+{
+    serf__spnego_buffer_t input_buf;
+    serf__spnego_buffer_t output_buf;
+    apr_status_t status = APR_SUCCESS;
+
+    /* If the server sent us a token, pass it to gss_init_sec_token for
+       validation. */
+    if (token) {
+        input_buf.value = token;
+        input_buf.length = token_len;
+    } else {
+        input_buf.value = 0;
+        input_buf.length = 0;
+    }
+
+    /* Establish a security context to the server. */
+    status = serf__spnego_init_sec_context(
+         conn,
+         gss_info->gss_ctx,
+         KRB_HTTP_SERVICE, hostname,
+         &input_buf,
+         &output_buf,
+         gss_info->pool,
+         gss_info->pool
+        );
+
+    switch(status) {
+    case APR_SUCCESS:
+        if (output_buf.length == 0) {
+            gss_info->state = gss_api_auth_completed;
+        } else {
+            gss_info->state = gss_api_auth_in_progress;
+        }
+        break;
+    case APR_EAGAIN:
+        gss_info->state = gss_api_auth_in_progress;
+        status = APR_SUCCESS;
+        break;
+    default:
+        return status;
+    }
+
+    /* Return the session key to our caller. */
+    *buf = output_buf.value;
+    *buf_len = output_buf.length;
+
+    return status;
+}
+
+/* do_auth is invoked in two situations:
+   - when a response from a server is received that contains an authn header
+     (either from a 40x or 2xx response)
+   - when a request is prepared on a connection with stateless authentication.
+
+   Read the header sent by the server (if any), invoke the gssapi authn
+   code and use the resulting Server Ticket on the next request to the
+   server. */
+static apr_status_t
+do_auth(peer_t peer,
+        int code,
+        gss_authn_info_t *gss_info,
+        serf_connection_t *conn,
+        serf_request_t *request,
+        const char *auth_hdr,
+        apr_pool_t *pool)
+{
+    serf_context_t *ctx = conn->ctx;
+    serf__authn_info_t *authn_info;
+    const char *tmp = NULL;
+    char *token = NULL;
+    apr_size_t tmp_len = 0, token_len = 0;
+    apr_status_t status;
+
+    if (peer == HOST) {
+        authn_info = serf__get_authn_info_for_server(conn);
+    } else {
+        authn_info = &ctx->proxy_authn_info;
+    }
+
+    /* Is this a response from a host/proxy? auth_hdr should always be set. */
+    if (code && auth_hdr) {
+        const char *space = NULL;
+        /* The server will return a token as attribute to the Negotiate key.
+           Negotiate YGwGCSqGSIb3EgECAgIAb10wW6ADAgEFoQMCAQ+iTzBNoAMCARCiRgREa6
+           mouMBAMFqKVdTGtfpZNXKzyw4Yo1paphJdIA3VOgncaoIlXxZLnkHiIHS2v65pVvrp
+           bRIyjF8xve9HxpnNIucCY9c=
+
+           Read this base64 value, decode it and validate it so we're sure the
+           server is who we expect it to be. */
+        space = strchr(auth_hdr, ' ');
+
+        if (space) {
+            token = apr_palloc(pool, apr_base64_decode_len(space + 1));
+            token_len = apr_base64_decode(token, space + 1);
+        }
+    } else {
+        /* This is a new request, not a retry in response to a 40x of the
+           host/proxy. 
+           Only add the Authorization header if we know the server requires
+           per-request authentication (stateless). */
+        if (gss_info->pstate != pstate_stateless)
+            return APR_SUCCESS;
+    }
+
+    switch(gss_info->pstate) {
+        case pstate_init:
+            /* Nothing to do here */
+            break;
+        case pstate_undecided: /* Fall through */
+        case pstate_stateful:
+            {
+                /* Switch to stateless mode, from now on handle authentication
+                   of each request with a new gss context. This is easiest to
+                   manage when sending requests one by one. */
+                serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
+                              "Server requires per-request SPNEGO authn, "
+                              "switching to stateless mode.\n");
+
+                gss_info->pstate = pstate_stateless;
+                serf_connection_set_max_outstanding_requests(conn, 1);
+                break;
+            }
+        case pstate_stateless:
+            /* Nothing to do here */
+            break;
+    }
+
+    if (request->auth_baton && !token) {
+        /* We provided token with this request, but server responded with empty
+           authentication header. This means server rejected our credentials.
+           XXX: Probably we need separate error code for this case like
+           SERF_ERROR_AUTHN_CREDS_REJECTED? */
+        return SERF_ERROR_AUTHN_FAILED;
+    }
+
+    /* If the server didn't provide us with a token, start with a new initial
+       step in the SPNEGO authentication. */
+    if (!token) {
+        serf__spnego_reset_sec_context(gss_info->gss_ctx);
+        gss_info->state = gss_api_auth_not_started;
+    }
+
+    if (peer == HOST) {
+        status = gss_api_get_credentials(conn,
+                                         token, token_len,
+                                         conn->host_info.hostname,
+                                         &tmp, &tmp_len,
+                                         gss_info);
+    } else {
+        char *proxy_host = conn->ctx->proxy_address->hostname;
+        status = gss_api_get_credentials(conn,
+                                         token, token_len, proxy_host,
+                                         &tmp, &tmp_len,
+                                         gss_info);
+    }
+    if (status)
+        return status;
+
+    /* On the next request, add an Authorization header. */
+    if (tmp_len) {
+        serf__encode_auth_header(&gss_info->value, authn_info->scheme->name,
+                                 tmp,
+                                 tmp_len,
+                                 pool);
+        gss_info->header = (peer == HOST) ?
+            "Authorization" : "Proxy-Authorization";
+    }
+
+    return APR_SUCCESS;
+}
+
+apr_status_t
+serf__init_spnego(int code,
+                  serf_context_t *ctx,
+                  apr_pool_t *pool)
+{
+    return APR_SUCCESS;
+}
+
+/* A new connection is created to a server that's known to use
+   Kerberos. */
+apr_status_t
+serf__init_spnego_connection(const serf__authn_scheme_t *scheme,
+                             int code,
+                             serf_connection_t *conn,
+                             apr_pool_t *pool)
+{
+    serf_context_t *ctx = conn->ctx;
+    serf__authn_info_t *authn_info;
+    gss_authn_info_t *gss_info = NULL;
+
+    /* For proxy authentication, reuse the gss context for all connections. 
+       For server authentication, create a new gss context per connection. */
+    if (code == 401) {
+        authn_info = &conn->authn_info;
+    } else {
+        authn_info = &ctx->proxy_authn_info;
+    }
+    gss_info = authn_info->baton;
+
+    if (!gss_info) {
+        apr_status_t status;
+
+        gss_info = apr_pcalloc(conn->pool, sizeof(*gss_info));
+        gss_info->pool = conn->pool;
+        gss_info->state = gss_api_auth_not_started;
+        gss_info->pstate = pstate_init;
+        status = serf__spnego_create_sec_context(&gss_info->gss_ctx, scheme,
+                                                 gss_info->pool, pool);
+        if (status) {
+            return status;
+        }
+        authn_info->baton = gss_info;
+    }
+
+    /* Make serf send the initial requests one by one */
+    serf_connection_set_max_outstanding_requests(conn, 1);
+
+    serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
+                  "Initialized Kerberos context for this connection.\n");
+
+    return APR_SUCCESS;
+}
+
+/* A 40x response was received, handle the authentication. */
+apr_status_t
+serf__handle_spnego_auth(int code,
+                         serf_request_t *request,
+                         serf_bucket_t *response,
+                         const char *auth_hdr,
+                         const char *auth_attr,
+                         void *baton,
+                         apr_pool_t *pool)
+{
+    serf_connection_t *conn = request->conn;
+    serf_context_t *ctx = conn->ctx;
+    gss_authn_info_t *gss_info = (code == 401) ? conn->authn_info.baton :
+                                                 ctx->proxy_authn_info.baton;
+
+    return do_auth(code == 401 ? HOST : PROXY,
+                   code,
+                   gss_info,
+                   request->conn,
+                   request,
+                   auth_hdr,
+                   pool);
+}
+
+/* Setup the authn headers on this request message. */
+apr_status_t
+serf__setup_request_spnego_auth(peer_t peer,
+                                int code,
+                                serf_connection_t *conn,
+                                serf_request_t *request,
+                                const char *method,
+                                const char *uri,
+                                serf_bucket_t *hdrs_bkt)
+{
+    serf_context_t *ctx = conn->ctx;
+    gss_authn_info_t *gss_info = (peer == HOST) ? conn->authn_info.baton :
+                                                  ctx->proxy_authn_info.baton;
+
+    /* If we have an ongoing authentication handshake, the handler of the
+       previous response will have created the authn headers for this request
+       already. */
+    if (gss_info && gss_info->header && gss_info->value) {
+        serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
+                      "Set Negotiate authn header on retried request.\n");
+
+        serf_bucket_headers_setn(hdrs_bkt, gss_info->header,
+                                 gss_info->value);
+
+        /* Remember that we're using this request for authentication
+           handshake. */
+        request->auth_baton = (void*) TRUE;
+
+        /* We should send each token only once. */
+        gss_info->header = NULL;
+        gss_info->value = NULL;
+
+        return APR_SUCCESS;
+    }
+
+    switch (gss_info->pstate) {
+        case pstate_init:
+            /* We shouldn't normally arrive here, do nothing. */
+            break;
+        case pstate_undecided: /* fall through */
+            serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
+                          "Assume for now that the server supports persistent "
+                          "SPNEGO authentication.\n");
+            /* Nothing to do here. */
+            break;
+        case pstate_stateful:
+            serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
+                          "SPNEGO on this connection is persistent, "
+                          "don't set authn header on next request.\n");
+            /* Nothing to do here. */
+            break;
+        case pstate_stateless:
+            {
+                apr_status_t status;
+
+                /* Authentication on this connection is known to be stateless.
+                   Add an initial Negotiate token for the server, to bypass the
+                   40x response we know we'll otherwise receive.
+                  (RFC 4559 section 4.2) */
+                serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
+                              "Add initial Negotiate header to request.\n");
+
+                status = do_auth(peer,
+                                 code,
+                                 gss_info,
+                                 conn,
+                                 request,
+                                 0l,    /* no response authn header */
+                                 conn->pool);
+                if (status)
+                    return status;
+
+                serf_bucket_headers_setn(hdrs_bkt, gss_info->header,
+                                         gss_info->value);
+
+                /* Remember that we're using this request for authentication
+                   handshake. */
+                request->auth_baton = (void*) TRUE;
+
+                /* We should send each token only once. */
+                gss_info->header = NULL;
+                gss_info->value = NULL;
+                break;
+            }
+    }
+
+    return APR_SUCCESS;
+}
+
+/**
+ * Baton passed to the get_auth_header callback function.
+ */
+typedef struct {
+    const char *hdr_name;
+    const char *auth_name;
+    const char *hdr_value;
+    apr_pool_t *pool;
+} get_auth_header_baton_t;
+
+static int
+get_auth_header_cb(void *baton,
+                   const char *key,
+                   const char *header)
+{
+    get_auth_header_baton_t *b = baton;
+
+    /* We're only interested in xxxx-Authenticate headers. */
+    if (strcasecmp(key, b->hdr_name) != 0)
+        return 0;
+
+    /* Check if header value starts with interesting auth name. */
+    if (strncmp(header, b->auth_name, strlen(b->auth_name)) == 0) {
+        /* Save interesting header value and stop iteration. */
+        b->hdr_value = apr_pstrdup(b->pool,  header);
+        return 1;
+    }
+
+    return 0;
+}
+
+static const char *
+get_auth_header(serf_bucket_t *hdrs,
+                const char *hdr_name,
+                const char *auth_name,
+                apr_pool_t *pool)
+{
+    get_auth_header_baton_t b;
+
+    b.auth_name = hdr_name;
+    b.hdr_name = auth_name;
+    b.hdr_value = NULL;
+    b.pool = pool;
+
+    serf_bucket_headers_do(hdrs, get_auth_header_cb, &b);
+
+    return b.hdr_value;
+}
+
+/* Function is called when 2xx responses are received. Normally we don't
+ * have to do anything, except for the first response after the
+ * authentication handshake. This specific response includes authentication
+ * data which should be validated by the client (mutual authentication).
+ */
+apr_status_t
+serf__validate_response_spnego_auth(const serf__authn_scheme_t *scheme,
+                                    peer_t peer,
+                                    int code,
+                                    serf_connection_t *conn,
+                                    serf_request_t *request,
+                                    serf_bucket_t *response,
+                                    apr_pool_t *pool)
+{
+    serf_context_t *ctx = conn->ctx;
+    gss_authn_info_t *gss_info;
+    const char *auth_hdr_name;
+
+    /* TODO: currently this function is only called when a response includes
+       an Authenticate header. This header is optional. If the server does
+       not provide this header on the first 2xx response, we will not promote
+       the connection from undecided to stateful. This won't break anything,
+       but means we stay in non-pipelining mode. */
+    serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
+                  "Validate Negotiate response header.\n");
+
+    if (peer == HOST) {
+        gss_info = conn->authn_info.baton;
+        auth_hdr_name = "WWW-Authenticate";
+    } else {
+        gss_info = ctx->proxy_authn_info.baton;
+        auth_hdr_name = "Proxy-Authenticate";
+    }
+
+    if (gss_info->state != gss_api_auth_completed) {
+        serf_bucket_t *hdrs;
+        const char *auth_hdr_val;
+        apr_status_t status;
+
+        hdrs = serf_bucket_response_get_headers(response);
+        auth_hdr_val = get_auth_header(hdrs, auth_hdr_name, scheme->name,
+                                       pool);
+
+        if (auth_hdr_val) {
+            status = do_auth(peer, code, gss_info, conn, request, auth_hdr_val,
+                             pool);
+            if (status) {
+                return status;
+            }
+        } else {
+            /* No Authenticate headers, nothing to validate: authentication
+               completed.*/
+            gss_info->state = gss_api_auth_completed;
+
+            serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
+                          "SPNEGO handshake completed.\n");
+        }
+    }
+
+    if (gss_info->state == gss_api_auth_completed) {
+        switch(gss_info->pstate) {
+            case pstate_init:
+                /* Authentication of the first request is done. */
+                gss_info->pstate = pstate_undecided;
+                break;
+            case pstate_undecided:
+                /* The server didn't request for authentication even though
+                   we didn't add an Authorization header to previous
+                   request. That means it supports persistent authentication. */
+                gss_info->pstate = pstate_stateful;
+                serf_connection_set_max_outstanding_requests(conn, 0);
+                break;
+            default:
+                /* Nothing to do here. */
+                break;
+        }
+    }
+
+    return APR_SUCCESS;
+}
+
+#endif /* SERF_HAVE_SPNEGO */

Deleted: vendor/serf/1.3.9/auth/auth_spnego.h
===================================================================
--- vendor/serf/dist/auth/auth_spnego.h	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/auth/auth_spnego.h	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,116 +0,0 @@
-/* Copyright 2010 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 AUTH_SPNEGO_H
-#define AUTH_SPNEGO_H
-
-#include <apr.h>
-#include <apr_pools.h>
-#include "serf.h"
-#include "serf_private.h"
-
-#if defined(SERF_HAVE_SSPI)
-#define SERF_HAVE_SPNEGO
-#define SERF_USE_SSPI
-#elif defined(SERF_HAVE_GSSAPI)
-#define SERF_HAVE_SPNEGO
-#define SERF_USE_GSSAPI
-#endif
-
-#ifdef SERF_HAVE_SPNEGO
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct serf__spnego_context_t serf__spnego_context_t;
-
-typedef struct serf__spnego_buffer_t {
-    apr_size_t length;
-    void *value;
-} serf__spnego_buffer_t;
-
-/* Create outbound security context.
- *
- * All temporary allocations will be performed in SCRATCH_POOL, while security
- * context will be allocated in result_pool and will be destroyed automatically
- * on RESULT_POOL cleanup.
- *
- */
-apr_status_t
-serf__spnego_create_sec_context(serf__spnego_context_t **ctx_p,
-                                const serf__authn_scheme_t *scheme,
-                                apr_pool_t *result_pool,
-                                apr_pool_t *scratch_pool);
-
-/* Initialize outbound security context.
- *
- * The function is used to build a security context between the client
- * application and a remote peer.
- *
- * CTX is pointer to existing context created using
- * serf__spnego_create_sec_context() function.
- *
- * SERVICE is name of Kerberos service name. Usually 'HTTP'. HOSTNAME is
- * canonical name of destination server. Caller should resolve server's alias
- * to canonical name.
- *
- * INPUT_BUF is pointer structure describing input token if any. Should be
- * zero length on first call.
- *
- * OUTPUT_BUF will be populated with pointer to output data that should send
- * to destination server. This buffer will be automatically freed on
- * RESULT_POOL cleanup.
- *
- * All temporary allocations will be performed in SCRATCH_POOL.
- *
- * Return value:
- * - APR_EAGAIN The client must send the output token to the server and wait
- *   for a return token.
- *
- * - APR_SUCCESS The security context was successfully initialized. There is no
- *   need for another serf__spnego_init_sec_context call. If the function returns
- *   an output token, that is, if the OUTPUT_BUF is of nonzero length, that
- *   token must be sent to the server.
- *
- * Other returns values indicates error.
- */
-apr_status_t
-serf__spnego_init_sec_context(serf_connection_t *conn,
-                              serf__spnego_context_t *ctx,
-                              const char *service,
-                              const char *hostname,
-                              serf__spnego_buffer_t *input_buf,
-                              serf__spnego_buffer_t *output_buf,
-                              apr_pool_t *result_pool,
-                              apr_pool_t *scratch_pool
-                              );
-
-/*
- * Reset a previously created security context so we can start with a new one.
- *
- * This is triggered when the server requires per-request authentication,
- * where each request requires a new security context.
- */
-apr_status_t
-serf__spnego_reset_sec_context(serf__spnego_context_t *ctx);
-    
-#ifdef __cplusplus
-}
-#endif
-
-#endif    /* SERF_HAVE_SPNEGO */
-
-#endif    /* !AUTH_SPNEGO_H */

Copied: vendor/serf/1.3.9/auth/auth_spnego.h (from rev 9259, vendor/serf/dist/auth/auth_spnego.h)
===================================================================
--- vendor/serf/1.3.9/auth/auth_spnego.h	                        (rev 0)
+++ vendor/serf/1.3.9/auth/auth_spnego.h	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,121 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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 AUTH_SPNEGO_H
+#define AUTH_SPNEGO_H
+
+#include <apr.h>
+#include <apr_pools.h>
+#include "serf.h"
+#include "serf_private.h"
+
+#if defined(SERF_HAVE_SSPI)
+#define SERF_HAVE_SPNEGO
+#define SERF_USE_SSPI
+#elif defined(SERF_HAVE_GSSAPI)
+#define SERF_HAVE_SPNEGO
+#define SERF_USE_GSSAPI
+#endif
+
+#ifdef SERF_HAVE_SPNEGO
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct serf__spnego_context_t serf__spnego_context_t;
+
+typedef struct serf__spnego_buffer_t {
+    apr_size_t length;
+    void *value;
+} serf__spnego_buffer_t;
+
+/* Create outbound security context.
+ *
+ * All temporary allocations will be performed in SCRATCH_POOL, while security
+ * context will be allocated in result_pool and will be destroyed automatically
+ * on RESULT_POOL cleanup.
+ *
+ */
+apr_status_t
+serf__spnego_create_sec_context(serf__spnego_context_t **ctx_p,
+                                const serf__authn_scheme_t *scheme,
+                                apr_pool_t *result_pool,
+                                apr_pool_t *scratch_pool);
+
+/* Initialize outbound security context.
+ *
+ * The function is used to build a security context between the client
+ * application and a remote peer.
+ *
+ * CTX is pointer to existing context created using
+ * serf__spnego_create_sec_context() function.
+ *
+ * SERVICE is name of Kerberos service name. Usually 'HTTP'. HOSTNAME is
+ * canonical name of destination server. Caller should resolve server's alias
+ * to canonical name.
+ *
+ * INPUT_BUF is pointer structure describing input token if any. Should be
+ * zero length on first call.
+ *
+ * OUTPUT_BUF will be populated with pointer to output data that should send
+ * to destination server. This buffer will be automatically freed on
+ * RESULT_POOL cleanup.
+ *
+ * All temporary allocations will be performed in SCRATCH_POOL.
+ *
+ * Return value:
+ * - APR_EAGAIN The client must send the output token to the server and wait
+ *   for a return token.
+ *
+ * - APR_SUCCESS The security context was successfully initialized. There is no
+ *   need for another serf__spnego_init_sec_context call. If the function returns
+ *   an output token, that is, if the OUTPUT_BUF is of nonzero length, that
+ *   token must be sent to the server.
+ *
+ * Other returns values indicates error.
+ */
+apr_status_t
+serf__spnego_init_sec_context(serf_connection_t *conn,
+                              serf__spnego_context_t *ctx,
+                              const char *service,
+                              const char *hostname,
+                              serf__spnego_buffer_t *input_buf,
+                              serf__spnego_buffer_t *output_buf,
+                              apr_pool_t *result_pool,
+                              apr_pool_t *scratch_pool
+                              );
+
+/*
+ * Reset a previously created security context so we can start with a new one.
+ *
+ * This is triggered when the server requires per-request authentication,
+ * where each request requires a new security context.
+ */
+apr_status_t
+serf__spnego_reset_sec_context(serf__spnego_context_t *ctx);
+    
+#ifdef __cplusplus
+}
+#endif
+
+#endif    /* SERF_HAVE_SPNEGO */
+
+#endif    /* !AUTH_SPNEGO_H */

Deleted: vendor/serf/1.3.9/auth/auth_spnego_gss.c
===================================================================
--- vendor/serf/dist/auth/auth_spnego_gss.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/auth/auth_spnego_gss.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,226 +0,0 @@
-/* Copyright 2009 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 "serf.h"
-#include "serf_private.h"
-#include "auth_spnego.h"
-
-#ifdef SERF_USE_GSSAPI
-#include <apr_strings.h>
-#include <gssapi/gssapi.h>
-
-
-/* This module can support all authentication mechanisms as provided by
-   the GSS-API implementation, but for now it only supports SPNEGO for
-   Negotiate.
-   SPNEGO can delegate authentication to Kerberos if supported by the
-   host. */
-
-#ifndef GSS_SPNEGO_MECHANISM
-static gss_OID_desc spnego_mech_oid = { 6, "\x2b\x06\x01\x05\x05\x02" };
-#define GSS_SPNEGO_MECHANISM &spnego_mech_oid
-#endif
-
-struct serf__spnego_context_t
-{
-    /* GSSAPI context */
-    gss_ctx_id_t gss_ctx;
-
-    /* Mechanism used to authenticate. */
-    gss_OID gss_mech;
-};
-
-static void
-log_error(int verbose_flag, apr_socket_t *skt,
-          serf__spnego_context_t *ctx,
-          OM_uint32 err_maj_stat,
-          OM_uint32 err_min_stat,
-          const char *msg)
-{
-    OM_uint32 maj_stat, min_stat;
-    gss_buffer_desc stat_buff;
-    OM_uint32 msg_ctx = 0;
-
-    if (verbose_flag) {
-        maj_stat = gss_display_status(&min_stat,
-                                      err_maj_stat,
-                                      GSS_C_GSS_CODE,
-                                      ctx->gss_mech,
-                                      &msg_ctx,
-                                      &stat_buff);
-        if (maj_stat == GSS_S_COMPLETE ||
-            maj_stat == GSS_S_FAILURE) {
-            maj_stat = gss_display_status(&min_stat,
-                                          err_min_stat,
-                                          GSS_C_MECH_CODE,
-                                          ctx->gss_mech,
-                                          &msg_ctx,
-                                          &stat_buff);
-        }
-
-        serf__log_skt(verbose_flag, __FILE__, skt,
-                  "%s (%x,%d): %s\n", msg,
-                  err_maj_stat, err_min_stat, stat_buff.value);
-    }
-}
-
-/* Cleans the GSS context object, when the pool used to create it gets
-   cleared or destroyed. */
-static apr_status_t
-cleanup_ctx(void *data)
-{
-    serf__spnego_context_t *ctx = data;
-
-    if (ctx->gss_ctx != GSS_C_NO_CONTEXT) {
-        OM_uint32 gss_min_stat, gss_maj_stat;
-
-        gss_maj_stat = gss_delete_sec_context(&gss_min_stat, &ctx->gss_ctx,
-                                              GSS_C_NO_BUFFER);
-        if(GSS_ERROR(gss_maj_stat)) {
-            log_error(AUTH_VERBOSE, NULL, ctx,
-                      gss_maj_stat, gss_min_stat,
-                      "Error cleaning up GSS security context");
-            return SERF_ERROR_AUTHN_FAILED;
-        }
-    }
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t
-cleanup_sec_buffer(void *data)
-{
-    OM_uint32 min_stat;
-    gss_buffer_desc *gss_buf = data;
-
-    gss_release_buffer(&min_stat, gss_buf);
-
-    return APR_SUCCESS;
-}
-
-apr_status_t
-serf__spnego_create_sec_context(serf__spnego_context_t **ctx_p,
-                                const serf__authn_scheme_t *scheme,
-                                apr_pool_t *result_pool,
-                                apr_pool_t *scratch_pool)
-{
-    serf__spnego_context_t *ctx;
-
-    ctx = apr_pcalloc(result_pool, sizeof(*ctx));
-
-    ctx->gss_ctx = GSS_C_NO_CONTEXT;
-    ctx->gss_mech = GSS_SPNEGO_MECHANISM;
-
-    apr_pool_cleanup_register(result_pool, ctx,
-                              cleanup_ctx,
-                              apr_pool_cleanup_null);
-
-    *ctx_p = ctx;
-
-    return APR_SUCCESS;
-}
-
-apr_status_t
-serf__spnego_reset_sec_context(serf__spnego_context_t *ctx)
-{
-    OM_uint32 dummy_stat;
-
-    if (ctx->gss_ctx)
-        (void)gss_delete_sec_context(&dummy_stat, &ctx->gss_ctx,
-                                     GSS_C_NO_BUFFER);
-    ctx->gss_ctx = GSS_C_NO_CONTEXT;
-
-    return APR_SUCCESS;
-}
-
-apr_status_t
-serf__spnego_init_sec_context(serf_connection_t *conn,
-                              serf__spnego_context_t *ctx,
-                              const char *service,
-                              const char *hostname,
-                              serf__spnego_buffer_t *input_buf,
-                              serf__spnego_buffer_t *output_buf,
-                              apr_pool_t *result_pool,
-                              apr_pool_t *scratch_pool
-                              )
-{
-    gss_buffer_desc gss_input_buf = GSS_C_EMPTY_BUFFER;
-    gss_buffer_desc *gss_output_buf_p;
-    OM_uint32 gss_min_stat, gss_maj_stat;
-    gss_name_t host_gss_name;
-    gss_buffer_desc bufdesc;
-    gss_OID dummy; /* unused */
-
-    /* Get the name for the HTTP service at the target host. */
-    /* TODO: should be shared between multiple requests. */
-    bufdesc.value = apr_pstrcat(scratch_pool, service, "@", hostname, NULL);
-    bufdesc.length = strlen(bufdesc.value);
-    serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
-                  "Get principal for %s\n", bufdesc.value);
-    gss_maj_stat = gss_import_name (&gss_min_stat, &bufdesc,
-                                    GSS_C_NT_HOSTBASED_SERVICE,
-                                    &host_gss_name);
-    if(GSS_ERROR(gss_maj_stat)) {
-        log_error(AUTH_VERBOSE, conn->skt, ctx,
-                  gss_maj_stat, gss_min_stat,
-                  "Error converting principal name to GSS internal format ");
-        return SERF_ERROR_AUTHN_FAILED;
-    }
-
-    /* If the server sent us a token, pass it to gss_init_sec_token for
-       validation. */
-    gss_input_buf.value = input_buf->value;
-    gss_input_buf.length = input_buf->length;
-
-    gss_output_buf_p = apr_pcalloc(result_pool, sizeof(*gss_output_buf_p));
-
-    /* Establish a security context to the server. */
-    gss_maj_stat = gss_init_sec_context
-        (&gss_min_stat,             /* minor_status */
-         GSS_C_NO_CREDENTIAL,       /* XXXXX claimant_cred_handle */
-         &ctx->gss_ctx,              /* gssapi context handle */
-         host_gss_name,             /* HTTP at server name */
-         ctx->gss_mech,             /* mech_type (SPNEGO) */
-         GSS_C_MUTUAL_FLAG,         /* ensure the peer authenticates itself */
-         0,                         /* default validity period */
-         GSS_C_NO_CHANNEL_BINDINGS, /* do not use channel bindings */
-         &gss_input_buf,            /* server token, initially empty */
-         &dummy,                    /* actual mech type */
-         gss_output_buf_p,           /* output_token */
-         NULL,                      /* ret_flags */
-         NULL                       /* not interested in remaining validity */
-         );
-
-    apr_pool_cleanup_register(result_pool, gss_output_buf_p,
-                              cleanup_sec_buffer,
-                              apr_pool_cleanup_null);
-
-    output_buf->value = gss_output_buf_p->value;
-    output_buf->length = gss_output_buf_p->length;
-
-    switch(gss_maj_stat) {
-    case GSS_S_COMPLETE:
-        return APR_SUCCESS;
-    case GSS_S_CONTINUE_NEEDED:
-        return APR_EAGAIN;
-    default:
-        log_error(AUTH_VERBOSE, conn->skt, ctx,
-                  gss_maj_stat, gss_min_stat,
-                  "Error during Kerberos handshake");
-        return SERF_ERROR_AUTHN_FAILED;
-    }
-}
-
-#endif /* SERF_USE_GSSAPI */

Copied: vendor/serf/1.3.9/auth/auth_spnego_gss.c (from rev 9259, vendor/serf/dist/auth/auth_spnego_gss.c)
===================================================================
--- vendor/serf/1.3.9/auth/auth_spnego_gss.c	                        (rev 0)
+++ vendor/serf/1.3.9/auth/auth_spnego_gss.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,231 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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 "serf.h"
+#include "serf_private.h"
+#include "auth_spnego.h"
+
+#ifdef SERF_USE_GSSAPI
+#include <apr_strings.h>
+#include <gssapi/gssapi.h>
+
+
+/* This module can support all authentication mechanisms as provided by
+   the GSS-API implementation, but for now it only supports SPNEGO for
+   Negotiate.
+   SPNEGO can delegate authentication to Kerberos if supported by the
+   host. */
+
+#ifndef GSS_SPNEGO_MECHANISM
+static gss_OID_desc spnego_mech_oid = { 6, "\x2b\x06\x01\x05\x05\x02" };
+#define GSS_SPNEGO_MECHANISM &spnego_mech_oid
+#endif
+
+struct serf__spnego_context_t
+{
+    /* GSSAPI context */
+    gss_ctx_id_t gss_ctx;
+
+    /* Mechanism used to authenticate. */
+    gss_OID gss_mech;
+};
+
+static void
+log_error(int verbose_flag, apr_socket_t *skt,
+          serf__spnego_context_t *ctx,
+          OM_uint32 err_maj_stat,
+          OM_uint32 err_min_stat,
+          const char *msg)
+{
+    OM_uint32 maj_stat, min_stat;
+    gss_buffer_desc stat_buff;
+    OM_uint32 msg_ctx = 0;
+
+    if (verbose_flag) {
+        maj_stat = gss_display_status(&min_stat,
+                                      err_maj_stat,
+                                      GSS_C_GSS_CODE,
+                                      ctx->gss_mech,
+                                      &msg_ctx,
+                                      &stat_buff);
+        if (maj_stat == GSS_S_COMPLETE ||
+            maj_stat == GSS_S_FAILURE) {
+            maj_stat = gss_display_status(&min_stat,
+                                          err_min_stat,
+                                          GSS_C_MECH_CODE,
+                                          ctx->gss_mech,
+                                          &msg_ctx,
+                                          &stat_buff);
+        }
+
+        serf__log_skt(verbose_flag, __FILE__, skt,
+                  "%s (%x,%d): %s\n", msg,
+                  err_maj_stat, err_min_stat, stat_buff.value);
+    }
+}
+
+/* Cleans the GSS context object, when the pool used to create it gets
+   cleared or destroyed. */
+static apr_status_t
+cleanup_ctx(void *data)
+{
+    serf__spnego_context_t *ctx = data;
+
+    if (ctx->gss_ctx != GSS_C_NO_CONTEXT) {
+        OM_uint32 gss_min_stat, gss_maj_stat;
+
+        gss_maj_stat = gss_delete_sec_context(&gss_min_stat, &ctx->gss_ctx,
+                                              GSS_C_NO_BUFFER);
+        if(GSS_ERROR(gss_maj_stat)) {
+            log_error(AUTH_VERBOSE, NULL, ctx,
+                      gss_maj_stat, gss_min_stat,
+                      "Error cleaning up GSS security context");
+            return SERF_ERROR_AUTHN_FAILED;
+        }
+    }
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t
+cleanup_sec_buffer(void *data)
+{
+    OM_uint32 min_stat;
+    gss_buffer_desc *gss_buf = data;
+
+    gss_release_buffer(&min_stat, gss_buf);
+
+    return APR_SUCCESS;
+}
+
+apr_status_t
+serf__spnego_create_sec_context(serf__spnego_context_t **ctx_p,
+                                const serf__authn_scheme_t *scheme,
+                                apr_pool_t *result_pool,
+                                apr_pool_t *scratch_pool)
+{
+    serf__spnego_context_t *ctx;
+
+    ctx = apr_pcalloc(result_pool, sizeof(*ctx));
+
+    ctx->gss_ctx = GSS_C_NO_CONTEXT;
+    ctx->gss_mech = GSS_SPNEGO_MECHANISM;
+
+    apr_pool_cleanup_register(result_pool, ctx,
+                              cleanup_ctx,
+                              apr_pool_cleanup_null);
+
+    *ctx_p = ctx;
+
+    return APR_SUCCESS;
+}
+
+apr_status_t
+serf__spnego_reset_sec_context(serf__spnego_context_t *ctx)
+{
+    OM_uint32 dummy_stat;
+
+    if (ctx->gss_ctx)
+        (void)gss_delete_sec_context(&dummy_stat, &ctx->gss_ctx,
+                                     GSS_C_NO_BUFFER);
+    ctx->gss_ctx = GSS_C_NO_CONTEXT;
+
+    return APR_SUCCESS;
+}
+
+apr_status_t
+serf__spnego_init_sec_context(serf_connection_t *conn,
+                              serf__spnego_context_t *ctx,
+                              const char *service,
+                              const char *hostname,
+                              serf__spnego_buffer_t *input_buf,
+                              serf__spnego_buffer_t *output_buf,
+                              apr_pool_t *result_pool,
+                              apr_pool_t *scratch_pool
+                              )
+{
+    gss_buffer_desc gss_input_buf = GSS_C_EMPTY_BUFFER;
+    gss_buffer_desc *gss_output_buf_p;
+    OM_uint32 gss_min_stat, gss_maj_stat;
+    gss_name_t host_gss_name;
+    gss_buffer_desc bufdesc;
+    gss_OID dummy; /* unused */
+
+    /* Get the name for the HTTP service at the target host. */
+    /* TODO: should be shared between multiple requests. */
+    bufdesc.value = apr_pstrcat(scratch_pool, service, "@", hostname, NULL);
+    bufdesc.length = strlen(bufdesc.value);
+    serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
+                  "Get principal for %s\n", bufdesc.value);
+    gss_maj_stat = gss_import_name (&gss_min_stat, &bufdesc,
+                                    GSS_C_NT_HOSTBASED_SERVICE,
+                                    &host_gss_name);
+    if(GSS_ERROR(gss_maj_stat)) {
+        log_error(AUTH_VERBOSE, conn->skt, ctx,
+                  gss_maj_stat, gss_min_stat,
+                  "Error converting principal name to GSS internal format ");
+        return SERF_ERROR_AUTHN_FAILED;
+    }
+
+    /* If the server sent us a token, pass it to gss_init_sec_token for
+       validation. */
+    gss_input_buf.value = input_buf->value;
+    gss_input_buf.length = input_buf->length;
+
+    gss_output_buf_p = apr_pcalloc(result_pool, sizeof(*gss_output_buf_p));
+
+    /* Establish a security context to the server. */
+    gss_maj_stat = gss_init_sec_context
+        (&gss_min_stat,             /* minor_status */
+         GSS_C_NO_CREDENTIAL,       /* XXXXX claimant_cred_handle */
+         &ctx->gss_ctx,              /* gssapi context handle */
+         host_gss_name,             /* HTTP at server name */
+         ctx->gss_mech,             /* mech_type (SPNEGO) */
+         GSS_C_MUTUAL_FLAG,         /* ensure the peer authenticates itself */
+         0,                         /* default validity period */
+         GSS_C_NO_CHANNEL_BINDINGS, /* do not use channel bindings */
+         &gss_input_buf,            /* server token, initially empty */
+         &dummy,                    /* actual mech type */
+         gss_output_buf_p,           /* output_token */
+         NULL,                      /* ret_flags */
+         NULL                       /* not interested in remaining validity */
+         );
+
+    apr_pool_cleanup_register(result_pool, gss_output_buf_p,
+                              cleanup_sec_buffer,
+                              apr_pool_cleanup_null);
+
+    output_buf->value = gss_output_buf_p->value;
+    output_buf->length = gss_output_buf_p->length;
+
+    switch(gss_maj_stat) {
+    case GSS_S_COMPLETE:
+        return APR_SUCCESS;
+    case GSS_S_CONTINUE_NEEDED:
+        return APR_EAGAIN;
+    default:
+        log_error(AUTH_VERBOSE, conn->skt, ctx,
+                  gss_maj_stat, gss_min_stat,
+                  "Error during Kerberos handshake");
+        return SERF_ERROR_AUTHN_FAILED;
+    }
+}
+
+#endif /* SERF_USE_GSSAPI */

Deleted: vendor/serf/1.3.9/auth/auth_spnego_sspi.c
===================================================================
--- vendor/serf/dist/auth/auth_spnego_sspi.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/auth/auth_spnego_sspi.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,298 +0,0 @@
-/* Copyright 2010 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 "auth_spnego.h"
-#include "serf.h"
-#include "serf_private.h"
-
-#ifdef SERF_USE_SSPI
-#include <apr.h>
-#include <apr_strings.h>
-
-#define SECURITY_WIN32
-#include <sspi.h>
-
-/* SEC_E_MUTUAL_AUTH_FAILED is not defined in Windows Platform SDK 5.0. */
-#ifndef SEC_E_MUTUAL_AUTH_FAILED
-#define SEC_E_MUTUAL_AUTH_FAILED _HRESULT_TYPEDEF_(0x80090363L)
-#endif
-
-struct serf__spnego_context_t
-{
-    CredHandle sspi_credentials;
-    CtxtHandle sspi_context;
-    BOOL initalized;
-    apr_pool_t *pool;
-
-    /* Service Principal Name (SPN) used for authentication. */
-    const char *target_name;
-
-    /* One of SERF_AUTHN_* authentication types.*/
-    int authn_type;
-};
-
-/* Map SECURITY_STATUS from SSPI to APR error code. Some error codes mapped
- * to our own codes and some to Win32 error codes:
- * http://support.microsoft.com/kb/113996
- */
-static apr_status_t
-map_sspi_status(SECURITY_STATUS sspi_status)
-{
-    switch(sspi_status)
-    {
-    case SEC_E_INSUFFICIENT_MEMORY:
-        return APR_FROM_OS_ERROR(ERROR_NO_SYSTEM_RESOURCES);
-    case SEC_E_INVALID_HANDLE:
-        return APR_FROM_OS_ERROR(ERROR_INVALID_HANDLE);
-    case SEC_E_UNSUPPORTED_FUNCTION:
-        return APR_FROM_OS_ERROR(ERROR_INVALID_FUNCTION);
-    case SEC_E_TARGET_UNKNOWN:
-        return APR_FROM_OS_ERROR(ERROR_BAD_NETPATH);
-    case SEC_E_INTERNAL_ERROR:
-        return APR_FROM_OS_ERROR(ERROR_INTERNAL_ERROR);
-    case SEC_E_SECPKG_NOT_FOUND:
-    case SEC_E_BAD_PKGID:
-        return APR_FROM_OS_ERROR(ERROR_NO_SUCH_PACKAGE);
-    case SEC_E_NO_IMPERSONATION:
-        return APR_FROM_OS_ERROR(ERROR_CANNOT_IMPERSONATE);
-    case SEC_E_NO_AUTHENTICATING_AUTHORITY:
-        return APR_FROM_OS_ERROR(ERROR_NO_LOGON_SERVERS);
-    case SEC_E_UNTRUSTED_ROOT:
-        return APR_FROM_OS_ERROR(ERROR_TRUST_FAILURE);
-    case SEC_E_WRONG_PRINCIPAL:
-        return APR_FROM_OS_ERROR(ERROR_WRONG_TARGET_NAME);
-    case SEC_E_MUTUAL_AUTH_FAILED:
-        return APR_FROM_OS_ERROR(ERROR_MUTUAL_AUTH_FAILED);
-    case SEC_E_TIME_SKEW:
-        return APR_FROM_OS_ERROR(ERROR_TIME_SKEW);
-    default:
-        return SERF_ERROR_AUTHN_FAILED;
-    }
-}
-
-/* Cleans the SSPI context object, when the pool used to create it gets
-   cleared or destroyed. */
-static apr_status_t
-cleanup_ctx(void *data)
-{
-    serf__spnego_context_t *ctx = data;
-
-    if (SecIsValidHandle(&ctx->sspi_context)) {
-        DeleteSecurityContext(&ctx->sspi_context);
-        SecInvalidateHandle(&ctx->sspi_context);
-    }
-
-    if (SecIsValidHandle(&ctx->sspi_credentials)) {
-        FreeCredentialsHandle(&ctx->sspi_credentials);
-        SecInvalidateHandle(&ctx->sspi_credentials);
-    }
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t
-cleanup_sec_buffer(void *data)
-{
-    FreeContextBuffer(data);
-
-    return APR_SUCCESS;
-}
-
-apr_status_t
-serf__spnego_create_sec_context(serf__spnego_context_t **ctx_p,
-                                const serf__authn_scheme_t *scheme,
-                                apr_pool_t *result_pool,
-                                apr_pool_t *scratch_pool)
-{
-    SECURITY_STATUS sspi_status;
-    serf__spnego_context_t *ctx;
-    const char *sspi_package;
-
-    ctx = apr_pcalloc(result_pool, sizeof(*ctx));
-
-    SecInvalidateHandle(&ctx->sspi_context);
-    SecInvalidateHandle(&ctx->sspi_credentials);
-    ctx->initalized = FALSE;
-    ctx->pool = result_pool;
-    ctx->target_name = NULL;
-    ctx->authn_type = scheme->type;
-
-    apr_pool_cleanup_register(result_pool, ctx,
-                              cleanup_ctx,
-                              apr_pool_cleanup_null);
-
-    if (ctx->authn_type == SERF_AUTHN_NEGOTIATE)
-        sspi_package = "Negotiate";
-    else
-        sspi_package = "NTLM";
-
-    sspi_status = AcquireCredentialsHandle(
-        NULL, sspi_package, SECPKG_CRED_OUTBOUND,
-        NULL, NULL, NULL, NULL,
-        &ctx->sspi_credentials, NULL);
-
-    if (FAILED(sspi_status)) {
-        return map_sspi_status(sspi_status);
-    }
-
-    *ctx_p = ctx;
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t
-get_canonical_hostname(const char **canonname,
-                       const char *hostname,
-                       apr_pool_t *pool)
-{
-    struct addrinfo hints;
-    struct addrinfo *addrinfo;
-
-    ZeroMemory(&hints, sizeof(hints));
-    hints.ai_flags = AI_CANONNAME;
-
-    if (getaddrinfo(hostname, NULL, &hints, &addrinfo)) {
-        return apr_get_netos_error();
-    }
-
-    if (addrinfo) {
-        *canonname = apr_pstrdup(pool, addrinfo->ai_canonname);
-    }
-    else {
-        *canonname = apr_pstrdup(pool, hostname);
-    }
-
-    freeaddrinfo(addrinfo);
-    return APR_SUCCESS;
-}
-
-apr_status_t
-serf__spnego_reset_sec_context(serf__spnego_context_t *ctx)
-{
-    if (SecIsValidHandle(&ctx->sspi_context)) {
-        DeleteSecurityContext(&ctx->sspi_context);
-        SecInvalidateHandle(&ctx->sspi_context);
-    }
-
-    ctx->initalized = FALSE;
-
-    return APR_SUCCESS;
-}
-
-apr_status_t
-serf__spnego_init_sec_context(serf_connection_t *conn,
-                              serf__spnego_context_t *ctx,
-                              const char *service,
-                              const char *hostname,
-                              serf__spnego_buffer_t *input_buf,
-                              serf__spnego_buffer_t *output_buf,
-                              apr_pool_t *result_pool,
-                              apr_pool_t *scratch_pool
-                              )
-{
-    SECURITY_STATUS status;
-    ULONG actual_attr;
-    SecBuffer sspi_in_buffer;
-    SecBufferDesc sspi_in_buffer_desc;
-    SecBuffer sspi_out_buffer;
-    SecBufferDesc sspi_out_buffer_desc;
-    apr_status_t apr_status;
-    const char *canonname;
-
-    if (!ctx->initalized && ctx->authn_type == SERF_AUTHN_NEGOTIATE) {
-        apr_status = get_canonical_hostname(&canonname, hostname, scratch_pool);
-        if (apr_status) {
-            return apr_status;
-        }
-
-        ctx->target_name = apr_pstrcat(scratch_pool, service, "/", canonname,
-                                       NULL);
-
-        serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
-                      "Using SPN '%s' for '%s'\n", ctx->target_name, hostname);
-    }
-    else if (ctx->authn_type == SERF_AUTHN_NTLM)
-    {
-        /* Target name is not used for NTLM authentication. */
-        ctx->target_name = NULL;
-    }
-
-    /* Prepare input buffer description. */
-    sspi_in_buffer.BufferType = SECBUFFER_TOKEN;
-    sspi_in_buffer.pvBuffer = input_buf->value;
-    sspi_in_buffer.cbBuffer = input_buf->length; 
-
-    sspi_in_buffer_desc.cBuffers = 1;
-    sspi_in_buffer_desc.pBuffers = &sspi_in_buffer;
-    sspi_in_buffer_desc.ulVersion = SECBUFFER_VERSION;
-
-    /* Output buffers. Output buffer will be allocated by system. */
-    sspi_out_buffer.BufferType = SECBUFFER_TOKEN;
-    sspi_out_buffer.pvBuffer = NULL; 
-    sspi_out_buffer.cbBuffer = 0;
-
-    sspi_out_buffer_desc.cBuffers = 1;
-    sspi_out_buffer_desc.pBuffers = &sspi_out_buffer;
-    sspi_out_buffer_desc.ulVersion = SECBUFFER_VERSION;
-
-    status = InitializeSecurityContext(
-        &ctx->sspi_credentials,
-        ctx->initalized ? &ctx->sspi_context : NULL,
-        ctx->target_name,
-        ISC_REQ_ALLOCATE_MEMORY
-        | ISC_REQ_MUTUAL_AUTH
-        | ISC_REQ_CONFIDENTIALITY,
-        0,                          /* Reserved1 */
-        SECURITY_NETWORK_DREP,
-        &sspi_in_buffer_desc,
-        0,                          /* Reserved2 */
-        &ctx->sspi_context,
-        &sspi_out_buffer_desc,
-        &actual_attr,
-        NULL);
-
-    if (sspi_out_buffer.cbBuffer > 0) {
-        apr_pool_cleanup_register(result_pool, sspi_out_buffer.pvBuffer,
-                                  cleanup_sec_buffer,
-                                  apr_pool_cleanup_null);
-    }
-
-    ctx->initalized = TRUE;
-
-    /* Finish authentication if SSPI requires so. */
-    if (status == SEC_I_COMPLETE_NEEDED
-        || status == SEC_I_COMPLETE_AND_CONTINUE)
-    {
-        CompleteAuthToken(&ctx->sspi_context, &sspi_out_buffer_desc);
-    }
-
-    output_buf->value = sspi_out_buffer.pvBuffer;
-    output_buf->length = sspi_out_buffer.cbBuffer;
-
-    switch(status) {
-    case SEC_I_COMPLETE_AND_CONTINUE:
-    case SEC_I_CONTINUE_NEEDED:
-        return APR_EAGAIN;
-
-    case SEC_I_COMPLETE_NEEDED:
-    case SEC_E_OK:
-        return APR_SUCCESS;
-
-    default:
-        return map_sspi_status(status);
-    }
-}
-
-#endif /* SERF_USE_SSPI */

Copied: vendor/serf/1.3.9/auth/auth_spnego_sspi.c (from rev 9259, vendor/serf/dist/auth/auth_spnego_sspi.c)
===================================================================
--- vendor/serf/1.3.9/auth/auth_spnego_sspi.c	                        (rev 0)
+++ vendor/serf/1.3.9/auth/auth_spnego_sspi.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,303 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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 "auth_spnego.h"
+#include "serf.h"
+#include "serf_private.h"
+
+#ifdef SERF_USE_SSPI
+#include <apr.h>
+#include <apr_strings.h>
+
+#define SECURITY_WIN32
+#include <sspi.h>
+
+/* SEC_E_MUTUAL_AUTH_FAILED is not defined in Windows Platform SDK 5.0. */
+#ifndef SEC_E_MUTUAL_AUTH_FAILED
+#define SEC_E_MUTUAL_AUTH_FAILED _HRESULT_TYPEDEF_(0x80090363L)
+#endif
+
+struct serf__spnego_context_t
+{
+    CredHandle sspi_credentials;
+    CtxtHandle sspi_context;
+    BOOL initalized;
+    apr_pool_t *pool;
+
+    /* Service Principal Name (SPN) used for authentication. */
+    const char *target_name;
+
+    /* One of SERF_AUTHN_* authentication types.*/
+    int authn_type;
+};
+
+/* Map SECURITY_STATUS from SSPI to APR error code. Some error codes mapped
+ * to our own codes and some to Win32 error codes:
+ * http://support.microsoft.com/kb/113996
+ */
+static apr_status_t
+map_sspi_status(SECURITY_STATUS sspi_status)
+{
+    switch(sspi_status)
+    {
+    case SEC_E_INSUFFICIENT_MEMORY:
+        return APR_FROM_OS_ERROR(ERROR_NO_SYSTEM_RESOURCES);
+    case SEC_E_INVALID_HANDLE:
+        return APR_FROM_OS_ERROR(ERROR_INVALID_HANDLE);
+    case SEC_E_UNSUPPORTED_FUNCTION:
+        return APR_FROM_OS_ERROR(ERROR_INVALID_FUNCTION);
+    case SEC_E_TARGET_UNKNOWN:
+        return APR_FROM_OS_ERROR(ERROR_BAD_NETPATH);
+    case SEC_E_INTERNAL_ERROR:
+        return APR_FROM_OS_ERROR(ERROR_INTERNAL_ERROR);
+    case SEC_E_SECPKG_NOT_FOUND:
+    case SEC_E_BAD_PKGID:
+        return APR_FROM_OS_ERROR(ERROR_NO_SUCH_PACKAGE);
+    case SEC_E_NO_IMPERSONATION:
+        return APR_FROM_OS_ERROR(ERROR_CANNOT_IMPERSONATE);
+    case SEC_E_NO_AUTHENTICATING_AUTHORITY:
+        return APR_FROM_OS_ERROR(ERROR_NO_LOGON_SERVERS);
+    case SEC_E_UNTRUSTED_ROOT:
+        return APR_FROM_OS_ERROR(ERROR_TRUST_FAILURE);
+    case SEC_E_WRONG_PRINCIPAL:
+        return APR_FROM_OS_ERROR(ERROR_WRONG_TARGET_NAME);
+    case SEC_E_MUTUAL_AUTH_FAILED:
+        return APR_FROM_OS_ERROR(ERROR_MUTUAL_AUTH_FAILED);
+    case SEC_E_TIME_SKEW:
+        return APR_FROM_OS_ERROR(ERROR_TIME_SKEW);
+    default:
+        return SERF_ERROR_AUTHN_FAILED;
+    }
+}
+
+/* Cleans the SSPI context object, when the pool used to create it gets
+   cleared or destroyed. */
+static apr_status_t
+cleanup_ctx(void *data)
+{
+    serf__spnego_context_t *ctx = data;
+
+    if (SecIsValidHandle(&ctx->sspi_context)) {
+        DeleteSecurityContext(&ctx->sspi_context);
+        SecInvalidateHandle(&ctx->sspi_context);
+    }
+
+    if (SecIsValidHandle(&ctx->sspi_credentials)) {
+        FreeCredentialsHandle(&ctx->sspi_credentials);
+        SecInvalidateHandle(&ctx->sspi_credentials);
+    }
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t
+cleanup_sec_buffer(void *data)
+{
+    FreeContextBuffer(data);
+
+    return APR_SUCCESS;
+}
+
+apr_status_t
+serf__spnego_create_sec_context(serf__spnego_context_t **ctx_p,
+                                const serf__authn_scheme_t *scheme,
+                                apr_pool_t *result_pool,
+                                apr_pool_t *scratch_pool)
+{
+    SECURITY_STATUS sspi_status;
+    serf__spnego_context_t *ctx;
+    const char *sspi_package;
+
+    ctx = apr_pcalloc(result_pool, sizeof(*ctx));
+
+    SecInvalidateHandle(&ctx->sspi_context);
+    SecInvalidateHandle(&ctx->sspi_credentials);
+    ctx->initalized = FALSE;
+    ctx->pool = result_pool;
+    ctx->target_name = NULL;
+    ctx->authn_type = scheme->type;
+
+    apr_pool_cleanup_register(result_pool, ctx,
+                              cleanup_ctx,
+                              apr_pool_cleanup_null);
+
+    if (ctx->authn_type == SERF_AUTHN_NEGOTIATE)
+        sspi_package = "Negotiate";
+    else
+        sspi_package = "NTLM";
+
+    sspi_status = AcquireCredentialsHandleA(
+        NULL, sspi_package, SECPKG_CRED_OUTBOUND,
+        NULL, NULL, NULL, NULL,
+        &ctx->sspi_credentials, NULL);
+
+    if (FAILED(sspi_status)) {
+        return map_sspi_status(sspi_status);
+    }
+
+    *ctx_p = ctx;
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t
+get_canonical_hostname(const char **canonname,
+                       const char *hostname,
+                       apr_pool_t *pool)
+{
+    struct addrinfo hints;
+    struct addrinfo *addrinfo;
+
+    ZeroMemory(&hints, sizeof(hints));
+    hints.ai_flags = AI_CANONNAME;
+
+    if (getaddrinfo(hostname, NULL, &hints, &addrinfo)) {
+        return apr_get_netos_error();
+    }
+
+    if (addrinfo) {
+        *canonname = apr_pstrdup(pool, addrinfo->ai_canonname);
+    }
+    else {
+        *canonname = apr_pstrdup(pool, hostname);
+    }
+
+    freeaddrinfo(addrinfo);
+    return APR_SUCCESS;
+}
+
+apr_status_t
+serf__spnego_reset_sec_context(serf__spnego_context_t *ctx)
+{
+    if (SecIsValidHandle(&ctx->sspi_context)) {
+        DeleteSecurityContext(&ctx->sspi_context);
+        SecInvalidateHandle(&ctx->sspi_context);
+    }
+
+    ctx->initalized = FALSE;
+
+    return APR_SUCCESS;
+}
+
+apr_status_t
+serf__spnego_init_sec_context(serf_connection_t *conn,
+                              serf__spnego_context_t *ctx,
+                              const char *service,
+                              const char *hostname,
+                              serf__spnego_buffer_t *input_buf,
+                              serf__spnego_buffer_t *output_buf,
+                              apr_pool_t *result_pool,
+                              apr_pool_t *scratch_pool
+                              )
+{
+    SECURITY_STATUS status;
+    ULONG actual_attr;
+    SecBuffer sspi_in_buffer;
+    SecBufferDesc sspi_in_buffer_desc;
+    SecBuffer sspi_out_buffer;
+    SecBufferDesc sspi_out_buffer_desc;
+    apr_status_t apr_status;
+    const char *canonname;
+
+    if (!ctx->initalized && ctx->authn_type == SERF_AUTHN_NEGOTIATE) {
+        apr_status = get_canonical_hostname(&canonname, hostname, scratch_pool);
+        if (apr_status) {
+            return apr_status;
+        }
+
+        ctx->target_name = apr_pstrcat(scratch_pool, service, "/", canonname,
+                                       NULL);
+
+        serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
+                      "Using SPN '%s' for '%s'\n", ctx->target_name, hostname);
+    }
+    else if (ctx->authn_type == SERF_AUTHN_NTLM)
+    {
+        /* Target name is not used for NTLM authentication. */
+        ctx->target_name = NULL;
+    }
+
+    /* Prepare input buffer description. */
+    sspi_in_buffer.BufferType = SECBUFFER_TOKEN;
+    sspi_in_buffer.pvBuffer = input_buf->value;
+    sspi_in_buffer.cbBuffer = input_buf->length; 
+
+    sspi_in_buffer_desc.cBuffers = 1;
+    sspi_in_buffer_desc.pBuffers = &sspi_in_buffer;
+    sspi_in_buffer_desc.ulVersion = SECBUFFER_VERSION;
+
+    /* Output buffers. Output buffer will be allocated by system. */
+    sspi_out_buffer.BufferType = SECBUFFER_TOKEN;
+    sspi_out_buffer.pvBuffer = NULL; 
+    sspi_out_buffer.cbBuffer = 0;
+
+    sspi_out_buffer_desc.cBuffers = 1;
+    sspi_out_buffer_desc.pBuffers = &sspi_out_buffer;
+    sspi_out_buffer_desc.ulVersion = SECBUFFER_VERSION;
+
+    status = InitializeSecurityContextA(
+        &ctx->sspi_credentials,
+        ctx->initalized ? &ctx->sspi_context : NULL,
+        ctx->target_name,
+        ISC_REQ_ALLOCATE_MEMORY
+        | ISC_REQ_MUTUAL_AUTH
+        | ISC_REQ_CONFIDENTIALITY,
+        0,                          /* Reserved1 */
+        SECURITY_NETWORK_DREP,
+        &sspi_in_buffer_desc,
+        0,                          /* Reserved2 */
+        &ctx->sspi_context,
+        &sspi_out_buffer_desc,
+        &actual_attr,
+        NULL);
+
+    if (sspi_out_buffer.cbBuffer > 0) {
+        apr_pool_cleanup_register(result_pool, sspi_out_buffer.pvBuffer,
+                                  cleanup_sec_buffer,
+                                  apr_pool_cleanup_null);
+    }
+
+    ctx->initalized = TRUE;
+
+    /* Finish authentication if SSPI requires so. */
+    if (status == SEC_I_COMPLETE_NEEDED
+        || status == SEC_I_COMPLETE_AND_CONTINUE)
+    {
+        CompleteAuthToken(&ctx->sspi_context, &sspi_out_buffer_desc);
+    }
+
+    output_buf->value = sspi_out_buffer.pvBuffer;
+    output_buf->length = sspi_out_buffer.cbBuffer;
+
+    switch(status) {
+    case SEC_I_COMPLETE_AND_CONTINUE:
+    case SEC_I_CONTINUE_NEEDED:
+        return APR_EAGAIN;
+
+    case SEC_I_COMPLETE_NEEDED:
+    case SEC_E_OK:
+        return APR_SUCCESS;
+
+    default:
+        return map_sspi_status(status);
+    }
+}
+
+#endif /* SERF_USE_SSPI */

Deleted: vendor/serf/1.3.9/buckets/aggregate_buckets.c
===================================================================
--- vendor/serf/dist/buckets/aggregate_buckets.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/buckets/aggregate_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,488 +0,0 @@
-/* Copyright 2002-2004 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 "serf.h"
-#include "serf_bucket_util.h"
-
-
-/* Should be an APR_RING? */
-typedef struct bucket_list {
-    serf_bucket_t *bucket;
-    struct bucket_list *next;
-} bucket_list_t;
-
-typedef struct {
-    bucket_list_t *list; /* active buckets */
-    bucket_list_t *last; /* last bucket of the list */
-    bucket_list_t *done; /* we finished reading this; now pending a destroy */
-
-    serf_bucket_aggregate_eof_t hold_open;
-    void *hold_open_baton;
-
-    /* Does this bucket own its children? !0 if yes, 0 if not. */
-    int bucket_owner;
-} aggregate_context_t;
-
-
-static void cleanup_aggregate(aggregate_context_t *ctx,
-                              serf_bucket_alloc_t *allocator)
-{
-    bucket_list_t *next_list;
-
-    /* If we finished reading a bucket during the previous read, then
-     * we can now toss that bucket.
-     */
-    while (ctx->done != NULL) {
-        next_list = ctx->done->next;
-
-        if (ctx->bucket_owner) {
-            serf_bucket_destroy(ctx->done->bucket);
-        }
-        serf_bucket_mem_free(allocator, ctx->done);
-
-        ctx->done = next_list;
-    }
-}
-
-void serf_bucket_aggregate_cleanup(
-    serf_bucket_t *bucket, serf_bucket_alloc_t *allocator)
-{
-    aggregate_context_t *ctx = bucket->data;
-
-    cleanup_aggregate(ctx, allocator);
-}
-
-static aggregate_context_t *create_aggregate(serf_bucket_alloc_t *allocator)
-{
-    aggregate_context_t *ctx;
-
-    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
-
-    ctx->list = NULL;
-    ctx->last = NULL;
-    ctx->done = NULL;
-    ctx->hold_open = NULL;
-    ctx->hold_open_baton = NULL;
-    ctx->bucket_owner = 1;
-
-    return ctx;
-}
-
-serf_bucket_t *serf_bucket_aggregate_create(
-    serf_bucket_alloc_t *allocator)
-{
-    aggregate_context_t *ctx;
-
-    ctx = create_aggregate(allocator);
-
-    return serf_bucket_create(&serf_bucket_type_aggregate, allocator, ctx);
-}
-
-serf_bucket_t *serf__bucket_stream_create(
-    serf_bucket_alloc_t *allocator,
-    serf_bucket_aggregate_eof_t fn,
-    void *baton)
-{
-    serf_bucket_t *bucket = serf_bucket_aggregate_create(allocator);
-    aggregate_context_t *ctx = bucket->data;
-
-    serf_bucket_aggregate_hold_open(bucket, fn, baton);
-
-    ctx->bucket_owner = 0;
-
-    return bucket;
-}
-
-
-static void serf_aggregate_destroy_and_data(serf_bucket_t *bucket)
-{
-    aggregate_context_t *ctx = bucket->data;
-    bucket_list_t *next_ctx;
-
-    while (ctx->list) {
-        if (ctx->bucket_owner) {
-            serf_bucket_destroy(ctx->list->bucket);
-        }
-        next_ctx = ctx->list->next;
-        serf_bucket_mem_free(bucket->allocator, ctx->list);
-        ctx->list = next_ctx;
-    }
-    cleanup_aggregate(ctx, bucket->allocator);
-
-    serf_default_destroy_and_data(bucket);
-}
-
-void serf_bucket_aggregate_become(serf_bucket_t *bucket)
-{
-    aggregate_context_t *ctx;
-
-    ctx = create_aggregate(bucket->allocator);
-
-    bucket->type = &serf_bucket_type_aggregate;
-    bucket->data = ctx;
-
-    /* The allocator remains the same. */
-}
-
-
-void serf_bucket_aggregate_prepend(
-    serf_bucket_t *aggregate_bucket,
-    serf_bucket_t *prepend_bucket)
-{
-    aggregate_context_t *ctx = aggregate_bucket->data;
-    bucket_list_t *new_list;
-
-    new_list = serf_bucket_mem_alloc(aggregate_bucket->allocator,
-                                     sizeof(*new_list));
-    new_list->bucket = prepend_bucket;
-    new_list->next = ctx->list;
-
-    ctx->list = new_list;
-}
-
-void serf_bucket_aggregate_append(
-    serf_bucket_t *aggregate_bucket,
-    serf_bucket_t *append_bucket)
-{
-    aggregate_context_t *ctx = aggregate_bucket->data;
-    bucket_list_t *new_list;
-
-    new_list = serf_bucket_mem_alloc(aggregate_bucket->allocator,
-                                     sizeof(*new_list));
-    new_list->bucket = append_bucket;
-    new_list->next = NULL;
-
-    /* If we use APR_RING, this is trivial.  So, wait.
-    new_list->next = ctx->list;
-    ctx->list = new_list;
-    */
-    if (ctx->list == NULL) {
-        ctx->list = new_list;
-        ctx->last = new_list;
-    }
-    else {
-        ctx->last->next = new_list;
-        ctx->last = ctx->last->next;
-    }
-}
-
-void serf_bucket_aggregate_hold_open(serf_bucket_t *aggregate_bucket, 
-                                     serf_bucket_aggregate_eof_t fn,
-                                     void *baton)
-{
-    aggregate_context_t *ctx = aggregate_bucket->data;
-    ctx->hold_open = fn;
-    ctx->hold_open_baton = baton;
-}
-
-void serf_bucket_aggregate_prepend_iovec(
-    serf_bucket_t *aggregate_bucket,
-    struct iovec *vecs,
-    int vecs_count)
-{
-    int i;
-
-    /* Add in reverse order. */
-    for (i = vecs_count - 1; i >= 0; i--) {
-        serf_bucket_t *new_bucket;
-
-        new_bucket = serf_bucket_simple_create(vecs[i].iov_base,
-                                               vecs[i].iov_len,
-                                               NULL, NULL,
-                                               aggregate_bucket->allocator);
-
-        serf_bucket_aggregate_prepend(aggregate_bucket, new_bucket);
-
-    }
-}
-
-void serf_bucket_aggregate_append_iovec(
-    serf_bucket_t *aggregate_bucket,
-    struct iovec *vecs,
-    int vecs_count)
-{
-    serf_bucket_t *new_bucket;
-
-    new_bucket = serf_bucket_iovec_create(vecs, vecs_count,
-                                          aggregate_bucket->allocator);
-
-    serf_bucket_aggregate_append(aggregate_bucket, new_bucket);
-}
-
-static apr_status_t read_aggregate(serf_bucket_t *bucket,
-                                   apr_size_t requested,
-                                   int vecs_size, struct iovec *vecs,
-                                   int *vecs_used)
-{
-    aggregate_context_t *ctx = bucket->data;
-    int cur_vecs_used;
-    apr_status_t status;
-
-    *vecs_used = 0;
-
-    if (!ctx->list) {
-        if (ctx->hold_open) {
-            return ctx->hold_open(ctx->hold_open_baton, bucket);
-        }
-        else {
-            return APR_EOF;
-        }
-    }
-
-    status = APR_SUCCESS;
-    while (requested) {
-        serf_bucket_t *head = ctx->list->bucket;
-
-        status = serf_bucket_read_iovec(head, requested, vecs_size, vecs,
-                                        &cur_vecs_used);
-
-        if (SERF_BUCKET_READ_ERROR(status))
-            return status;
-
-        /* Add the number of vecs we read to our running total. */
-        *vecs_used += cur_vecs_used;
-
-        if (cur_vecs_used > 0 || status) {
-            bucket_list_t *next_list;
-
-            /* If we got SUCCESS (w/bytes) or EAGAIN, we want to return now
-             * as it isn't safe to read more without returning to our caller.
-             */
-            if (!status || APR_STATUS_IS_EAGAIN(status) || status == SERF_ERROR_WAIT_CONN) {
-                return status;
-            }
-
-            /* However, if we read EOF, we can stash this bucket in a
-             * to-be-freed list and move on to the next bucket.  This ensures
-             * that the bucket stays alive (so as not to violate our read
-             * semantics).  We'll destroy this list of buckets the next time
-             * we are asked to perform a read operation - thus ensuring the
-             * proper read lifetime.
-             */
-            next_list = ctx->list->next;
-            ctx->list->next = ctx->done;
-            ctx->done = ctx->list;
-            ctx->list = next_list;
-
-            /* If we have no more in our list, return EOF. */
-            if (!ctx->list) {
-                if (ctx->hold_open) {
-                    return ctx->hold_open(ctx->hold_open_baton, bucket);
-                }
-                else {
-                    return APR_EOF;
-                }
-            }
-
-            /* At this point, it safe to read the next bucket - if we can. */
-
-            /* If the caller doesn't want ALL_AVAIL, decrement the size
-             * of the items we just read from the list.
-             */
-            if (requested != SERF_READ_ALL_AVAIL) {
-                int i;
-
-                for (i = 0; i < cur_vecs_used; i++)
-                    requested -= vecs[i].iov_len;
-            }
-
-            /* Adjust our vecs to account for what we just read. */
-            vecs_size -= cur_vecs_used;
-            vecs += cur_vecs_used;
-
-            /* We reached our max.  Oh well. */
-            if (!requested || !vecs_size) {
-                return APR_SUCCESS;
-            }
-        }
-    }
-
-    return status;
-}
-
-static apr_status_t serf_aggregate_read(serf_bucket_t *bucket,
-                                        apr_size_t requested,
-                                        const char **data, apr_size_t *len)
-{
-    aggregate_context_t *ctx = bucket->data;
-    struct iovec vec;
-    int vecs_used;
-    apr_status_t status;
-
-    cleanup_aggregate(ctx, bucket->allocator);
-
-    status = read_aggregate(bucket, requested, 1, &vec, &vecs_used);
-
-    if (!vecs_used) {
-        *len = 0;
-    }
-    else {
-        *data = vec.iov_base;
-        *len = vec.iov_len;
-    }
-
-    return status;
-}
-
-static apr_status_t serf_aggregate_read_iovec(serf_bucket_t *bucket,
-                                              apr_size_t requested,
-                                              int vecs_size,
-                                              struct iovec *vecs,
-                                              int *vecs_used)
-{
-    aggregate_context_t *ctx = bucket->data;
-
-    cleanup_aggregate(ctx, bucket->allocator);
-
-    return read_aggregate(bucket, requested, vecs_size, vecs, vecs_used);
-}
-
-static apr_status_t serf_aggregate_readline(serf_bucket_t *bucket,
-                                            int acceptable, int *found,
-                                            const char **data, apr_size_t *len)
-{
-    aggregate_context_t *ctx = bucket->data;
-    apr_status_t status;
-
-    cleanup_aggregate(ctx, bucket->allocator);
-
-    do {
-        serf_bucket_t *head;
-
-        *len = 0;
-
-        if (!ctx->list) {
-            if (ctx->hold_open) {
-                return ctx->hold_open(ctx->hold_open_baton, bucket);
-            }
-            else {
-                return APR_EOF;
-            }
-        }
-
-        head = ctx->list->bucket;
-
-        status = serf_bucket_readline(head, acceptable, found,
-                                      data, len);
-        if (SERF_BUCKET_READ_ERROR(status))
-            return status;
-
-        if (status == APR_EOF) {
-            bucket_list_t *next_list;
-
-            /* head bucket is empty, move to to-be-cleaned-up list. */
-            next_list = ctx->list->next;
-            ctx->list->next = ctx->done;
-            ctx->done = ctx->list;
-            ctx->list = next_list;
-
-            /* If we have no more in our list, return EOF. */
-            if (!ctx->list) {
-                if (ctx->hold_open) {
-                    return ctx->hold_open(ctx->hold_open_baton, bucket);
-                }
-                else {
-                    return APR_EOF;
-                }
-            }
-
-            /* we read something, so bail out and let the appl. read again. */
-            if (*len)
-                status = APR_SUCCESS;
-        }
-
-        /* continue with APR_SUCCESS or APR_EOF and no data read yet. */
-    } while (!*len && status != APR_EAGAIN);
-
-    return status;
-}
-
-static apr_status_t serf_aggregate_peek(serf_bucket_t *bucket,
-                                        const char **data,
-                                        apr_size_t *len)
-{
-    aggregate_context_t *ctx = bucket->data;
-    serf_bucket_t *head;
-    apr_status_t status;
-
-    cleanup_aggregate(ctx, bucket->allocator);
-
-    /* Peek the first bucket in the list, if any. */
-    if (!ctx->list) {
-        *len = 0;
-        if (ctx->hold_open) {
-            status = ctx->hold_open(ctx->hold_open_baton, bucket);
-            if (status == APR_EAGAIN)
-                status = APR_SUCCESS;
-            return status;
-        }
-        else {
-            return APR_EOF;
-        }
-    }
-
-    head = ctx->list->bucket;
-
-    status = serf_bucket_peek(head, data, len);
-
-    if (status == APR_EOF) {
-        if (ctx->list->next) {
-            status = APR_SUCCESS;
-        } else {
-            if (ctx->hold_open) {
-                status = ctx->hold_open(ctx->hold_open_baton, bucket);
-                if (status == APR_EAGAIN)
-                    status = APR_SUCCESS;
-                return status;
-            }
-        }
-    }
-
-    return status;
-}
-
-static serf_bucket_t * serf_aggregate_read_bucket(
-    serf_bucket_t *bucket,
-    const serf_bucket_type_t *type)
-{
-    aggregate_context_t *ctx = bucket->data;
-    serf_bucket_t *found_bucket;
-
-    if (!ctx->list) {
-        return NULL;
-    }
-
-    if (ctx->list->bucket->type == type) {
-        /* Got the bucket. Consume it from our list. */
-        found_bucket = ctx->list->bucket;
-        ctx->list = ctx->list->next;
-        return found_bucket;
-    }
-
-    /* Call read_bucket on first one in our list. */
-    return serf_bucket_read_bucket(ctx->list->bucket, type);
-}
-
-
-const serf_bucket_type_t serf_bucket_type_aggregate = {
-    "AGGREGATE",
-    serf_aggregate_read,
-    serf_aggregate_readline,
-    serf_aggregate_read_iovec,
-    serf_default_read_for_sendfile,
-    serf_aggregate_read_bucket,
-    serf_aggregate_peek,
-    serf_aggregate_destroy_and_data,
-};

Copied: vendor/serf/1.3.9/buckets/aggregate_buckets.c (from rev 9259, vendor/serf/dist/buckets/aggregate_buckets.c)
===================================================================
--- vendor/serf/1.3.9/buckets/aggregate_buckets.c	                        (rev 0)
+++ vendor/serf/1.3.9/buckets/aggregate_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,493 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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 "serf.h"
+#include "serf_bucket_util.h"
+
+
+/* Should be an APR_RING? */
+typedef struct bucket_list {
+    serf_bucket_t *bucket;
+    struct bucket_list *next;
+} bucket_list_t;
+
+typedef struct {
+    bucket_list_t *list; /* active buckets */
+    bucket_list_t *last; /* last bucket of the list */
+    bucket_list_t *done; /* we finished reading this; now pending a destroy */
+
+    serf_bucket_aggregate_eof_t hold_open;
+    void *hold_open_baton;
+
+    /* Does this bucket own its children? !0 if yes, 0 if not. */
+    int bucket_owner;
+} aggregate_context_t;
+
+
+static void cleanup_aggregate(aggregate_context_t *ctx,
+                              serf_bucket_alloc_t *allocator)
+{
+    bucket_list_t *next_list;
+
+    /* If we finished reading a bucket during the previous read, then
+     * we can now toss that bucket.
+     */
+    while (ctx->done != NULL) {
+        next_list = ctx->done->next;
+
+        if (ctx->bucket_owner) {
+            serf_bucket_destroy(ctx->done->bucket);
+        }
+        serf_bucket_mem_free(allocator, ctx->done);
+
+        ctx->done = next_list;
+    }
+}
+
+void serf_bucket_aggregate_cleanup(
+    serf_bucket_t *bucket, serf_bucket_alloc_t *allocator)
+{
+    aggregate_context_t *ctx = bucket->data;
+
+    cleanup_aggregate(ctx, allocator);
+}
+
+static aggregate_context_t *create_aggregate(serf_bucket_alloc_t *allocator)
+{
+    aggregate_context_t *ctx;
+
+    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
+
+    ctx->list = NULL;
+    ctx->last = NULL;
+    ctx->done = NULL;
+    ctx->hold_open = NULL;
+    ctx->hold_open_baton = NULL;
+    ctx->bucket_owner = 1;
+
+    return ctx;
+}
+
+serf_bucket_t *serf_bucket_aggregate_create(
+    serf_bucket_alloc_t *allocator)
+{
+    aggregate_context_t *ctx;
+
+    ctx = create_aggregate(allocator);
+
+    return serf_bucket_create(&serf_bucket_type_aggregate, allocator, ctx);
+}
+
+serf_bucket_t *serf__bucket_stream_create(
+    serf_bucket_alloc_t *allocator,
+    serf_bucket_aggregate_eof_t fn,
+    void *baton)
+{
+    serf_bucket_t *bucket = serf_bucket_aggregate_create(allocator);
+    aggregate_context_t *ctx = bucket->data;
+
+    serf_bucket_aggregate_hold_open(bucket, fn, baton);
+
+    ctx->bucket_owner = 0;
+
+    return bucket;
+}
+
+
+static void serf_aggregate_destroy_and_data(serf_bucket_t *bucket)
+{
+    aggregate_context_t *ctx = bucket->data;
+    bucket_list_t *next_ctx;
+
+    while (ctx->list) {
+        if (ctx->bucket_owner) {
+            serf_bucket_destroy(ctx->list->bucket);
+        }
+        next_ctx = ctx->list->next;
+        serf_bucket_mem_free(bucket->allocator, ctx->list);
+        ctx->list = next_ctx;
+    }
+    cleanup_aggregate(ctx, bucket->allocator);
+
+    serf_default_destroy_and_data(bucket);
+}
+
+void serf_bucket_aggregate_become(serf_bucket_t *bucket)
+{
+    aggregate_context_t *ctx;
+
+    ctx = create_aggregate(bucket->allocator);
+
+    bucket->type = &serf_bucket_type_aggregate;
+    bucket->data = ctx;
+
+    /* The allocator remains the same. */
+}
+
+
+void serf_bucket_aggregate_prepend(
+    serf_bucket_t *aggregate_bucket,
+    serf_bucket_t *prepend_bucket)
+{
+    aggregate_context_t *ctx = aggregate_bucket->data;
+    bucket_list_t *new_list;
+
+    new_list = serf_bucket_mem_alloc(aggregate_bucket->allocator,
+                                     sizeof(*new_list));
+    new_list->bucket = prepend_bucket;
+    new_list->next = ctx->list;
+
+    ctx->list = new_list;
+}
+
+void serf_bucket_aggregate_append(
+    serf_bucket_t *aggregate_bucket,
+    serf_bucket_t *append_bucket)
+{
+    aggregate_context_t *ctx = aggregate_bucket->data;
+    bucket_list_t *new_list;
+
+    new_list = serf_bucket_mem_alloc(aggregate_bucket->allocator,
+                                     sizeof(*new_list));
+    new_list->bucket = append_bucket;
+    new_list->next = NULL;
+
+    /* If we use APR_RING, this is trivial.  So, wait.
+    new_list->next = ctx->list;
+    ctx->list = new_list;
+    */
+    if (ctx->list == NULL) {
+        ctx->list = new_list;
+        ctx->last = new_list;
+    }
+    else {
+        ctx->last->next = new_list;
+        ctx->last = ctx->last->next;
+    }
+}
+
+void serf_bucket_aggregate_hold_open(serf_bucket_t *aggregate_bucket, 
+                                     serf_bucket_aggregate_eof_t fn,
+                                     void *baton)
+{
+    aggregate_context_t *ctx = aggregate_bucket->data;
+    ctx->hold_open = fn;
+    ctx->hold_open_baton = baton;
+}
+
+void serf_bucket_aggregate_prepend_iovec(
+    serf_bucket_t *aggregate_bucket,
+    struct iovec *vecs,
+    int vecs_count)
+{
+    int i;
+
+    /* Add in reverse order. */
+    for (i = vecs_count - 1; i >= 0; i--) {
+        serf_bucket_t *new_bucket;
+
+        new_bucket = serf_bucket_simple_create(vecs[i].iov_base,
+                                               vecs[i].iov_len,
+                                               NULL, NULL,
+                                               aggregate_bucket->allocator);
+
+        serf_bucket_aggregate_prepend(aggregate_bucket, new_bucket);
+
+    }
+}
+
+void serf_bucket_aggregate_append_iovec(
+    serf_bucket_t *aggregate_bucket,
+    struct iovec *vecs,
+    int vecs_count)
+{
+    serf_bucket_t *new_bucket;
+
+    new_bucket = serf_bucket_iovec_create(vecs, vecs_count,
+                                          aggregate_bucket->allocator);
+
+    serf_bucket_aggregate_append(aggregate_bucket, new_bucket);
+}
+
+static apr_status_t read_aggregate(serf_bucket_t *bucket,
+                                   apr_size_t requested,
+                                   int vecs_size, struct iovec *vecs,
+                                   int *vecs_used)
+{
+    aggregate_context_t *ctx = bucket->data;
+    int cur_vecs_used;
+    apr_status_t status;
+
+    *vecs_used = 0;
+
+    if (!ctx->list) {
+        if (ctx->hold_open) {
+            return ctx->hold_open(ctx->hold_open_baton, bucket);
+        }
+        else {
+            return APR_EOF;
+        }
+    }
+
+    status = APR_SUCCESS;
+    while (requested) {
+        serf_bucket_t *head = ctx->list->bucket;
+
+        status = serf_bucket_read_iovec(head, requested, vecs_size, vecs,
+                                        &cur_vecs_used);
+
+        if (SERF_BUCKET_READ_ERROR(status))
+            return status;
+
+        /* Add the number of vecs we read to our running total. */
+        *vecs_used += cur_vecs_used;
+
+        if (cur_vecs_used > 0 || status) {
+            bucket_list_t *next_list;
+
+            /* If we got SUCCESS (w/bytes) or EAGAIN, we want to return now
+             * as it isn't safe to read more without returning to our caller.
+             */
+            if (!status || APR_STATUS_IS_EAGAIN(status) || status == SERF_ERROR_WAIT_CONN) {
+                return status;
+            }
+
+            /* However, if we read EOF, we can stash this bucket in a
+             * to-be-freed list and move on to the next bucket.  This ensures
+             * that the bucket stays alive (so as not to violate our read
+             * semantics).  We'll destroy this list of buckets the next time
+             * we are asked to perform a read operation - thus ensuring the
+             * proper read lifetime.
+             */
+            next_list = ctx->list->next;
+            ctx->list->next = ctx->done;
+            ctx->done = ctx->list;
+            ctx->list = next_list;
+
+            /* If we have no more in our list, return EOF. */
+            if (!ctx->list) {
+                if (ctx->hold_open) {
+                    return ctx->hold_open(ctx->hold_open_baton, bucket);
+                }
+                else {
+                    return APR_EOF;
+                }
+            }
+
+            /* At this point, it safe to read the next bucket - if we can. */
+
+            /* If the caller doesn't want ALL_AVAIL, decrement the size
+             * of the items we just read from the list.
+             */
+            if (requested != SERF_READ_ALL_AVAIL) {
+                int i;
+
+                for (i = 0; i < cur_vecs_used; i++)
+                    requested -= vecs[i].iov_len;
+            }
+
+            /* Adjust our vecs to account for what we just read. */
+            vecs_size -= cur_vecs_used;
+            vecs += cur_vecs_used;
+
+            /* We reached our max.  Oh well. */
+            if (!requested || !vecs_size) {
+                return APR_SUCCESS;
+            }
+        }
+    }
+
+    return status;
+}
+
+static apr_status_t serf_aggregate_read(serf_bucket_t *bucket,
+                                        apr_size_t requested,
+                                        const char **data, apr_size_t *len)
+{
+    aggregate_context_t *ctx = bucket->data;
+    struct iovec vec;
+    int vecs_used;
+    apr_status_t status;
+
+    cleanup_aggregate(ctx, bucket->allocator);
+
+    status = read_aggregate(bucket, requested, 1, &vec, &vecs_used);
+
+    if (!vecs_used) {
+        *len = 0;
+    }
+    else {
+        *data = vec.iov_base;
+        *len = vec.iov_len;
+    }
+
+    return status;
+}
+
+static apr_status_t serf_aggregate_read_iovec(serf_bucket_t *bucket,
+                                              apr_size_t requested,
+                                              int vecs_size,
+                                              struct iovec *vecs,
+                                              int *vecs_used)
+{
+    aggregate_context_t *ctx = bucket->data;
+
+    cleanup_aggregate(ctx, bucket->allocator);
+
+    return read_aggregate(bucket, requested, vecs_size, vecs, vecs_used);
+}
+
+static apr_status_t serf_aggregate_readline(serf_bucket_t *bucket,
+                                            int acceptable, int *found,
+                                            const char **data, apr_size_t *len)
+{
+    aggregate_context_t *ctx = bucket->data;
+    apr_status_t status;
+
+    cleanup_aggregate(ctx, bucket->allocator);
+
+    do {
+        serf_bucket_t *head;
+
+        *len = 0;
+
+        if (!ctx->list) {
+            if (ctx->hold_open) {
+                return ctx->hold_open(ctx->hold_open_baton, bucket);
+            }
+            else {
+                return APR_EOF;
+            }
+        }
+
+        head = ctx->list->bucket;
+
+        status = serf_bucket_readline(head, acceptable, found,
+                                      data, len);
+        if (SERF_BUCKET_READ_ERROR(status))
+            return status;
+
+        if (status == APR_EOF) {
+            bucket_list_t *next_list;
+
+            /* head bucket is empty, move to to-be-cleaned-up list. */
+            next_list = ctx->list->next;
+            ctx->list->next = ctx->done;
+            ctx->done = ctx->list;
+            ctx->list = next_list;
+
+            /* If we have no more in our list, return EOF. */
+            if (!ctx->list) {
+                if (ctx->hold_open) {
+                    return ctx->hold_open(ctx->hold_open_baton, bucket);
+                }
+                else {
+                    return APR_EOF;
+                }
+            }
+
+            /* we read something, so bail out and let the appl. read again. */
+            if (*len)
+                status = APR_SUCCESS;
+        }
+
+        /* continue with APR_SUCCESS or APR_EOF and no data read yet. */
+    } while (!*len && status != APR_EAGAIN);
+
+    return status;
+}
+
+static apr_status_t serf_aggregate_peek(serf_bucket_t *bucket,
+                                        const char **data,
+                                        apr_size_t *len)
+{
+    aggregate_context_t *ctx = bucket->data;
+    serf_bucket_t *head;
+    apr_status_t status;
+
+    cleanup_aggregate(ctx, bucket->allocator);
+
+    /* Peek the first bucket in the list, if any. */
+    if (!ctx->list) {
+        *len = 0;
+        if (ctx->hold_open) {
+            status = ctx->hold_open(ctx->hold_open_baton, bucket);
+            if (status == APR_EAGAIN)
+                status = APR_SUCCESS;
+            return status;
+        }
+        else {
+            return APR_EOF;
+        }
+    }
+
+    head = ctx->list->bucket;
+
+    status = serf_bucket_peek(head, data, len);
+
+    if (status == APR_EOF) {
+        if (ctx->list->next) {
+            status = APR_SUCCESS;
+        } else {
+            if (ctx->hold_open) {
+                status = ctx->hold_open(ctx->hold_open_baton, bucket);
+                if (status == APR_EAGAIN)
+                    status = APR_SUCCESS;
+                return status;
+            }
+        }
+    }
+
+    return status;
+}
+
+static serf_bucket_t * serf_aggregate_read_bucket(
+    serf_bucket_t *bucket,
+    const serf_bucket_type_t *type)
+{
+    aggregate_context_t *ctx = bucket->data;
+    serf_bucket_t *found_bucket;
+
+    if (!ctx->list) {
+        return NULL;
+    }
+
+    if (ctx->list->bucket->type == type) {
+        /* Got the bucket. Consume it from our list. */
+        found_bucket = ctx->list->bucket;
+        ctx->list = ctx->list->next;
+        return found_bucket;
+    }
+
+    /* Call read_bucket on first one in our list. */
+    return serf_bucket_read_bucket(ctx->list->bucket, type);
+}
+
+
+const serf_bucket_type_t serf_bucket_type_aggregate = {
+    "AGGREGATE",
+    serf_aggregate_read,
+    serf_aggregate_readline,
+    serf_aggregate_read_iovec,
+    serf_default_read_for_sendfile,
+    serf_aggregate_read_bucket,
+    serf_aggregate_peek,
+    serf_aggregate_destroy_and_data,
+};

Deleted: vendor/serf/1.3.9/buckets/allocator.c
===================================================================
--- vendor/serf/dist/buckets/allocator.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/buckets/allocator.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,434 +0,0 @@
-/* Copyright 2002-2004 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_pools.h>
-
-#include "serf.h"
-#include "serf_bucket_util.h"
-
-
-typedef struct node_header_t {
-    apr_size_t size;
-    union {
-        struct node_header_t *next;      /* if size == 0 (freed/inactive) */
-        /* no data                          if size == STANDARD_NODE_SIZE */
-        apr_memnode_t *memnode;          /* if size > STANDARD_NODE_SIZE */
-    } u;
-} node_header_t;
-
-/* The size of a node_header_t, properly aligned. Note that (normally)
- * this macro will round the size to a multiple of 8 bytes. Keep this in
- * mind when altering the node_header_t structure. Also, keep in mind that
- * node_header_t is an overhead for every allocation performed through
- * the serf_bucket_mem_alloc() function.
- */
-#define SIZEOF_NODE_HEADER_T  APR_ALIGN_DEFAULT(sizeof(node_header_t))
-
-
-/* STANDARD_NODE_SIZE is manually set to an allocation size that will
- * capture most allocators performed via this API. It must be "large
- * enough" to avoid lots of spillage to allocating directly from the
- * apr_allocator associated with the bucket allocator. The apr_allocator
- * has a minimum size of 8k, which can be expensive if you missed the
- * STANDARD_NODE_SIZE by just a few bytes.
- */
-/* ### we should define some rules or ways to determine how to derive
- * ### a "good" value for this. probably log some stats on allocs, then
- * ### analyze them for size "misses". then find the balance point between
- * ### wasted space due to min-size allocator, and wasted-space due to
- * ### size-spill to the 8k minimum.
- */
-#define STANDARD_NODE_SIZE 128
-
-/* When allocating a block of memory from the allocator, we should go for
- * an 8k block, minus the overhead that the allocator needs.
- */
-#define ALLOC_AMT (8192 - APR_MEMNODE_T_SIZE)
-
-/* Define DEBUG_DOUBLE_FREE if you're interested in debugging double-free
- * calls to serf_bucket_mem_free().
- */
-#define DEBUG_DOUBLE_FREE
-
-
-typedef struct {
-    const serf_bucket_t *bucket;
-    apr_status_t last;
-} read_status_t;
-
-#define TRACK_BUCKET_COUNT 100  /* track N buckets' status */
-
-typedef struct {
-    int next_index;    /* info[] is a ring. next bucket goes at this idx. */
-    int num_used;
-
-    read_status_t info[TRACK_BUCKET_COUNT];
-} track_state_t;
-
-
-struct serf_bucket_alloc_t {
-    apr_pool_t *pool;
-    apr_allocator_t *allocator;
-    int own_allocator;
-
-    serf_unfreed_func_t unfreed;
-    void *unfreed_baton;
-
-    apr_uint32_t num_alloc;
-
-    node_header_t *freelist;    /* free STANDARD_NODE_SIZE blocks */
-    apr_memnode_t *blocks;      /* blocks we allocated for subdividing */
-
-    track_state_t *track;
-};
-
-/* ==================================================================== */
-
-
-static apr_status_t allocator_cleanup(void *data)
-{
-    serf_bucket_alloc_t *allocator = data;
-
-    /* If we allocated anything, give it back. */
-    if (allocator->blocks) {
-        apr_allocator_free(allocator->allocator, allocator->blocks);
-    }
-
-    /* If we allocated our own allocator (?!), destroy it here. */
-    if (allocator->own_allocator) {
-        apr_allocator_destroy(allocator->allocator);
-    }
-
-    return APR_SUCCESS;
-}
-
-serf_bucket_alloc_t *serf_bucket_allocator_create(
-    apr_pool_t *pool,
-    serf_unfreed_func_t unfreed,
-    void *unfreed_baton)
-{
-    serf_bucket_alloc_t *allocator = apr_pcalloc(pool, sizeof(*allocator));
-
-    allocator->pool = pool;
-    allocator->allocator = apr_pool_allocator_get(pool);
-    if (allocator->allocator == NULL) {
-        /* This most likely means pools are running in debug mode, create our
-         * own allocator to deal with memory ourselves */
-        apr_allocator_create(&allocator->allocator);
-        allocator->own_allocator = 1;
-    }
-    allocator->unfreed = unfreed;
-    allocator->unfreed_baton = unfreed_baton;
-
-#ifdef SERF_DEBUG_BUCKET_USE
-    {
-        track_state_t *track;
-
-        track = allocator->track = apr_palloc(pool, sizeof(*allocator->track));
-        track->next_index = 0;
-        track->num_used = 0;
-    }
-#endif
-
-    /* NOTE: On a fork/exec, the child won't bother cleaning up memory.
-             This is just fine... the memory will go away at exec.
-
-       NOTE: If the child will NOT perform an exec, then the parent or
-             the child will need to decide who to clean up any
-             outstanding connection/buckets (as appropriate).  */
-    apr_pool_cleanup_register(pool, allocator,
-                              allocator_cleanup, apr_pool_cleanup_null);
-
-    return allocator;
-}
-
-apr_pool_t *serf_bucket_allocator_get_pool(
-    const serf_bucket_alloc_t *allocator)
-{
-    return allocator->pool;
-}
-
-
-void *serf_bucket_mem_alloc(
-    serf_bucket_alloc_t *allocator,
-    apr_size_t size)
-{
-    node_header_t *node;
-
-    ++allocator->num_alloc;
-
-    size += SIZEOF_NODE_HEADER_T;
-    if (size <= STANDARD_NODE_SIZE) {
-        if (allocator->freelist) {
-            /* just pull a node off our freelist */
-            node = allocator->freelist;
-            allocator->freelist = node->u.next;
-#ifdef DEBUG_DOUBLE_FREE
-            /* When we free an item, we set its size to zero. Thus, when
-             * we return it to the caller, we must ensure the size is set
-             * properly.
-             */
-            node->size = STANDARD_NODE_SIZE;
-#endif
-        }
-        else {
-            apr_memnode_t *active = allocator->blocks;
-
-            if (active == NULL
-                || active->first_avail + STANDARD_NODE_SIZE >= active->endp) {
-                apr_memnode_t *head = allocator->blocks;
-
-                /* ran out of room. grab another block. */
-                active = apr_allocator_alloc(allocator->allocator, ALLOC_AMT);
-
-                /* System couldn't provide us with memory. */
-                if (active == NULL)
-                    return NULL;
-
-                /* link the block into our tracking list */
-                allocator->blocks = active;
-                active->next = head;
-            }
-
-            node = (node_header_t *)active->first_avail;
-            node->size = STANDARD_NODE_SIZE;
-            active->first_avail += STANDARD_NODE_SIZE;
-        }
-    }
-    else {
-        apr_memnode_t *memnode = apr_allocator_alloc(allocator->allocator,
-                                                     size);
-
-        if (memnode == NULL)
-            return NULL;
-
-        node = (node_header_t *)memnode->first_avail;
-        node->u.memnode = memnode;
-        node->size = size;
-    }
-
-    return ((char *)node) + SIZEOF_NODE_HEADER_T;
-}
-
-
-void *serf_bucket_mem_calloc(
-    serf_bucket_alloc_t *allocator,
-    apr_size_t size)
-{
-    void *mem;
-    mem = serf_bucket_mem_alloc(allocator, size);
-    if (mem == NULL)
-        return NULL;
-    memset(mem, 0, size);
-    return mem;
-}
-
-
-void serf_bucket_mem_free(
-    serf_bucket_alloc_t *allocator,
-    void *block)
-{
-    node_header_t *node;
-
-    --allocator->num_alloc;
-
-    node = (node_header_t *)((char *)block - SIZEOF_NODE_HEADER_T);
-
-    if (node->size == STANDARD_NODE_SIZE) {
-        /* put the node onto our free list */
-        node->u.next = allocator->freelist;
-        allocator->freelist = node;
-
-#ifdef DEBUG_DOUBLE_FREE
-        /* note that this thing was freed. */
-        node->size = 0;
-    }
-    else if (node->size == 0) {
-        /* damn thing was freed already. */
-        abort();
-#endif
-    }
-    else {
-#ifdef DEBUG_DOUBLE_FREE
-        /* note that this thing was freed. */
-        node->size = 0;
-#endif
-
-        /* now free it */
-        apr_allocator_free(allocator->allocator, node->u.memnode);
-    }
-}
-
-
-/* ==================================================================== */
-
-
-#ifdef SERF_DEBUG_BUCKET_USE
-
-static read_status_t *find_read_status(
-    track_state_t *track,
-    const serf_bucket_t *bucket,
-    int create_rs)
-{
-    read_status_t *rs;
-
-    if (track->num_used) {
-        int count = track->num_used;
-        int idx = track->next_index;
-
-        /* Search backwards. In all likelihood, the bucket which just got
-         * read was read very recently.
-         */
-        while (count-- > 0) {
-            if (!idx--) {
-                /* assert: track->num_used == TRACK_BUCKET_COUNT */
-                idx = track->num_used - 1;
-            }
-            if ((rs = &track->info[idx])->bucket == bucket) {
-                return rs;
-            }
-        }
-    }
-
-    /* Only create a new read_status_t when asked. */
-    if (!create_rs)
-        return NULL;
-
-    if (track->num_used < TRACK_BUCKET_COUNT) {
-        /* We're still filling up the ring. */
-        ++track->num_used;
-    }
-
-    rs = &track->info[track->next_index];
-    rs->bucket = bucket;
-    rs->last = APR_SUCCESS;     /* ### the right initial value? */
-
-    if (++track->next_index == TRACK_BUCKET_COUNT)
-        track->next_index = 0;
-
-    return rs;
-}
-
-#endif /* SERF_DEBUG_BUCKET_USE */
-
-
-apr_status_t serf_debug__record_read(
-    const serf_bucket_t *bucket,
-    apr_status_t status)
-{
-#ifndef SERF_DEBUG_BUCKET_USE
-    return status;
-#else
-
-    track_state_t *track = bucket->allocator->track;
-    read_status_t *rs = find_read_status(track, bucket, 1);
-
-    /* Validate that the previous status value allowed for another read. */
-    if (APR_STATUS_IS_EAGAIN(rs->last) /* ### or APR_EOF? */) {
-        /* Somebody read when they weren't supposed to. Bail. */
-        abort();
-    }
-
-    /* Save the current status for later. */
-    rs->last = status;
-
-    return status;
-#endif
-}
-
-
-void serf_debug__entered_loop(serf_bucket_alloc_t *allocator)
-{
-#ifdef SERF_DEBUG_BUCKET_USE
-
-    track_state_t *track = allocator->track;
-    read_status_t *rs = &track->info[0];
-
-    for ( ; track->num_used; --track->num_used, ++rs ) {
-        if (rs->last == APR_SUCCESS) {
-            /* Somebody should have read this bucket again. */
-            abort();
-        }
-
-        /* ### other status values? */
-    }
-
-    /* num_used was reset. also need to reset the next index. */
-    track->next_index = 0;
-
-#endif
-}
-
-
-void serf_debug__closed_conn(serf_bucket_alloc_t *allocator)
-{
-#ifdef SERF_DEBUG_BUCKET_USE
-
-    /* Just reset the number used so that we don't examine the info[] */
-    allocator->track->num_used = 0;
-    allocator->track->next_index = 0;
-
-#endif
-}
-
-
-void serf_debug__bucket_destroy(const serf_bucket_t *bucket)
-{
-#ifdef SERF_DEBUG_BUCKET_USE
-
-    track_state_t *track = bucket->allocator->track;
-    read_status_t *rs = find_read_status(track, bucket, 0);
-
-    if (rs != NULL && rs->last != APR_EOF) {
-        /* The bucket was destroyed before it was read to completion. */
-
-        /* Special exception for socket buckets. If a connection remains
-         * open, they are not read to completion.
-         */
-        if (SERF_BUCKET_IS_SOCKET(bucket))
-            return;
-
-        /* Ditto for SSL Decrypt buckets. */
-        if (SERF_BUCKET_IS_SSL_DECRYPT(bucket))
-            return;
-
-        /* Ditto for SSL Encrypt buckets. */
-        if (SERF_BUCKET_IS_SSL_ENCRYPT(bucket))
-            return;
-
-        /* Ditto for barrier buckets. */
-        if (SERF_BUCKET_IS_BARRIER(bucket))
-            return;
-
-
-        abort();
-    }
-
-#endif
-}
-
-
-void serf_debug__bucket_alloc_check(
-    serf_bucket_alloc_t *allocator)
-{
-#ifdef SERF_DEBUG_BUCKET_USE
-    if (allocator->num_alloc != 0) {
-        abort();
-    }
-#endif
-}
-

Copied: vendor/serf/1.3.9/buckets/allocator.c (from rev 9259, vendor/serf/dist/buckets/allocator.c)
===================================================================
--- vendor/serf/1.3.9/buckets/allocator.c	                        (rev 0)
+++ vendor/serf/1.3.9/buckets/allocator.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,439 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_pools.h>
+
+#include "serf.h"
+#include "serf_bucket_util.h"
+
+
+typedef struct node_header_t {
+    apr_size_t size;
+    union {
+        struct node_header_t *next;      /* if size == 0 (freed/inactive) */
+        /* no data                          if size == STANDARD_NODE_SIZE */
+        apr_memnode_t *memnode;          /* if size > STANDARD_NODE_SIZE */
+    } u;
+} node_header_t;
+
+/* The size of a node_header_t, properly aligned. Note that (normally)
+ * this macro will round the size to a multiple of 8 bytes. Keep this in
+ * mind when altering the node_header_t structure. Also, keep in mind that
+ * node_header_t is an overhead for every allocation performed through
+ * the serf_bucket_mem_alloc() function.
+ */
+#define SIZEOF_NODE_HEADER_T  APR_ALIGN_DEFAULT(sizeof(node_header_t))
+
+
+/* STANDARD_NODE_SIZE is manually set to an allocation size that will
+ * capture most allocators performed via this API. It must be "large
+ * enough" to avoid lots of spillage to allocating directly from the
+ * apr_allocator associated with the bucket allocator. The apr_allocator
+ * has a minimum size of 8k, which can be expensive if you missed the
+ * STANDARD_NODE_SIZE by just a few bytes.
+ */
+/* ### we should define some rules or ways to determine how to derive
+ * ### a "good" value for this. probably log some stats on allocs, then
+ * ### analyze them for size "misses". then find the balance point between
+ * ### wasted space due to min-size allocator, and wasted-space due to
+ * ### size-spill to the 8k minimum.
+ */
+#define STANDARD_NODE_SIZE 128
+
+/* When allocating a block of memory from the allocator, we should go for
+ * an 8k block, minus the overhead that the allocator needs.
+ */
+#define ALLOC_AMT (8192 - APR_MEMNODE_T_SIZE)
+
+/* Define DEBUG_DOUBLE_FREE if you're interested in debugging double-free
+ * calls to serf_bucket_mem_free().
+ */
+#define DEBUG_DOUBLE_FREE
+
+
+typedef struct {
+    const serf_bucket_t *bucket;
+    apr_status_t last;
+} read_status_t;
+
+#define TRACK_BUCKET_COUNT 100  /* track N buckets' status */
+
+typedef struct {
+    int next_index;    /* info[] is a ring. next bucket goes at this idx. */
+    int num_used;
+
+    read_status_t info[TRACK_BUCKET_COUNT];
+} track_state_t;
+
+
+struct serf_bucket_alloc_t {
+    apr_pool_t *pool;
+    apr_allocator_t *allocator;
+    int own_allocator;
+
+    serf_unfreed_func_t unfreed;
+    void *unfreed_baton;
+
+    apr_uint32_t num_alloc;
+
+    node_header_t *freelist;    /* free STANDARD_NODE_SIZE blocks */
+    apr_memnode_t *blocks;      /* blocks we allocated for subdividing */
+
+    track_state_t *track;
+};
+
+/* ==================================================================== */
+
+
+static apr_status_t allocator_cleanup(void *data)
+{
+    serf_bucket_alloc_t *allocator = data;
+
+    /* If we allocated anything, give it back. */
+    if (allocator->blocks) {
+        apr_allocator_free(allocator->allocator, allocator->blocks);
+    }
+
+    /* If we allocated our own allocator (?!), destroy it here. */
+    if (allocator->own_allocator) {
+        apr_allocator_destroy(allocator->allocator);
+    }
+
+    return APR_SUCCESS;
+}
+
+serf_bucket_alloc_t *serf_bucket_allocator_create(
+    apr_pool_t *pool,
+    serf_unfreed_func_t unfreed,
+    void *unfreed_baton)
+{
+    serf_bucket_alloc_t *allocator = apr_pcalloc(pool, sizeof(*allocator));
+
+    allocator->pool = pool;
+    allocator->allocator = apr_pool_allocator_get(pool);
+    if (allocator->allocator == NULL) {
+        /* This most likely means pools are running in debug mode, create our
+         * own allocator to deal with memory ourselves */
+        apr_allocator_create(&allocator->allocator);
+        allocator->own_allocator = 1;
+    }
+    allocator->unfreed = unfreed;
+    allocator->unfreed_baton = unfreed_baton;
+
+#ifdef SERF_DEBUG_BUCKET_USE
+    {
+        track_state_t *track;
+
+        track = allocator->track = apr_palloc(pool, sizeof(*allocator->track));
+        track->next_index = 0;
+        track->num_used = 0;
+    }
+#endif
+
+    /* NOTE: On a fork/exec, the child won't bother cleaning up memory.
+             This is just fine... the memory will go away at exec.
+
+       NOTE: If the child will NOT perform an exec, then the parent or
+             the child will need to decide who to clean up any
+             outstanding connection/buckets (as appropriate).  */
+    apr_pool_cleanup_register(pool, allocator,
+                              allocator_cleanup, apr_pool_cleanup_null);
+
+    return allocator;
+}
+
+apr_pool_t *serf_bucket_allocator_get_pool(
+    const serf_bucket_alloc_t *allocator)
+{
+    return allocator->pool;
+}
+
+
+void *serf_bucket_mem_alloc(
+    serf_bucket_alloc_t *allocator,
+    apr_size_t size)
+{
+    node_header_t *node;
+
+    ++allocator->num_alloc;
+
+    size += SIZEOF_NODE_HEADER_T;
+    if (size <= STANDARD_NODE_SIZE) {
+        if (allocator->freelist) {
+            /* just pull a node off our freelist */
+            node = allocator->freelist;
+            allocator->freelist = node->u.next;
+#ifdef DEBUG_DOUBLE_FREE
+            /* When we free an item, we set its size to zero. Thus, when
+             * we return it to the caller, we must ensure the size is set
+             * properly.
+             */
+            node->size = STANDARD_NODE_SIZE;
+#endif
+        }
+        else {
+            apr_memnode_t *active = allocator->blocks;
+
+            if (active == NULL
+                || active->first_avail + STANDARD_NODE_SIZE >= active->endp) {
+                apr_memnode_t *head = allocator->blocks;
+
+                /* ran out of room. grab another block. */
+                active = apr_allocator_alloc(allocator->allocator, ALLOC_AMT);
+
+                /* System couldn't provide us with memory. */
+                if (active == NULL)
+                    return NULL;
+
+                /* link the block into our tracking list */
+                allocator->blocks = active;
+                active->next = head;
+            }
+
+            node = (node_header_t *)active->first_avail;
+            node->size = STANDARD_NODE_SIZE;
+            active->first_avail += STANDARD_NODE_SIZE;
+        }
+    }
+    else {
+        apr_memnode_t *memnode = apr_allocator_alloc(allocator->allocator,
+                                                     size);
+
+        if (memnode == NULL)
+            return NULL;
+
+        node = (node_header_t *)memnode->first_avail;
+        node->u.memnode = memnode;
+        node->size = size;
+    }
+
+    return ((char *)node) + SIZEOF_NODE_HEADER_T;
+}
+
+
+void *serf_bucket_mem_calloc(
+    serf_bucket_alloc_t *allocator,
+    apr_size_t size)
+{
+    void *mem;
+    mem = serf_bucket_mem_alloc(allocator, size);
+    if (mem == NULL)
+        return NULL;
+    memset(mem, 0, size);
+    return mem;
+}
+
+
+void serf_bucket_mem_free(
+    serf_bucket_alloc_t *allocator,
+    void *block)
+{
+    node_header_t *node;
+
+    --allocator->num_alloc;
+
+    node = (node_header_t *)((char *)block - SIZEOF_NODE_HEADER_T);
+
+    if (node->size == STANDARD_NODE_SIZE) {
+        /* put the node onto our free list */
+        node->u.next = allocator->freelist;
+        allocator->freelist = node;
+
+#ifdef DEBUG_DOUBLE_FREE
+        /* note that this thing was freed. */
+        node->size = 0;
+    }
+    else if (node->size == 0) {
+        /* damn thing was freed already. */
+        abort();
+#endif
+    }
+    else {
+#ifdef DEBUG_DOUBLE_FREE
+        /* note that this thing was freed. */
+        node->size = 0;
+#endif
+
+        /* now free it */
+        apr_allocator_free(allocator->allocator, node->u.memnode);
+    }
+}
+
+
+/* ==================================================================== */
+
+
+#ifdef SERF_DEBUG_BUCKET_USE
+
+static read_status_t *find_read_status(
+    track_state_t *track,
+    const serf_bucket_t *bucket,
+    int create_rs)
+{
+    read_status_t *rs;
+
+    if (track->num_used) {
+        int count = track->num_used;
+        int idx = track->next_index;
+
+        /* Search backwards. In all likelihood, the bucket which just got
+         * read was read very recently.
+         */
+        while (count-- > 0) {
+            if (!idx--) {
+                /* assert: track->num_used == TRACK_BUCKET_COUNT */
+                idx = track->num_used - 1;
+            }
+            if ((rs = &track->info[idx])->bucket == bucket) {
+                return rs;
+            }
+        }
+    }
+
+    /* Only create a new read_status_t when asked. */
+    if (!create_rs)
+        return NULL;
+
+    if (track->num_used < TRACK_BUCKET_COUNT) {
+        /* We're still filling up the ring. */
+        ++track->num_used;
+    }
+
+    rs = &track->info[track->next_index];
+    rs->bucket = bucket;
+    rs->last = APR_SUCCESS;     /* ### the right initial value? */
+
+    if (++track->next_index == TRACK_BUCKET_COUNT)
+        track->next_index = 0;
+
+    return rs;
+}
+
+#endif /* SERF_DEBUG_BUCKET_USE */
+
+
+apr_status_t serf_debug__record_read(
+    const serf_bucket_t *bucket,
+    apr_status_t status)
+{
+#ifndef SERF_DEBUG_BUCKET_USE
+    return status;
+#else
+
+    track_state_t *track = bucket->allocator->track;
+    read_status_t *rs = find_read_status(track, bucket, 1);
+
+    /* Validate that the previous status value allowed for another read. */
+    if (APR_STATUS_IS_EAGAIN(rs->last) /* ### or APR_EOF? */) {
+        /* Somebody read when they weren't supposed to. Bail. */
+        abort();
+    }
+
+    /* Save the current status for later. */
+    rs->last = status;
+
+    return status;
+#endif
+}
+
+
+void serf_debug__entered_loop(serf_bucket_alloc_t *allocator)
+{
+#ifdef SERF_DEBUG_BUCKET_USE
+
+    track_state_t *track = allocator->track;
+    read_status_t *rs = &track->info[0];
+
+    for ( ; track->num_used; --track->num_used, ++rs ) {
+        if (rs->last == APR_SUCCESS) {
+            /* Somebody should have read this bucket again. */
+            abort();
+        }
+
+        /* ### other status values? */
+    }
+
+    /* num_used was reset. also need to reset the next index. */
+    track->next_index = 0;
+
+#endif
+}
+
+
+void serf_debug__closed_conn(serf_bucket_alloc_t *allocator)
+{
+#ifdef SERF_DEBUG_BUCKET_USE
+
+    /* Just reset the number used so that we don't examine the info[] */
+    allocator->track->num_used = 0;
+    allocator->track->next_index = 0;
+
+#endif
+}
+
+
+void serf_debug__bucket_destroy(const serf_bucket_t *bucket)
+{
+#ifdef SERF_DEBUG_BUCKET_USE
+
+    track_state_t *track = bucket->allocator->track;
+    read_status_t *rs = find_read_status(track, bucket, 0);
+
+    if (rs != NULL && rs->last != APR_EOF) {
+        /* The bucket was destroyed before it was read to completion. */
+
+        /* Special exception for socket buckets. If a connection remains
+         * open, they are not read to completion.
+         */
+        if (SERF_BUCKET_IS_SOCKET(bucket))
+            return;
+
+        /* Ditto for SSL Decrypt buckets. */
+        if (SERF_BUCKET_IS_SSL_DECRYPT(bucket))
+            return;
+
+        /* Ditto for SSL Encrypt buckets. */
+        if (SERF_BUCKET_IS_SSL_ENCRYPT(bucket))
+            return;
+
+        /* Ditto for barrier buckets. */
+        if (SERF_BUCKET_IS_BARRIER(bucket))
+            return;
+
+
+        abort();
+    }
+
+#endif
+}
+
+
+void serf_debug__bucket_alloc_check(
+    serf_bucket_alloc_t *allocator)
+{
+#ifdef SERF_DEBUG_BUCKET_USE
+    if (allocator->num_alloc != 0) {
+        abort();
+    }
+#endif
+}
+

Deleted: vendor/serf/1.3.9/buckets/barrier_buckets.c
===================================================================
--- vendor/serf/dist/buckets/barrier_buckets.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/buckets/barrier_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,97 +0,0 @@
-/* Copyright 2002-2004 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_pools.h>
-
-#include "serf.h"
-#include "serf_bucket_util.h"
-
-
-typedef struct {
-    serf_bucket_t *stream;
-} barrier_context_t;
-
-
-serf_bucket_t *serf_bucket_barrier_create(
-    serf_bucket_t *stream,
-    serf_bucket_alloc_t *allocator)
-{
-    barrier_context_t *ctx;
-
-    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
-    ctx->stream = stream;
-
-    return serf_bucket_create(&serf_bucket_type_barrier, allocator, ctx);
-}
-
-static apr_status_t serf_barrier_read(serf_bucket_t *bucket,
-                                     apr_size_t requested,
-                                     const char **data, apr_size_t *len)
-{
-    barrier_context_t *ctx = bucket->data;
-
-    return serf_bucket_read(ctx->stream, requested, data, len);
-}
-
-static apr_status_t serf_barrier_read_iovec(serf_bucket_t *bucket,
-                                            apr_size_t requested,
-                                            int vecs_size, struct iovec *vecs,
-                                            int *vecs_used)
-{
-    barrier_context_t *ctx = bucket->data;
-
-    return serf_bucket_read_iovec(ctx->stream, requested, vecs_size, vecs,
-                                  vecs_used);
-}
-
-static apr_status_t serf_barrier_readline(serf_bucket_t *bucket,
-                                         int acceptable, int *found,
-                                         const char **data, apr_size_t *len)
-{
-    barrier_context_t *ctx = bucket->data;
-
-    return serf_bucket_readline(ctx->stream, acceptable, found, data, len);
-}
-
-static apr_status_t serf_barrier_peek(serf_bucket_t *bucket,
-                                     const char **data,
-                                     apr_size_t *len)
-{
-    barrier_context_t *ctx = bucket->data;
-
-    return serf_bucket_peek(ctx->stream, data, len);
-}
-
-static void serf_barrier_destroy(serf_bucket_t *bucket)
-{
-    /* The intent of this bucket is not to let our wrapped buckets be
-     * destroyed. */
-
-    /* The option is for us to go ahead and 'eat' this bucket now,
-     * or just ignore the deletion entirely.
-     */
-    serf_default_destroy_and_data(bucket);
-}
-
-const serf_bucket_type_t serf_bucket_type_barrier = {
-    "BARRIER",
-    serf_barrier_read,
-    serf_barrier_readline,
-    serf_barrier_read_iovec,
-    serf_default_read_for_sendfile,
-    serf_default_read_bucket,
-    serf_barrier_peek,
-    serf_barrier_destroy,
-};

Copied: vendor/serf/1.3.9/buckets/barrier_buckets.c (from rev 9259, vendor/serf/dist/buckets/barrier_buckets.c)
===================================================================
--- vendor/serf/1.3.9/buckets/barrier_buckets.c	                        (rev 0)
+++ vendor/serf/1.3.9/buckets/barrier_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,102 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_pools.h>
+
+#include "serf.h"
+#include "serf_bucket_util.h"
+
+
+typedef struct {
+    serf_bucket_t *stream;
+} barrier_context_t;
+
+
+serf_bucket_t *serf_bucket_barrier_create(
+    serf_bucket_t *stream,
+    serf_bucket_alloc_t *allocator)
+{
+    barrier_context_t *ctx;
+
+    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
+    ctx->stream = stream;
+
+    return serf_bucket_create(&serf_bucket_type_barrier, allocator, ctx);
+}
+
+static apr_status_t serf_barrier_read(serf_bucket_t *bucket,
+                                     apr_size_t requested,
+                                     const char **data, apr_size_t *len)
+{
+    barrier_context_t *ctx = bucket->data;
+
+    return serf_bucket_read(ctx->stream, requested, data, len);
+}
+
+static apr_status_t serf_barrier_read_iovec(serf_bucket_t *bucket,
+                                            apr_size_t requested,
+                                            int vecs_size, struct iovec *vecs,
+                                            int *vecs_used)
+{
+    barrier_context_t *ctx = bucket->data;
+
+    return serf_bucket_read_iovec(ctx->stream, requested, vecs_size, vecs,
+                                  vecs_used);
+}
+
+static apr_status_t serf_barrier_readline(serf_bucket_t *bucket,
+                                         int acceptable, int *found,
+                                         const char **data, apr_size_t *len)
+{
+    barrier_context_t *ctx = bucket->data;
+
+    return serf_bucket_readline(ctx->stream, acceptable, found, data, len);
+}
+
+static apr_status_t serf_barrier_peek(serf_bucket_t *bucket,
+                                     const char **data,
+                                     apr_size_t *len)
+{
+    barrier_context_t *ctx = bucket->data;
+
+    return serf_bucket_peek(ctx->stream, data, len);
+}
+
+static void serf_barrier_destroy(serf_bucket_t *bucket)
+{
+    /* The intent of this bucket is not to let our wrapped buckets be
+     * destroyed. */
+
+    /* The option is for us to go ahead and 'eat' this bucket now,
+     * or just ignore the deletion entirely.
+     */
+    serf_default_destroy_and_data(bucket);
+}
+
+const serf_bucket_type_t serf_bucket_type_barrier = {
+    "BARRIER",
+    serf_barrier_read,
+    serf_barrier_readline,
+    serf_barrier_read_iovec,
+    serf_default_read_for_sendfile,
+    serf_default_read_bucket,
+    serf_barrier_peek,
+    serf_barrier_destroy,
+};

Deleted: vendor/serf/1.3.9/buckets/buckets.c
===================================================================
--- vendor/serf/dist/buckets/buckets.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/buckets/buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,640 +0,0 @@
-/* Copyright 2002-2004 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_pools.h>
-
-#include "serf.h"
-#include "serf_bucket_util.h"
-#include "serf_private.h"
-
-serf_bucket_t *serf_bucket_create(
-    const serf_bucket_type_t *type,
-    serf_bucket_alloc_t *allocator,
-    void *data)
-{
-    serf_bucket_t *bkt = serf_bucket_mem_alloc(allocator, sizeof(*bkt));
-
-    bkt->type = type;
-    bkt->data = data;
-    bkt->allocator = allocator;
-
-    return bkt;
-}
-
-
-apr_status_t serf_default_read_iovec(
-    serf_bucket_t *bucket,
-    apr_size_t requested,
-    int vecs_size,
-    struct iovec *vecs,
-    int *vecs_used)
-{
-    const char *data;
-    apr_size_t len;
-
-    /* Read some data from the bucket.
-     *
-     * Because we're an internal 'helper' to the bucket, we can't call the
-     * normal serf_bucket_read() call because the debug allocator tracker will
-     * end up marking the bucket as read *twice* - once for us and once for
-     * our caller - which is reading the same bucket.  This leads to premature
-     * abort()s if we ever see EAGAIN.  Instead, we'll go directly to the
-     * vtable and bypass the debug tracker.
-     */
-    apr_status_t status = bucket->type->read(bucket, requested, &data, &len);
-
-    /* assert that vecs_size >= 1 ? */
-
-    /* Return that data as a single iovec. */
-    if (len) {
-        vecs[0].iov_base = (void *)data; /* loses the 'const' */
-        vecs[0].iov_len = len;
-        *vecs_used = 1;
-    }
-    else {
-        *vecs_used = 0;
-    }
-
-    return status;
-}
-
-
-apr_status_t serf_default_read_for_sendfile(
-    serf_bucket_t *bucket,
-    apr_size_t requested,
-    apr_hdtr_t *hdtr,
-    apr_file_t **file,
-    apr_off_t *offset,
-    apr_size_t *len)
-{
-    /* Read a bunch of stuff into the headers.
-     *
-     * See serf_default_read_iovec as to why we call into the vtable
-     * directly.
-     */
-    apr_status_t status = bucket->type->read_iovec(bucket, requested,
-                                                   hdtr->numheaders,
-                                                   hdtr->headers,
-                                                   &hdtr->numheaders);
-
-    /* There isn't a file, and there are no trailers. */
-    *file = NULL;
-    hdtr->numtrailers = 0;
-
-    return status;
-}
-
-
-serf_bucket_t *serf_default_read_bucket(
-    serf_bucket_t *bucket,
-    const serf_bucket_type_t *type)
-{
-    return NULL;
-}
-
-
-void serf_default_destroy(serf_bucket_t *bucket)
-{
-#ifdef SERF_DEBUG_BUCKET_USE
-    serf_debug__bucket_destroy(bucket);
-#endif
-
-    serf_bucket_mem_free(bucket->allocator, bucket);
-}
-
-
-void serf_default_destroy_and_data(serf_bucket_t *bucket)
-{
-    serf_bucket_mem_free(bucket->allocator, bucket->data);
-    serf_default_destroy(bucket);
-}
-
-
-/* ==================================================================== */
-
-
-char *serf_bstrmemdup(serf_bucket_alloc_t *allocator,
-                      const char *str,
-                      apr_size_t size)
-{
-    char *newstr = serf_bucket_mem_alloc(allocator, size + 1);
-    memcpy(newstr, str, size);
-    newstr[size] = '\0';
-    return newstr;
-}
-
-
-void *serf_bmemdup(serf_bucket_alloc_t *allocator,
-                   const void *mem,
-                   apr_size_t size)
-{
-    void *newmem = serf_bucket_mem_alloc(allocator, size);
-    memcpy(newmem, mem, size);
-    return newmem;
-}
-
-
-char *serf_bstrdup(serf_bucket_alloc_t *allocator,
-                   const char *str)
-{
-    apr_size_t size = strlen(str) + 1;
-    char *newstr = serf_bucket_mem_alloc(allocator, size);
-    memcpy(newstr, str, size);
-    return newstr;
-}
-
-char *serf_bstrcatv(serf_bucket_alloc_t *allocator, struct iovec *vec,
-                    int vecs, apr_size_t *bytes_written)
-{
-    int i;
-    apr_size_t new_len = 0;
-    char *c, *newstr;
-
-    for (i = 0; i < vecs; i++) {
-        new_len += vec[i].iov_len;
-    }
-
-    /* It's up to the caller to free this memory later. */
-    newstr = serf_bucket_mem_alloc(allocator, new_len);
-
-    c = newstr;
-    for (i = 0; i < vecs; i++) {
-        memcpy(c, vec[i].iov_base, vec[i].iov_len);
-        c += vec[i].iov_len;
-    }
-
-    if (bytes_written) {
-        *bytes_written = c - newstr;
-    }
-
-    return newstr;
-}
-
-/* ==================================================================== */
-
-
-static void find_crlf(const char **data, apr_size_t *len, int *found)
-{
-    const char *start = *data;
-    const char *end = start + *len;
-
-    while (start < end) {
-        const char *cr = memchr(start, '\r', *len);
-
-        if (cr == NULL) {
-            break;
-        }
-        ++cr;
-
-        if (cr < end && cr[0] == '\n') {
-            *len -= cr + 1 - start;
-            *data = cr + 1;
-            *found = SERF_NEWLINE_CRLF;
-            return;
-        }
-        if (cr == end) {
-            *len = 0;
-            *data = end;
-            *found = SERF_NEWLINE_CRLF_SPLIT;
-            return;
-        }
-
-        /* It was a bare CR without an LF. Just move past it. */
-        *len -= cr - start;
-        start = cr;
-    }
-
-    *data = start + *len;
-    *len -= *data - start;
-    *found = SERF_NEWLINE_NONE;
-}
-
-
-void serf_util_readline(
-    const char **data,
-    apr_size_t *len,
-    int acceptable,
-    int *found)
-{
-    const char *start;
-    const char *cr;
-    const char *lf;
-    int want_cr;
-    int want_crlf;
-    int want_lf;
-
-    /* If _only_ CRLF is acceptable, then the scanning needs a loop to
-     * skip false hits on CR characters. Use a separate function.
-     */
-    if (acceptable == SERF_NEWLINE_CRLF) {
-        find_crlf(data, len, found);
-        return;
-    }
-
-    start = *data;
-    cr = lf = NULL;
-    want_cr = acceptable & SERF_NEWLINE_CR;
-    want_crlf = acceptable & SERF_NEWLINE_CRLF;
-    want_lf = acceptable & SERF_NEWLINE_LF;
-
-    if (want_cr || want_crlf) {
-        cr = memchr(start, '\r', *len);
-    }
-    if (want_lf) {
-        lf = memchr(start, '\n', *len);
-    }
-
-    if (cr != NULL) {
-        if (lf != NULL) {
-            if (cr + 1 == lf)
-                *found = want_crlf ? SERF_NEWLINE_CRLF : SERF_NEWLINE_CR;
-            else if (want_cr && cr < lf)
-                *found = SERF_NEWLINE_CR;
-            else
-                *found = SERF_NEWLINE_LF;
-        }
-        else if (cr == start + *len - 1) {
-            /* the CR occurred in the last byte of the buffer. this could be
-             * a CRLF split across the data boundary.
-             * ### FIX THIS LOGIC? does caller need to detect?
-             */
-            *found = want_crlf ? SERF_NEWLINE_CRLF_SPLIT : SERF_NEWLINE_CR;
-        }
-        else if (want_cr)
-            *found = SERF_NEWLINE_CR;
-        else /* want_crlf */
-            *found = SERF_NEWLINE_NONE;
-    }
-    else if (lf != NULL)
-        *found = SERF_NEWLINE_LF;
-    else
-        *found = SERF_NEWLINE_NONE;
-
-    switch (*found) {
-      case SERF_NEWLINE_LF:
-        *data = lf + 1;
-        break;
-      case SERF_NEWLINE_CR:
-      case SERF_NEWLINE_CRLF:
-      case SERF_NEWLINE_CRLF_SPLIT:
-        *data = cr + 1 + (*found == SERF_NEWLINE_CRLF);
-        break;
-      case SERF_NEWLINE_NONE:
-        *data += *len;
-        break;
-      default:
-        /* Not reachable */
-        return;
-    }
-
-    *len -= *data - start;
-}
-
-
-/* ==================================================================== */
-
-
-void serf_databuf_init(serf_databuf_t *databuf)
-{
-    /* nothing is sitting in the buffer */
-    databuf->remaining = 0;
-
-    /* avoid thinking we have hit EOF */
-    databuf->status = APR_SUCCESS;
-}
-
-/* Ensure the buffer is prepared for reading. Will return APR_SUCCESS,
- * APR_EOF, or some failure code. *len is only set for EOF. */
-static apr_status_t common_databuf_prep(serf_databuf_t *databuf,
-                                        apr_size_t *len)
-{
-    apr_size_t readlen;
-    apr_status_t status;
-
-    /* if there is data in the buffer, then we're happy. */
-    if (databuf->remaining > 0)
-        return APR_SUCCESS;
-
-    /* if we already hit EOF, then keep returning that. */
-    if (APR_STATUS_IS_EOF(databuf->status)) {
-        /* *data = NULL;   ?? */
-        *len = 0;
-        return APR_EOF;
-    }
-
-    /* refill the buffer */
-    status = (*databuf->read)(databuf->read_baton, sizeof(databuf->buf),
-                              databuf->buf, &readlen);
-    if (SERF_BUCKET_READ_ERROR(status)) {
-        return status;
-    }
-
-    databuf->current = databuf->buf;
-    databuf->remaining = readlen;
-    databuf->status = status;
-
-    return APR_SUCCESS;
-}
-
-
-apr_status_t serf_databuf_read(
-    serf_databuf_t *databuf,
-    apr_size_t requested,
-    const char **data,
-    apr_size_t *len)
-{
-    apr_status_t status = common_databuf_prep(databuf, len);
-    if (status)
-        return status;
-
-    /* peg the requested amount to what we have remaining */
-    if (requested == SERF_READ_ALL_AVAIL || requested > databuf->remaining)
-        requested = databuf->remaining;
-
-    /* return the values */
-    *data = databuf->current;
-    *len = requested;
-
-    /* adjust our internal state to note we've consumed some data */
-    databuf->current += requested;
-    databuf->remaining -= requested;
-
-    /* If we read everything, then we need to return whatever the data
-     * read returned to us. This is going to be APR_EOF or APR_EGAIN.
-     * If we have NOT read everything, then return APR_SUCCESS to indicate
-     * that we're ready to return some more if asked.
-     */
-    return databuf->remaining ? APR_SUCCESS : databuf->status;
-}
-
-
-apr_status_t serf_databuf_readline(
-    serf_databuf_t *databuf,
-    int acceptable,
-    int *found,
-    const char **data,
-    apr_size_t *len)
-{
-    apr_status_t status = common_databuf_prep(databuf, len);
-    if (status)
-        return status;
-
-    /* the returned line will start at the current position. */
-    *data = databuf->current;
-
-    /* read a line from the buffer, and adjust the various pointers. */
-    serf_util_readline(&databuf->current, &databuf->remaining, acceptable,
-                       found);
-
-    /* the length matches the amount consumed by the readline */
-    *len = databuf->current - *data;
-
-    /* see serf_databuf_read's return condition */
-    return databuf->remaining ? APR_SUCCESS : databuf->status;
-}
-
-
-apr_status_t serf_databuf_peek(
-    serf_databuf_t *databuf,
-    const char **data,
-    apr_size_t *len)
-{
-    apr_status_t status = common_databuf_prep(databuf, len);
-    if (status)
-        return status;
-
-    /* return everything we have */
-    *data = databuf->current;
-    *len = databuf->remaining;
-
-    /* If the last read returned EOF, then the peek should return the same.
-     * The other possibility in databuf->status is APR_EAGAIN, which we
-     * should never return. Thus, just return APR_SUCCESS for non-EOF cases.
-     */
-    if (APR_STATUS_IS_EOF(databuf->status))
-        return APR_EOF;
-    return APR_SUCCESS;
-}
-
-
-/* ==================================================================== */
-
-
-void serf_linebuf_init(serf_linebuf_t *linebuf)
-{
-    linebuf->state = SERF_LINEBUF_EMPTY;
-    linebuf->used = 0;
-}
-
-
-apr_status_t serf_linebuf_fetch(
-    serf_linebuf_t *linebuf,
-    serf_bucket_t *bucket,
-    int acceptable)
-{
-    /* If we had a complete line, then assume the caller has used it, so
-     * we can now reset the state.
-     */
-    if (linebuf->state == SERF_LINEBUF_READY) {
-        linebuf->state = SERF_LINEBUF_EMPTY;
-
-        /* Reset the line_used, too, so we don't have to test the state
-         * before using this value.
-         */
-        linebuf->used = 0;
-    }
-
-    while (1) {
-        apr_status_t status;
-        const char *data;
-        apr_size_t len;
-
-        if (linebuf->state == SERF_LINEBUF_CRLF_SPLIT) {
-            /* On the previous read, we received just a CR. The LF might
-             * be present, but the bucket couldn't see it. We need to
-             * examine a single character to determine how to handle the
-             * split CRLF.
-             */
-
-            status = serf_bucket_peek(bucket, &data, &len);
-            if (SERF_BUCKET_READ_ERROR(status))
-                return status;
-
-            if (len > 0) {
-                if (*data == '\n') {
-                    /* We saw the second part of CRLF. We don't need to
-                     * save that character, so do an actual read to suck
-                     * up that character.
-                     */
-                    /* ### check status */
-                    (void) serf_bucket_read(bucket, 1, &data, &len);
-                }
-                /* else:
-                 *   We saw the first character of the next line. Thus,
-                 *   the current line is terminated by the CR. Just
-                 *   ignore whatever we peeked at. The next reader will
-                 *   see it and handle it as appropriate.
-                 */
-
-                /* Whatever was read, the line is now ready for use. */
-                linebuf->state = SERF_LINEBUF_READY;
-            } else {
-                /* no data available, try again later. */
-                return APR_EAGAIN;
-            }
-        }
-        else {
-            int found;
-
-            status = serf_bucket_readline(bucket, acceptable, &found,
-                                          &data, &len);
-            if (SERF_BUCKET_READ_ERROR(status)) {
-                return status;
-            }
-            /* Some bucket types (socket) might need an extra read to find
-               out EOF state, so they'll return no data in that read. This
-               means we're done reading, return what we got. */
-            if (APR_STATUS_IS_EOF(status) && len == 0) {
-	        return status;
-            }
-            if (linebuf->used + len > sizeof(linebuf->line)) {
-                /* ### need a "line too long" error */
-                return APR_EGENERAL;
-            }
-
-            /* Note: our logic doesn't change for SERF_LINEBUF_PARTIAL. That
-             * only affects how we fill the buffer. It is a communication to
-             * our caller on whether the line is ready or not.
-             */
-
-            /* If we didn't see a newline, then we should mark the line
-             * buffer as partially complete.
-             */
-            if (found == SERF_NEWLINE_NONE) {
-                linebuf->state = SERF_LINEBUF_PARTIAL;
-            }
-            else if (found == SERF_NEWLINE_CRLF_SPLIT) {
-                linebuf->state = SERF_LINEBUF_CRLF_SPLIT;
-
-                /* Toss the partial CR. We won't ever need it. */
-                --len;
-            }
-            else {
-                /* We got a newline (of some form). We don't need it
-                 * in the line buffer, so back up the length. Then
-                 * mark the line as ready.
-                 */
-                len -= 1 + (found == SERF_NEWLINE_CRLF);
-
-                linebuf->state = SERF_LINEBUF_READY;
-            }
-
-            /* ### it would be nice to avoid this copy if at all possible,
-               ### and just return the a data/len pair to the caller. we're
-               ### keeping it simple for now. */
-            memcpy(&linebuf->line[linebuf->used], data, len);
-            linebuf->used += len;
-        }
-
-        /* If we saw anything besides "success. please read again", then
-         * we should return that status. If the line was completed, then
-         * we should also return.
-         */
-        if (status || linebuf->state == SERF_LINEBUF_READY)
-            return status;
-
-        /* We got APR_SUCCESS and the line buffer is not complete. Let's
-         * loop to read some more data.
-         */
-    }
-    /* NOTREACHED */
-}
-
-/* Logging functions.
-   Use with one of the [COMP]_VERBOSE defines so that the compiler knows to
-   optimize this code out when no logging is needed. */
-static void log_time()
-{
-    apr_time_exp_t tm;
-
-    apr_time_exp_lt(&tm, apr_time_now());
-    fprintf(stderr, "[%d-%02d-%02dT%02d:%02d:%02d.%06d%+03d] ",
-            1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday,
-            tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec,
-            tm.tm_gmtoff/3600);
-}
-
-void serf__log(int verbose_flag, const char *filename, const char *fmt, ...)
-{
-    va_list argp;
-
-    if (verbose_flag) {
-        log_time();
-
-        if (filename)
-            fprintf(stderr, "%s: ", filename);
-
-        va_start(argp, fmt);
-        vfprintf(stderr, fmt, argp);
-        va_end(argp);
-    }
-}
-
-void serf__log_nopref(int verbose_flag, const char *fmt, ...)
-{
-    va_list argp;
-
-    if (verbose_flag) {
-        va_start(argp, fmt);
-        vfprintf(stderr, fmt, argp);
-        va_end(argp);
-    }
-}
-
-void serf__log_skt(int verbose_flag, const char *filename, apr_socket_t *skt,
-                   const char *fmt, ...)
-{
-    va_list argp;
-
-    if (verbose_flag) {
-        apr_sockaddr_t *sa;
-        log_time();
-
-        if (skt) {
-            /* Log local and remote ip address:port */
-            fprintf(stderr, "[l:");
-            if (apr_socket_addr_get(&sa, APR_LOCAL, skt) == APR_SUCCESS) {
-                char buf[32];
-                apr_sockaddr_ip_getbuf(buf, 32, sa);
-                fprintf(stderr, "%s:%d", buf, sa->port);
-            }
-            fprintf(stderr, " r:");
-            if (apr_socket_addr_get(&sa, APR_REMOTE, skt) == APR_SUCCESS) {
-                char buf[32];
-                apr_sockaddr_ip_getbuf(buf, 32, sa);
-                fprintf(stderr, "%s:%d", buf, sa->port);
-            }
-            fprintf(stderr, "] ");
-        }
-
-        if (filename)
-            fprintf(stderr, "%s: ", filename);
-
-        va_start(argp, fmt);
-        vfprintf(stderr, fmt, argp);
-        va_end(argp);
-    }
-}
-

Copied: vendor/serf/1.3.9/buckets/buckets.c (from rev 9259, vendor/serf/dist/buckets/buckets.c)
===================================================================
--- vendor/serf/1.3.9/buckets/buckets.c	                        (rev 0)
+++ vendor/serf/1.3.9/buckets/buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,645 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_pools.h>
+
+#include "serf.h"
+#include "serf_bucket_util.h"
+#include "serf_private.h"
+
+serf_bucket_t *serf_bucket_create(
+    const serf_bucket_type_t *type,
+    serf_bucket_alloc_t *allocator,
+    void *data)
+{
+    serf_bucket_t *bkt = serf_bucket_mem_alloc(allocator, sizeof(*bkt));
+
+    bkt->type = type;
+    bkt->data = data;
+    bkt->allocator = allocator;
+
+    return bkt;
+}
+
+
+apr_status_t serf_default_read_iovec(
+    serf_bucket_t *bucket,
+    apr_size_t requested,
+    int vecs_size,
+    struct iovec *vecs,
+    int *vecs_used)
+{
+    const char *data;
+    apr_size_t len;
+
+    /* Read some data from the bucket.
+     *
+     * Because we're an internal 'helper' to the bucket, we can't call the
+     * normal serf_bucket_read() call because the debug allocator tracker will
+     * end up marking the bucket as read *twice* - once for us and once for
+     * our caller - which is reading the same bucket.  This leads to premature
+     * abort()s if we ever see EAGAIN.  Instead, we'll go directly to the
+     * vtable and bypass the debug tracker.
+     */
+    apr_status_t status = bucket->type->read(bucket, requested, &data, &len);
+
+    /* assert that vecs_size >= 1 ? */
+
+    /* Return that data as a single iovec. */
+    if (len) {
+        vecs[0].iov_base = (void *)data; /* loses the 'const' */
+        vecs[0].iov_len = len;
+        *vecs_used = 1;
+    }
+    else {
+        *vecs_used = 0;
+    }
+
+    return status;
+}
+
+
+apr_status_t serf_default_read_for_sendfile(
+    serf_bucket_t *bucket,
+    apr_size_t requested,
+    apr_hdtr_t *hdtr,
+    apr_file_t **file,
+    apr_off_t *offset,
+    apr_size_t *len)
+{
+    /* Read a bunch of stuff into the headers.
+     *
+     * See serf_default_read_iovec as to why we call into the vtable
+     * directly.
+     */
+    apr_status_t status = bucket->type->read_iovec(bucket, requested,
+                                                   hdtr->numheaders,
+                                                   hdtr->headers,
+                                                   &hdtr->numheaders);
+
+    /* There isn't a file, and there are no trailers. */
+    *file = NULL;
+    hdtr->numtrailers = 0;
+
+    return status;
+}
+
+
+serf_bucket_t *serf_default_read_bucket(
+    serf_bucket_t *bucket,
+    const serf_bucket_type_t *type)
+{
+    return NULL;
+}
+
+
+void serf_default_destroy(serf_bucket_t *bucket)
+{
+#ifdef SERF_DEBUG_BUCKET_USE
+    serf_debug__bucket_destroy(bucket);
+#endif
+
+    serf_bucket_mem_free(bucket->allocator, bucket);
+}
+
+
+void serf_default_destroy_and_data(serf_bucket_t *bucket)
+{
+    serf_bucket_mem_free(bucket->allocator, bucket->data);
+    serf_default_destroy(bucket);
+}
+
+
+/* ==================================================================== */
+
+
+char *serf_bstrmemdup(serf_bucket_alloc_t *allocator,
+                      const char *str,
+                      apr_size_t size)
+{
+    char *newstr = serf_bucket_mem_alloc(allocator, size + 1);
+    memcpy(newstr, str, size);
+    newstr[size] = '\0';
+    return newstr;
+}
+
+
+void *serf_bmemdup(serf_bucket_alloc_t *allocator,
+                   const void *mem,
+                   apr_size_t size)
+{
+    void *newmem = serf_bucket_mem_alloc(allocator, size);
+    memcpy(newmem, mem, size);
+    return newmem;
+}
+
+
+char *serf_bstrdup(serf_bucket_alloc_t *allocator,
+                   const char *str)
+{
+    apr_size_t size = strlen(str) + 1;
+    char *newstr = serf_bucket_mem_alloc(allocator, size);
+    memcpy(newstr, str, size);
+    return newstr;
+}
+
+char *serf_bstrcatv(serf_bucket_alloc_t *allocator, struct iovec *vec,
+                    int vecs, apr_size_t *bytes_written)
+{
+    int i;
+    apr_size_t new_len = 0;
+    char *c, *newstr;
+
+    for (i = 0; i < vecs; i++) {
+        new_len += vec[i].iov_len;
+    }
+
+    /* It's up to the caller to free this memory later. */
+    newstr = serf_bucket_mem_alloc(allocator, new_len);
+
+    c = newstr;
+    for (i = 0; i < vecs; i++) {
+        memcpy(c, vec[i].iov_base, vec[i].iov_len);
+        c += vec[i].iov_len;
+    }
+
+    if (bytes_written) {
+        *bytes_written = c - newstr;
+    }
+
+    return newstr;
+}
+
+/* ==================================================================== */
+
+
+static void find_crlf(const char **data, apr_size_t *len, int *found)
+{
+    const char *start = *data;
+    const char *end = start + *len;
+
+    while (start < end) {
+        const char *cr = memchr(start, '\r', *len);
+
+        if (cr == NULL) {
+            break;
+        }
+        ++cr;
+
+        if (cr < end && cr[0] == '\n') {
+            *len -= cr + 1 - start;
+            *data = cr + 1;
+            *found = SERF_NEWLINE_CRLF;
+            return;
+        }
+        if (cr == end) {
+            *len = 0;
+            *data = end;
+            *found = SERF_NEWLINE_CRLF_SPLIT;
+            return;
+        }
+
+        /* It was a bare CR without an LF. Just move past it. */
+        *len -= cr - start;
+        start = cr;
+    }
+
+    *data = start + *len;
+    *len -= *data - start;
+    *found = SERF_NEWLINE_NONE;
+}
+
+
+void serf_util_readline(
+    const char **data,
+    apr_size_t *len,
+    int acceptable,
+    int *found)
+{
+    const char *start;
+    const char *cr;
+    const char *lf;
+    int want_cr;
+    int want_crlf;
+    int want_lf;
+
+    /* If _only_ CRLF is acceptable, then the scanning needs a loop to
+     * skip false hits on CR characters. Use a separate function.
+     */
+    if (acceptable == SERF_NEWLINE_CRLF) {
+        find_crlf(data, len, found);
+        return;
+    }
+
+    start = *data;
+    cr = lf = NULL;
+    want_cr = acceptable & SERF_NEWLINE_CR;
+    want_crlf = acceptable & SERF_NEWLINE_CRLF;
+    want_lf = acceptable & SERF_NEWLINE_LF;
+
+    if (want_cr || want_crlf) {
+        cr = memchr(start, '\r', *len);
+    }
+    if (want_lf) {
+        lf = memchr(start, '\n', *len);
+    }
+
+    if (cr != NULL) {
+        if (lf != NULL) {
+            if (cr + 1 == lf)
+                *found = want_crlf ? SERF_NEWLINE_CRLF : SERF_NEWLINE_CR;
+            else if (want_cr && cr < lf)
+                *found = SERF_NEWLINE_CR;
+            else
+                *found = SERF_NEWLINE_LF;
+        }
+        else if (cr == start + *len - 1) {
+            /* the CR occurred in the last byte of the buffer. this could be
+             * a CRLF split across the data boundary.
+             * ### FIX THIS LOGIC? does caller need to detect?
+             */
+            *found = want_crlf ? SERF_NEWLINE_CRLF_SPLIT : SERF_NEWLINE_CR;
+        }
+        else if (want_cr)
+            *found = SERF_NEWLINE_CR;
+        else /* want_crlf */
+            *found = SERF_NEWLINE_NONE;
+    }
+    else if (lf != NULL)
+        *found = SERF_NEWLINE_LF;
+    else
+        *found = SERF_NEWLINE_NONE;
+
+    switch (*found) {
+      case SERF_NEWLINE_LF:
+        *data = lf + 1;
+        break;
+      case SERF_NEWLINE_CR:
+      case SERF_NEWLINE_CRLF:
+      case SERF_NEWLINE_CRLF_SPLIT:
+        *data = cr + 1 + (*found == SERF_NEWLINE_CRLF);
+        break;
+      case SERF_NEWLINE_NONE:
+        *data += *len;
+        break;
+      default:
+        /* Not reachable */
+        return;
+    }
+
+    *len -= *data - start;
+}
+
+
+/* ==================================================================== */
+
+
+void serf_databuf_init(serf_databuf_t *databuf)
+{
+    /* nothing is sitting in the buffer */
+    databuf->remaining = 0;
+
+    /* avoid thinking we have hit EOF */
+    databuf->status = APR_SUCCESS;
+}
+
+/* Ensure the buffer is prepared for reading. Will return APR_SUCCESS,
+ * APR_EOF, or some failure code. *len is only set for EOF. */
+static apr_status_t common_databuf_prep(serf_databuf_t *databuf,
+                                        apr_size_t *len)
+{
+    apr_size_t readlen;
+    apr_status_t status;
+
+    /* if there is data in the buffer, then we're happy. */
+    if (databuf->remaining > 0)
+        return APR_SUCCESS;
+
+    /* if we already hit EOF, then keep returning that. */
+    if (APR_STATUS_IS_EOF(databuf->status)) {
+        /* *data = NULL;   ?? */
+        *len = 0;
+        return APR_EOF;
+    }
+
+    /* refill the buffer */
+    status = (*databuf->read)(databuf->read_baton, sizeof(databuf->buf),
+                              databuf->buf, &readlen);
+    if (SERF_BUCKET_READ_ERROR(status)) {
+        return status;
+    }
+
+    databuf->current = databuf->buf;
+    databuf->remaining = readlen;
+    databuf->status = status;
+
+    return APR_SUCCESS;
+}
+
+
+apr_status_t serf_databuf_read(
+    serf_databuf_t *databuf,
+    apr_size_t requested,
+    const char **data,
+    apr_size_t *len)
+{
+    apr_status_t status = common_databuf_prep(databuf, len);
+    if (status)
+        return status;
+
+    /* peg the requested amount to what we have remaining */
+    if (requested == SERF_READ_ALL_AVAIL || requested > databuf->remaining)
+        requested = databuf->remaining;
+
+    /* return the values */
+    *data = databuf->current;
+    *len = requested;
+
+    /* adjust our internal state to note we've consumed some data */
+    databuf->current += requested;
+    databuf->remaining -= requested;
+
+    /* If we read everything, then we need to return whatever the data
+     * read returned to us. This is going to be APR_EOF or APR_EGAIN.
+     * If we have NOT read everything, then return APR_SUCCESS to indicate
+     * that we're ready to return some more if asked.
+     */
+    return databuf->remaining ? APR_SUCCESS : databuf->status;
+}
+
+
+apr_status_t serf_databuf_readline(
+    serf_databuf_t *databuf,
+    int acceptable,
+    int *found,
+    const char **data,
+    apr_size_t *len)
+{
+    apr_status_t status = common_databuf_prep(databuf, len);
+    if (status)
+        return status;
+
+    /* the returned line will start at the current position. */
+    *data = databuf->current;
+
+    /* read a line from the buffer, and adjust the various pointers. */
+    serf_util_readline(&databuf->current, &databuf->remaining, acceptable,
+                       found);
+
+    /* the length matches the amount consumed by the readline */
+    *len = databuf->current - *data;
+
+    /* see serf_databuf_read's return condition */
+    return databuf->remaining ? APR_SUCCESS : databuf->status;
+}
+
+
+apr_status_t serf_databuf_peek(
+    serf_databuf_t *databuf,
+    const char **data,
+    apr_size_t *len)
+{
+    apr_status_t status = common_databuf_prep(databuf, len);
+    if (status)
+        return status;
+
+    /* return everything we have */
+    *data = databuf->current;
+    *len = databuf->remaining;
+
+    /* If the last read returned EOF, then the peek should return the same.
+     * The other possibility in databuf->status is APR_EAGAIN, which we
+     * should never return. Thus, just return APR_SUCCESS for non-EOF cases.
+     */
+    if (APR_STATUS_IS_EOF(databuf->status))
+        return APR_EOF;
+    return APR_SUCCESS;
+}
+
+
+/* ==================================================================== */
+
+
+void serf_linebuf_init(serf_linebuf_t *linebuf)
+{
+    linebuf->state = SERF_LINEBUF_EMPTY;
+    linebuf->used = 0;
+}
+
+
+apr_status_t serf_linebuf_fetch(
+    serf_linebuf_t *linebuf,
+    serf_bucket_t *bucket,
+    int acceptable)
+{
+    /* If we had a complete line, then assume the caller has used it, so
+     * we can now reset the state.
+     */
+    if (linebuf->state == SERF_LINEBUF_READY) {
+        linebuf->state = SERF_LINEBUF_EMPTY;
+
+        /* Reset the line_used, too, so we don't have to test the state
+         * before using this value.
+         */
+        linebuf->used = 0;
+    }
+
+    while (1) {
+        apr_status_t status;
+        const char *data;
+        apr_size_t len;
+
+        if (linebuf->state == SERF_LINEBUF_CRLF_SPLIT) {
+            /* On the previous read, we received just a CR. The LF might
+             * be present, but the bucket couldn't see it. We need to
+             * examine a single character to determine how to handle the
+             * split CRLF.
+             */
+
+            status = serf_bucket_peek(bucket, &data, &len);
+            if (SERF_BUCKET_READ_ERROR(status))
+                return status;
+
+            if (len > 0) {
+                if (*data == '\n') {
+                    /* We saw the second part of CRLF. We don't need to
+                     * save that character, so do an actual read to suck
+                     * up that character.
+                     */
+                    /* ### check status */
+                    (void) serf_bucket_read(bucket, 1, &data, &len);
+                }
+                /* else:
+                 *   We saw the first character of the next line. Thus,
+                 *   the current line is terminated by the CR. Just
+                 *   ignore whatever we peeked at. The next reader will
+                 *   see it and handle it as appropriate.
+                 */
+
+                /* Whatever was read, the line is now ready for use. */
+                linebuf->state = SERF_LINEBUF_READY;
+            } else {
+                /* no data available, try again later. */
+                return APR_EAGAIN;
+            }
+        }
+        else {
+            int found;
+
+            status = serf_bucket_readline(bucket, acceptable, &found,
+                                          &data, &len);
+            if (SERF_BUCKET_READ_ERROR(status)) {
+                return status;
+            }
+            /* Some bucket types (socket) might need an extra read to find
+               out EOF state, so they'll return no data in that read. This
+               means we're done reading, return what we got. */
+            if (APR_STATUS_IS_EOF(status) && len == 0) {
+	        return status;
+            }
+            if (linebuf->used + len > sizeof(linebuf->line)) {
+                /* ### need a "line too long" error */
+                return APR_EGENERAL;
+            }
+
+            /* Note: our logic doesn't change for SERF_LINEBUF_PARTIAL. That
+             * only affects how we fill the buffer. It is a communication to
+             * our caller on whether the line is ready or not.
+             */
+
+            /* If we didn't see a newline, then we should mark the line
+             * buffer as partially complete.
+             */
+            if (found == SERF_NEWLINE_NONE) {
+                linebuf->state = SERF_LINEBUF_PARTIAL;
+            }
+            else if (found == SERF_NEWLINE_CRLF_SPLIT) {
+                linebuf->state = SERF_LINEBUF_CRLF_SPLIT;
+
+                /* Toss the partial CR. We won't ever need it. */
+                --len;
+            }
+            else {
+                /* We got a newline (of some form). We don't need it
+                 * in the line buffer, so back up the length. Then
+                 * mark the line as ready.
+                 */
+                len -= 1 + (found == SERF_NEWLINE_CRLF);
+
+                linebuf->state = SERF_LINEBUF_READY;
+            }
+
+            /* ### it would be nice to avoid this copy if at all possible,
+               ### and just return the a data/len pair to the caller. we're
+               ### keeping it simple for now. */
+            memcpy(&linebuf->line[linebuf->used], data, len);
+            linebuf->used += len;
+        }
+
+        /* If we saw anything besides "success. please read again", then
+         * we should return that status. If the line was completed, then
+         * we should also return.
+         */
+        if (status || linebuf->state == SERF_LINEBUF_READY)
+            return status;
+
+        /* We got APR_SUCCESS and the line buffer is not complete. Let's
+         * loop to read some more data.
+         */
+    }
+    /* NOTREACHED */
+}
+
+/* Logging functions.
+   Use with one of the [COMP]_VERBOSE defines so that the compiler knows to
+   optimize this code out when no logging is needed. */
+static void log_time()
+{
+    apr_time_exp_t tm;
+
+    apr_time_exp_lt(&tm, apr_time_now());
+    fprintf(stderr, "[%d-%02d-%02dT%02d:%02d:%02d.%06d%+03d] ",
+            1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday,
+            tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec,
+            tm.tm_gmtoff/3600);
+}
+
+void serf__log(int verbose_flag, const char *filename, const char *fmt, ...)
+{
+    va_list argp;
+
+    if (verbose_flag) {
+        log_time();
+
+        if (filename)
+            fprintf(stderr, "%s: ", filename);
+
+        va_start(argp, fmt);
+        vfprintf(stderr, fmt, argp);
+        va_end(argp);
+    }
+}
+
+void serf__log_nopref(int verbose_flag, const char *fmt, ...)
+{
+    va_list argp;
+
+    if (verbose_flag) {
+        va_start(argp, fmt);
+        vfprintf(stderr, fmt, argp);
+        va_end(argp);
+    }
+}
+
+void serf__log_skt(int verbose_flag, const char *filename, apr_socket_t *skt,
+                   const char *fmt, ...)
+{
+    va_list argp;
+
+    if (verbose_flag) {
+        apr_sockaddr_t *sa;
+        log_time();
+
+        if (skt) {
+            /* Log local and remote ip address:port */
+            fprintf(stderr, "[l:");
+            if (apr_socket_addr_get(&sa, APR_LOCAL, skt) == APR_SUCCESS) {
+                char buf[32];
+                apr_sockaddr_ip_getbuf(buf, 32, sa);
+                fprintf(stderr, "%s:%d", buf, sa->port);
+            }
+            fprintf(stderr, " r:");
+            if (apr_socket_addr_get(&sa, APR_REMOTE, skt) == APR_SUCCESS) {
+                char buf[32];
+                apr_sockaddr_ip_getbuf(buf, 32, sa);
+                fprintf(stderr, "%s:%d", buf, sa->port);
+            }
+            fprintf(stderr, "] ");
+        }
+
+        if (filename)
+            fprintf(stderr, "%s: ", filename);
+
+        va_start(argp, fmt);
+        vfprintf(stderr, fmt, argp);
+        va_end(argp);
+    }
+}
+

Deleted: vendor/serf/1.3.9/buckets/bwtp_buckets.c
===================================================================
--- vendor/serf/dist/buckets/bwtp_buckets.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/buckets/bwtp_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,596 +0,0 @@
-/* Copyright 2002-2004 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_pools.h>
-#include <apr_strings.h>
-#include <apr_lib.h>
-#include <apr_date.h>
-
-#include "serf.h"
-#include "serf_bucket_util.h"
-#include "serf_bucket_types.h"
-
-#include <stdlib.h>
-
-/* This is an implementation of Bidirectional Web Transfer Protocol (BWTP)
- * See:
- *   http://bwtp.wikidot.com/
- */
-
-typedef struct {
-    int channel;
-    int open;
-    int type; /* 0 = header, 1 = message */ /* TODO enum? */
-    const char *phrase;
-    serf_bucket_t *headers;
-
-    char req_line[1000];
-} frame_context_t;
-
-typedef struct {
-    serf_bucket_t *stream;
-    serf_bucket_t *body;        /* Pointer to the stream wrapping the body. */
-    serf_bucket_t *headers;     /* holds parsed headers */
-
-    enum {
-        STATE_STATUS_LINE,      /* reading status line */
-        STATE_HEADERS,          /* reading headers */
-        STATE_BODY,             /* reading body */
-        STATE_DONE              /* we've sent EOF */
-    } state;
-
-    /* Buffer for accumulating a line from the response. */
-    serf_linebuf_t linebuf;
-
-    int type; /* 0 = header, 1 = message */ /* TODO enum? */
-    int channel;
-    char *phrase;
-    apr_size_t length;
-} incoming_context_t;
-
-
-serf_bucket_t *serf_bucket_bwtp_channel_close(
-    int channel,
-    serf_bucket_alloc_t *allocator)
-{
-    frame_context_t *ctx;
-
-    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
-    ctx->type = 0;
-    ctx->open = 0;
-    ctx->channel = channel;
-    ctx->phrase = "CLOSED";
-    ctx->headers = serf_bucket_headers_create(allocator);
-
-    return serf_bucket_create(&serf_bucket_type_bwtp_frame, allocator, ctx);
-}
-
-serf_bucket_t *serf_bucket_bwtp_channel_open(
-    int channel,
-    const char *uri,
-    serf_bucket_alloc_t *allocator)
-{
-    frame_context_t *ctx;
-
-    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
-    ctx->type = 0;
-    ctx->open = 1;
-    ctx->channel = channel;
-    ctx->phrase = uri;
-    ctx->headers = serf_bucket_headers_create(allocator);
-
-    return serf_bucket_create(&serf_bucket_type_bwtp_frame, allocator, ctx);
-}
-
-serf_bucket_t *serf_bucket_bwtp_header_create(
-    int channel,
-    const char *phrase,
-    serf_bucket_alloc_t *allocator)
-{
-    frame_context_t *ctx;
-
-    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
-    ctx->type = 0;
-    ctx->open = 0;
-    ctx->channel = channel;
-    ctx->phrase = phrase;
-    ctx->headers = serf_bucket_headers_create(allocator);
-
-    return serf_bucket_create(&serf_bucket_type_bwtp_frame, allocator, ctx);
-}
-
-serf_bucket_t *serf_bucket_bwtp_message_create(
-    int channel,
-    serf_bucket_t *body,
-    serf_bucket_alloc_t *allocator)
-{
-    frame_context_t *ctx;
-
-    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
-    ctx->type = 1;
-    ctx->open = 0;
-    ctx->channel = channel;
-    ctx->phrase = "MESSAGE";
-    ctx->headers = serf_bucket_headers_create(allocator);
-
-    return serf_bucket_create(&serf_bucket_type_bwtp_frame, allocator, ctx);
-}
-
-int serf_bucket_bwtp_frame_get_channel(
-    serf_bucket_t *bucket)
-{
-    if (SERF_BUCKET_IS_BWTP_FRAME(bucket)) {
-        frame_context_t *ctx = bucket->data;
-
-        return ctx->channel;
-    }
-    else if (SERF_BUCKET_IS_BWTP_INCOMING_FRAME(bucket)) {
-        incoming_context_t *ctx = bucket->data;
-
-        return ctx->channel;
-    }
-
-    return -1;
-}
-
-int serf_bucket_bwtp_frame_get_type(
-    serf_bucket_t *bucket)
-{
-    if (SERF_BUCKET_IS_BWTP_FRAME(bucket)) {
-        frame_context_t *ctx = bucket->data;
-
-        return ctx->type;
-    }
-    else if (SERF_BUCKET_IS_BWTP_INCOMING_FRAME(bucket)) {
-        incoming_context_t *ctx = bucket->data;
-
-        return ctx->type;
-    }
-
-    return -1;
-}
-
-const char *serf_bucket_bwtp_frame_get_phrase(
-    serf_bucket_t *bucket)
-{
-    if (SERF_BUCKET_IS_BWTP_FRAME(bucket)) {
-        frame_context_t *ctx = bucket->data;
-
-        return ctx->phrase;
-    }
-    else if (SERF_BUCKET_IS_BWTP_INCOMING_FRAME(bucket)) {
-        incoming_context_t *ctx = bucket->data;
-
-        return ctx->phrase;
-    }
-
-    return NULL;
-}
-
-serf_bucket_t *serf_bucket_bwtp_frame_get_headers(
-    serf_bucket_t *bucket)
-{
-    if (SERF_BUCKET_IS_BWTP_FRAME(bucket)) {
-        frame_context_t *ctx = bucket->data;
-
-        return ctx->headers;
-    }
-    else if (SERF_BUCKET_IS_BWTP_INCOMING_FRAME(bucket)) {
-        incoming_context_t *ctx = bucket->data;
-
-        return ctx->headers;
-    }
-
-    return NULL;
-}
-
-static int count_size(void *baton, const char *key, const char *value)
-{
-    apr_size_t *c = baton;
-    /* TODO Deal with folding.  Yikes. */
-
-    /* Add in ": " and CRLF - so an extra four bytes. */
-    *c += strlen(key) + strlen(value) + 4;
-
-    return 0;
-}
-
-static apr_size_t calc_header_size(serf_bucket_t *hdrs)
-{
-    apr_size_t size = 0;
-
-    serf_bucket_headers_do(hdrs, count_size, &size);
-
-    return size;
-}
-
-static void serialize_data(serf_bucket_t *bucket)
-{
-    frame_context_t *ctx = bucket->data;
-    serf_bucket_t *new_bucket;
-    apr_size_t req_len;
-
-    /* Serialize the request-line and headers into one mother string,
-     * and wrap a bucket around it.
-     */
-    req_len = apr_snprintf(ctx->req_line, sizeof(ctx->req_line),
-                           "%s %d " "%" APR_UINT64_T_HEX_FMT " %s%s\r\n",
-                           (ctx->type ? "BWM" : "BWH"),
-                           ctx->channel, calc_header_size(ctx->headers),
-                           (ctx->open ? "OPEN " : ""),
-                           ctx->phrase);
-    new_bucket = serf_bucket_simple_copy_create(ctx->req_line, req_len,
-                                                bucket->allocator);
-
-    /* Build up the new bucket structure.
-     *
-     * Note that self needs to become an aggregate bucket so that a
-     * pointer to self still represents the "right" data.
-     */
-    serf_bucket_aggregate_become(bucket);
-
-    /* Insert the two buckets. */
-    serf_bucket_aggregate_append(bucket, new_bucket);
-    serf_bucket_aggregate_append(bucket, ctx->headers);
-
-    /* Our private context is no longer needed, and is not referred to by
-     * any existing bucket. Toss it.
-     */
-    serf_bucket_mem_free(bucket->allocator, ctx);
-}
-
-static apr_status_t serf_bwtp_frame_read(serf_bucket_t *bucket,
-                                         apr_size_t requested,
-                                         const char **data, apr_size_t *len)
-{
-    /* Seralize our private data into a new aggregate bucket. */
-    serialize_data(bucket);
-
-    /* Delegate to the "new" aggregate bucket to do the read. */
-    return serf_bucket_read(bucket, requested, data, len);
-}
-
-static apr_status_t serf_bwtp_frame_readline(serf_bucket_t *bucket,
-                                             int acceptable, int *found,
-                                             const char **data, apr_size_t *len)
-{
-    /* Seralize our private data into a new aggregate bucket. */
-    serialize_data(bucket);
-
-    /* Delegate to the "new" aggregate bucket to do the readline. */
-    return serf_bucket_readline(bucket, acceptable, found, data, len);
-}
-
-static apr_status_t serf_bwtp_frame_read_iovec(serf_bucket_t *bucket,
-                                               apr_size_t requested,
-                                               int vecs_size,
-                                               struct iovec *vecs,
-                                               int *vecs_used)
-{
-    /* Seralize our private data into a new aggregate bucket. */
-    serialize_data(bucket);
-
-    /* Delegate to the "new" aggregate bucket to do the read. */
-    return serf_bucket_read_iovec(bucket, requested,
-                                  vecs_size, vecs, vecs_used);
-}
-
-static apr_status_t serf_bwtp_frame_peek(serf_bucket_t *bucket,
-                                         const char **data,
-                                         apr_size_t *len)
-{
-    /* Seralize our private data into a new aggregate bucket. */
-    serialize_data(bucket);
-
-    /* Delegate to the "new" aggregate bucket to do the peek. */
-    return serf_bucket_peek(bucket, data, len);
-}
-
-const serf_bucket_type_t serf_bucket_type_bwtp_frame = {
-    "BWTP-FRAME",
-    serf_bwtp_frame_read,
-    serf_bwtp_frame_readline,
-    serf_bwtp_frame_read_iovec,
-    serf_default_read_for_sendfile,
-    serf_default_read_bucket,
-    serf_bwtp_frame_peek,
-    serf_default_destroy_and_data,
-};
-
-
-serf_bucket_t *serf_bucket_bwtp_incoming_frame_create(
-    serf_bucket_t *stream,
-    serf_bucket_alloc_t *allocator)
-{
-    incoming_context_t *ctx;
-
-    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
-    ctx->stream = stream;
-    ctx->body = NULL;
-    ctx->headers = serf_bucket_headers_create(allocator);
-    ctx->state = STATE_STATUS_LINE;
-    ctx->length = 0;
-    ctx->channel = -1;
-    ctx->phrase = NULL;
-
-    serf_linebuf_init(&ctx->linebuf);
-
-    return serf_bucket_create(&serf_bucket_type_bwtp_incoming_frame, allocator, ctx);
-}
-
-static void bwtp_incoming_destroy_and_data(serf_bucket_t *bucket)
-{
-    incoming_context_t *ctx = bucket->data;
-
-    if (ctx->state != STATE_STATUS_LINE && ctx->phrase) {
-        serf_bucket_mem_free(bucket->allocator, (void*)ctx->phrase);
-    }
-
-    serf_bucket_destroy(ctx->stream);
-    if (ctx->body != NULL)
-        serf_bucket_destroy(ctx->body);
-    serf_bucket_destroy(ctx->headers);
-
-    serf_default_destroy_and_data(bucket);
-}
-
-static apr_status_t fetch_line(incoming_context_t *ctx, int acceptable)
-{
-    return serf_linebuf_fetch(&ctx->linebuf, ctx->stream, acceptable);
-}
-
-static apr_status_t parse_status_line(incoming_context_t *ctx,
-                                      serf_bucket_alloc_t *allocator)
-{
-    int res;
-    char *reason; /* ### stupid APR interface makes this non-const */
-
-    /* ctx->linebuf.line should be of form: BW* */
-    res = apr_date_checkmask(ctx->linebuf.line, "BW*");
-    if (!res) {
-        /* Not an BWTP response?  Well, at least we won't understand it. */
-        return APR_EGENERAL;
-    }
-
-    if (ctx->linebuf.line[2] == 'H') {
-        ctx->type = 0;
-    }
-    else if (ctx->linebuf.line[2] == 'M') {
-        ctx->type = 1;
-    }
-    else {
-        ctx->type = -1;
-    }
-
-    ctx->channel = apr_strtoi64(ctx->linebuf.line + 3, &reason, 16);
-
-    /* Skip leading spaces for the reason string. */
-    if (apr_isspace(*reason)) {
-        reason++;
-    }
-
-    ctx->length = apr_strtoi64(reason, &reason, 16);
-
-    /* Skip leading spaces for the reason string. */
-    if (reason - ctx->linebuf.line < ctx->linebuf.used) {
-        if (apr_isspace(*reason)) {
-            reason++;
-        }
-
-        ctx->phrase = serf_bstrmemdup(allocator, reason,
-                                      ctx->linebuf.used
-                                      - (reason - ctx->linebuf.line));
-    } else {
-        ctx->phrase = NULL;
-    }
-
-    return APR_SUCCESS;
-}
-
-/* This code should be replaced with header buckets. */
-static apr_status_t fetch_headers(serf_bucket_t *bkt, incoming_context_t *ctx)
-{
-    apr_status_t status;
-
-    /* RFC 2616 says that CRLF is the only line ending, but we can easily
-     * accept any kind of line ending.
-     */
-    status = fetch_line(ctx, SERF_NEWLINE_ANY);
-    if (SERF_BUCKET_READ_ERROR(status)) {
-        return status;
-    }
-    /* Something was read. Process it. */
-
-    if (ctx->linebuf.state == SERF_LINEBUF_READY && ctx->linebuf.used) {
-        const char *end_key;
-        const char *c;
-
-        end_key = c = memchr(ctx->linebuf.line, ':', ctx->linebuf.used);
-        if (!c) {
-            /* Bad headers? */
-            return APR_EGENERAL;
-        }
-
-        /* Skip over initial : and spaces. */
-        while (apr_isspace(*++c))
-            continue;
-
-        /* Always copy the headers (from the linebuf into new mem). */
-        /* ### we should be able to optimize some mem copies */
-        serf_bucket_headers_setx(
-            ctx->headers,
-            ctx->linebuf.line, end_key - ctx->linebuf.line, 1,
-            c, ctx->linebuf.line + ctx->linebuf.used - c, 1);
-    }
-
-    return status;
-}
-
-/* Perform one iteration of the state machine.
- *
- * Will return when one the following conditions occurred:
- *  1) a state change
- *  2) an error
- *  3) the stream is not ready or at EOF
- *  4) APR_SUCCESS, meaning the machine can be run again immediately
- */
-static apr_status_t run_machine(serf_bucket_t *bkt, incoming_context_t *ctx)
-{
-    apr_status_t status = APR_SUCCESS; /* initialize to avoid gcc warnings */
-
-    switch (ctx->state) {
-    case STATE_STATUS_LINE:
-        /* RFC 2616 says that CRLF is the only line ending, but we can easily
-         * accept any kind of line ending.
-         */
-        status = fetch_line(ctx, SERF_NEWLINE_ANY);
-        if (SERF_BUCKET_READ_ERROR(status))
-            return status;
-
-        if (ctx->linebuf.state == SERF_LINEBUF_READY && ctx->linebuf.used) {
-            /* The Status-Line is in the line buffer. Process it. */
-            status = parse_status_line(ctx, bkt->allocator);
-            if (status)
-                return status;
-
-            if (ctx->length) {
-                ctx->body =
-                    serf_bucket_barrier_create(ctx->stream, bkt->allocator);
-                ctx->body = serf_bucket_limit_create(ctx->body, ctx->length,
-                                                     bkt->allocator);
-                if (!ctx->type) {
-                    ctx->state = STATE_HEADERS;
-                } else {
-                    ctx->state = STATE_BODY;
-                }
-            } else {
-                ctx->state = STATE_DONE;
-            }
-        }
-        else {
-            /* The connection closed before we could get the next
-             * response.  Treat the request as lost so that our upper
-             * end knows the server never tried to give us a response.
-             */
-            if (APR_STATUS_IS_EOF(status)) {
-                return SERF_ERROR_REQUEST_LOST;
-            }
-        }
-        break;
-    case STATE_HEADERS:
-        status = fetch_headers(ctx->body, ctx);
-        if (SERF_BUCKET_READ_ERROR(status))
-            return status;
-
-        /* If an empty line was read, then we hit the end of the headers.
-         * Move on to the body.
-         */
-        if (ctx->linebuf.state == SERF_LINEBUF_READY && !ctx->linebuf.used) {
-            /* Advance the state. */
-            ctx->state = STATE_DONE;
-        }
-        break;
-    case STATE_BODY:
-        /* Don't do anything. */
-        break;
-    case STATE_DONE:
-        return APR_EOF;
-    default:
-        /* Not reachable */
-        return APR_EGENERAL;
-    }
-
-    return status;
-}
-
-static apr_status_t wait_for_body(serf_bucket_t *bkt, incoming_context_t *ctx)
-{
-    apr_status_t status;
-
-    /* Keep reading and moving through states if we aren't at the BODY */
-    while (ctx->state != STATE_BODY) {
-        status = run_machine(bkt, ctx);
-
-        /* Anything other than APR_SUCCESS means that we cannot immediately
-         * read again (for now).
-         */
-        if (status)
-            return status;
-    }
-    /* in STATE_BODY */
-
-    return APR_SUCCESS;
-}
-
-apr_status_t serf_bucket_bwtp_incoming_frame_wait_for_headers(
-    serf_bucket_t *bucket)
-{
-    incoming_context_t *ctx = bucket->data;
-
-    return wait_for_body(bucket, ctx);
-}
-
-static apr_status_t bwtp_incoming_read(serf_bucket_t *bucket,
-                                       apr_size_t requested,
-                                       const char **data, apr_size_t *len)
-{
-    incoming_context_t *ctx = bucket->data;
-    apr_status_t rv;
-
-    rv = wait_for_body(bucket, ctx);
-    if (rv) {
-        /* It's not possible to have read anything yet! */
-        if (APR_STATUS_IS_EOF(rv) || APR_STATUS_IS_EAGAIN(rv)) {
-            *len = 0;
-        }
-        return rv;
-    }
-
-    rv = serf_bucket_read(ctx->body, requested, data, len);
-    if (APR_STATUS_IS_EOF(rv)) {
-        ctx->state = STATE_DONE;
-    }
-    return rv;
-}
-
-static apr_status_t bwtp_incoming_readline(serf_bucket_t *bucket,
-                                           int acceptable, int *found,
-                                           const char **data, apr_size_t *len)
-{
-    incoming_context_t *ctx = bucket->data;
-    apr_status_t rv;
-
-    rv = wait_for_body(bucket, ctx);
-    if (rv) {
-        return rv;
-    }
-
-    /* Delegate to the stream bucket to do the readline. */
-    return serf_bucket_readline(ctx->body, acceptable, found, data, len);
-}
-
-/* ### need to implement */
-#define bwtp_incoming_peek NULL
-
-const serf_bucket_type_t serf_bucket_type_bwtp_incoming_frame = {
-    "BWTP-INCOMING",
-    bwtp_incoming_read,
-    bwtp_incoming_readline,
-    serf_default_read_iovec,
-    serf_default_read_for_sendfile,
-    serf_default_read_bucket,
-    bwtp_incoming_peek,
-    bwtp_incoming_destroy_and_data,
-};

Copied: vendor/serf/1.3.9/buckets/bwtp_buckets.c (from rev 9259, vendor/serf/dist/buckets/bwtp_buckets.c)
===================================================================
--- vendor/serf/1.3.9/buckets/bwtp_buckets.c	                        (rev 0)
+++ vendor/serf/1.3.9/buckets/bwtp_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,601 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_pools.h>
+#include <apr_strings.h>
+#include <apr_lib.h>
+#include <apr_date.h>
+
+#include "serf.h"
+#include "serf_bucket_util.h"
+#include "serf_bucket_types.h"
+
+#include <stdlib.h>
+
+/* This is an implementation of Bidirectional Web Transfer Protocol (BWTP)
+ * See:
+ *   http://bwtp.wikidot.com/
+ */
+
+typedef struct {
+    int channel;
+    int open;
+    int type; /* 0 = header, 1 = message */ /* TODO enum? */
+    const char *phrase;
+    serf_bucket_t *headers;
+
+    char req_line[1000];
+} frame_context_t;
+
+typedef struct {
+    serf_bucket_t *stream;
+    serf_bucket_t *body;        /* Pointer to the stream wrapping the body. */
+    serf_bucket_t *headers;     /* holds parsed headers */
+
+    enum {
+        STATE_STATUS_LINE,      /* reading status line */
+        STATE_HEADERS,          /* reading headers */
+        STATE_BODY,             /* reading body */
+        STATE_DONE              /* we've sent EOF */
+    } state;
+
+    /* Buffer for accumulating a line from the response. */
+    serf_linebuf_t linebuf;
+
+    int type; /* 0 = header, 1 = message */ /* TODO enum? */
+    int channel;
+    char *phrase;
+    apr_size_t length;
+} incoming_context_t;
+
+
+serf_bucket_t *serf_bucket_bwtp_channel_close(
+    int channel,
+    serf_bucket_alloc_t *allocator)
+{
+    frame_context_t *ctx;
+
+    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
+    ctx->type = 0;
+    ctx->open = 0;
+    ctx->channel = channel;
+    ctx->phrase = "CLOSED";
+    ctx->headers = serf_bucket_headers_create(allocator);
+
+    return serf_bucket_create(&serf_bucket_type_bwtp_frame, allocator, ctx);
+}
+
+serf_bucket_t *serf_bucket_bwtp_channel_open(
+    int channel,
+    const char *uri,
+    serf_bucket_alloc_t *allocator)
+{
+    frame_context_t *ctx;
+
+    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
+    ctx->type = 0;
+    ctx->open = 1;
+    ctx->channel = channel;
+    ctx->phrase = uri;
+    ctx->headers = serf_bucket_headers_create(allocator);
+
+    return serf_bucket_create(&serf_bucket_type_bwtp_frame, allocator, ctx);
+}
+
+serf_bucket_t *serf_bucket_bwtp_header_create(
+    int channel,
+    const char *phrase,
+    serf_bucket_alloc_t *allocator)
+{
+    frame_context_t *ctx;
+
+    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
+    ctx->type = 0;
+    ctx->open = 0;
+    ctx->channel = channel;
+    ctx->phrase = phrase;
+    ctx->headers = serf_bucket_headers_create(allocator);
+
+    return serf_bucket_create(&serf_bucket_type_bwtp_frame, allocator, ctx);
+}
+
+serf_bucket_t *serf_bucket_bwtp_message_create(
+    int channel,
+    serf_bucket_t *body,
+    serf_bucket_alloc_t *allocator)
+{
+    frame_context_t *ctx;
+
+    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
+    ctx->type = 1;
+    ctx->open = 0;
+    ctx->channel = channel;
+    ctx->phrase = "MESSAGE";
+    ctx->headers = serf_bucket_headers_create(allocator);
+
+    return serf_bucket_create(&serf_bucket_type_bwtp_frame, allocator, ctx);
+}
+
+int serf_bucket_bwtp_frame_get_channel(
+    serf_bucket_t *bucket)
+{
+    if (SERF_BUCKET_IS_BWTP_FRAME(bucket)) {
+        frame_context_t *ctx = bucket->data;
+
+        return ctx->channel;
+    }
+    else if (SERF_BUCKET_IS_BWTP_INCOMING_FRAME(bucket)) {
+        incoming_context_t *ctx = bucket->data;
+
+        return ctx->channel;
+    }
+
+    return -1;
+}
+
+int serf_bucket_bwtp_frame_get_type(
+    serf_bucket_t *bucket)
+{
+    if (SERF_BUCKET_IS_BWTP_FRAME(bucket)) {
+        frame_context_t *ctx = bucket->data;
+
+        return ctx->type;
+    }
+    else if (SERF_BUCKET_IS_BWTP_INCOMING_FRAME(bucket)) {
+        incoming_context_t *ctx = bucket->data;
+
+        return ctx->type;
+    }
+
+    return -1;
+}
+
+const char *serf_bucket_bwtp_frame_get_phrase(
+    serf_bucket_t *bucket)
+{
+    if (SERF_BUCKET_IS_BWTP_FRAME(bucket)) {
+        frame_context_t *ctx = bucket->data;
+
+        return ctx->phrase;
+    }
+    else if (SERF_BUCKET_IS_BWTP_INCOMING_FRAME(bucket)) {
+        incoming_context_t *ctx = bucket->data;
+
+        return ctx->phrase;
+    }
+
+    return NULL;
+}
+
+serf_bucket_t *serf_bucket_bwtp_frame_get_headers(
+    serf_bucket_t *bucket)
+{
+    if (SERF_BUCKET_IS_BWTP_FRAME(bucket)) {
+        frame_context_t *ctx = bucket->data;
+
+        return ctx->headers;
+    }
+    else if (SERF_BUCKET_IS_BWTP_INCOMING_FRAME(bucket)) {
+        incoming_context_t *ctx = bucket->data;
+
+        return ctx->headers;
+    }
+
+    return NULL;
+}
+
+static int count_size(void *baton, const char *key, const char *value)
+{
+    apr_size_t *c = baton;
+    /* TODO Deal with folding.  Yikes. */
+
+    /* Add in ": " and CRLF - so an extra four bytes. */
+    *c += strlen(key) + strlen(value) + 4;
+
+    return 0;
+}
+
+static apr_size_t calc_header_size(serf_bucket_t *hdrs)
+{
+    apr_size_t size = 0;
+
+    serf_bucket_headers_do(hdrs, count_size, &size);
+
+    return size;
+}
+
+static void serialize_data(serf_bucket_t *bucket)
+{
+    frame_context_t *ctx = bucket->data;
+    serf_bucket_t *new_bucket;
+    apr_size_t req_len;
+
+    /* Serialize the request-line and headers into one mother string,
+     * and wrap a bucket around it.
+     */
+    req_len = apr_snprintf(ctx->req_line, sizeof(ctx->req_line),
+                           "%s %d " "%" APR_UINT64_T_HEX_FMT " %s%s\r\n",
+                           (ctx->type ? "BWM" : "BWH"),
+                           ctx->channel, calc_header_size(ctx->headers),
+                           (ctx->open ? "OPEN " : ""),
+                           ctx->phrase);
+    new_bucket = serf_bucket_simple_copy_create(ctx->req_line, req_len,
+                                                bucket->allocator);
+
+    /* Build up the new bucket structure.
+     *
+     * Note that self needs to become an aggregate bucket so that a
+     * pointer to self still represents the "right" data.
+     */
+    serf_bucket_aggregate_become(bucket);
+
+    /* Insert the two buckets. */
+    serf_bucket_aggregate_append(bucket, new_bucket);
+    serf_bucket_aggregate_append(bucket, ctx->headers);
+
+    /* Our private context is no longer needed, and is not referred to by
+     * any existing bucket. Toss it.
+     */
+    serf_bucket_mem_free(bucket->allocator, ctx);
+}
+
+static apr_status_t serf_bwtp_frame_read(serf_bucket_t *bucket,
+                                         apr_size_t requested,
+                                         const char **data, apr_size_t *len)
+{
+    /* Seralize our private data into a new aggregate bucket. */
+    serialize_data(bucket);
+
+    /* Delegate to the "new" aggregate bucket to do the read. */
+    return serf_bucket_read(bucket, requested, data, len);
+}
+
+static apr_status_t serf_bwtp_frame_readline(serf_bucket_t *bucket,
+                                             int acceptable, int *found,
+                                             const char **data, apr_size_t *len)
+{
+    /* Seralize our private data into a new aggregate bucket. */
+    serialize_data(bucket);
+
+    /* Delegate to the "new" aggregate bucket to do the readline. */
+    return serf_bucket_readline(bucket, acceptable, found, data, len);
+}
+
+static apr_status_t serf_bwtp_frame_read_iovec(serf_bucket_t *bucket,
+                                               apr_size_t requested,
+                                               int vecs_size,
+                                               struct iovec *vecs,
+                                               int *vecs_used)
+{
+    /* Seralize our private data into a new aggregate bucket. */
+    serialize_data(bucket);
+
+    /* Delegate to the "new" aggregate bucket to do the read. */
+    return serf_bucket_read_iovec(bucket, requested,
+                                  vecs_size, vecs, vecs_used);
+}
+
+static apr_status_t serf_bwtp_frame_peek(serf_bucket_t *bucket,
+                                         const char **data,
+                                         apr_size_t *len)
+{
+    /* Seralize our private data into a new aggregate bucket. */
+    serialize_data(bucket);
+
+    /* Delegate to the "new" aggregate bucket to do the peek. */
+    return serf_bucket_peek(bucket, data, len);
+}
+
+const serf_bucket_type_t serf_bucket_type_bwtp_frame = {
+    "BWTP-FRAME",
+    serf_bwtp_frame_read,
+    serf_bwtp_frame_readline,
+    serf_bwtp_frame_read_iovec,
+    serf_default_read_for_sendfile,
+    serf_default_read_bucket,
+    serf_bwtp_frame_peek,
+    serf_default_destroy_and_data,
+};
+
+
+serf_bucket_t *serf_bucket_bwtp_incoming_frame_create(
+    serf_bucket_t *stream,
+    serf_bucket_alloc_t *allocator)
+{
+    incoming_context_t *ctx;
+
+    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
+    ctx->stream = stream;
+    ctx->body = NULL;
+    ctx->headers = serf_bucket_headers_create(allocator);
+    ctx->state = STATE_STATUS_LINE;
+    ctx->length = 0;
+    ctx->channel = -1;
+    ctx->phrase = NULL;
+
+    serf_linebuf_init(&ctx->linebuf);
+
+    return serf_bucket_create(&serf_bucket_type_bwtp_incoming_frame, allocator, ctx);
+}
+
+static void bwtp_incoming_destroy_and_data(serf_bucket_t *bucket)
+{
+    incoming_context_t *ctx = bucket->data;
+
+    if (ctx->state != STATE_STATUS_LINE && ctx->phrase) {
+        serf_bucket_mem_free(bucket->allocator, (void*)ctx->phrase);
+    }
+
+    serf_bucket_destroy(ctx->stream);
+    if (ctx->body != NULL)
+        serf_bucket_destroy(ctx->body);
+    serf_bucket_destroy(ctx->headers);
+
+    serf_default_destroy_and_data(bucket);
+}
+
+static apr_status_t fetch_line(incoming_context_t *ctx, int acceptable)
+{
+    return serf_linebuf_fetch(&ctx->linebuf, ctx->stream, acceptable);
+}
+
+static apr_status_t parse_status_line(incoming_context_t *ctx,
+                                      serf_bucket_alloc_t *allocator)
+{
+    int res;
+    char *reason; /* ### stupid APR interface makes this non-const */
+
+    /* ctx->linebuf.line should be of form: BW* */
+    res = apr_date_checkmask(ctx->linebuf.line, "BW*");
+    if (!res) {
+        /* Not an BWTP response?  Well, at least we won't understand it. */
+        return APR_EGENERAL;
+    }
+
+    if (ctx->linebuf.line[2] == 'H') {
+        ctx->type = 0;
+    }
+    else if (ctx->linebuf.line[2] == 'M') {
+        ctx->type = 1;
+    }
+    else {
+        ctx->type = -1;
+    }
+
+    ctx->channel = apr_strtoi64(ctx->linebuf.line + 3, &reason, 16);
+
+    /* Skip leading spaces for the reason string. */
+    if (apr_isspace(*reason)) {
+        reason++;
+    }
+
+    ctx->length = apr_strtoi64(reason, &reason, 16);
+
+    /* Skip leading spaces for the reason string. */
+    if (reason - ctx->linebuf.line < ctx->linebuf.used) {
+        if (apr_isspace(*reason)) {
+            reason++;
+        }
+
+        ctx->phrase = serf_bstrmemdup(allocator, reason,
+                                      ctx->linebuf.used
+                                      - (reason - ctx->linebuf.line));
+    } else {
+        ctx->phrase = NULL;
+    }
+
+    return APR_SUCCESS;
+}
+
+/* This code should be replaced with header buckets. */
+static apr_status_t fetch_headers(serf_bucket_t *bkt, incoming_context_t *ctx)
+{
+    apr_status_t status;
+
+    /* RFC 2616 says that CRLF is the only line ending, but we can easily
+     * accept any kind of line ending.
+     */
+    status = fetch_line(ctx, SERF_NEWLINE_ANY);
+    if (SERF_BUCKET_READ_ERROR(status)) {
+        return status;
+    }
+    /* Something was read. Process it. */
+
+    if (ctx->linebuf.state == SERF_LINEBUF_READY && ctx->linebuf.used) {
+        const char *end_key;
+        const char *c;
+
+        end_key = c = memchr(ctx->linebuf.line, ':', ctx->linebuf.used);
+        if (!c) {
+            /* Bad headers? */
+            return APR_EGENERAL;
+        }
+
+        /* Skip over initial : and spaces. */
+        while (apr_isspace(*++c))
+            continue;
+
+        /* Always copy the headers (from the linebuf into new mem). */
+        /* ### we should be able to optimize some mem copies */
+        serf_bucket_headers_setx(
+            ctx->headers,
+            ctx->linebuf.line, end_key - ctx->linebuf.line, 1,
+            c, ctx->linebuf.line + ctx->linebuf.used - c, 1);
+    }
+
+    return status;
+}
+
+/* Perform one iteration of the state machine.
+ *
+ * Will return when one the following conditions occurred:
+ *  1) a state change
+ *  2) an error
+ *  3) the stream is not ready or at EOF
+ *  4) APR_SUCCESS, meaning the machine can be run again immediately
+ */
+static apr_status_t run_machine(serf_bucket_t *bkt, incoming_context_t *ctx)
+{
+    apr_status_t status = APR_SUCCESS; /* initialize to avoid gcc warnings */
+
+    switch (ctx->state) {
+    case STATE_STATUS_LINE:
+        /* RFC 2616 says that CRLF is the only line ending, but we can easily
+         * accept any kind of line ending.
+         */
+        status = fetch_line(ctx, SERF_NEWLINE_ANY);
+        if (SERF_BUCKET_READ_ERROR(status))
+            return status;
+
+        if (ctx->linebuf.state == SERF_LINEBUF_READY && ctx->linebuf.used) {
+            /* The Status-Line is in the line buffer. Process it. */
+            status = parse_status_line(ctx, bkt->allocator);
+            if (status)
+                return status;
+
+            if (ctx->length) {
+                ctx->body =
+                    serf_bucket_barrier_create(ctx->stream, bkt->allocator);
+                ctx->body = serf_bucket_limit_create(ctx->body, ctx->length,
+                                                     bkt->allocator);
+                if (!ctx->type) {
+                    ctx->state = STATE_HEADERS;
+                } else {
+                    ctx->state = STATE_BODY;
+                }
+            } else {
+                ctx->state = STATE_DONE;
+            }
+        }
+        else {
+            /* The connection closed before we could get the next
+             * response.  Treat the request as lost so that our upper
+             * end knows the server never tried to give us a response.
+             */
+            if (APR_STATUS_IS_EOF(status)) {
+                return SERF_ERROR_REQUEST_LOST;
+            }
+        }
+        break;
+    case STATE_HEADERS:
+        status = fetch_headers(ctx->body, ctx);
+        if (SERF_BUCKET_READ_ERROR(status))
+            return status;
+
+        /* If an empty line was read, then we hit the end of the headers.
+         * Move on to the body.
+         */
+        if (ctx->linebuf.state == SERF_LINEBUF_READY && !ctx->linebuf.used) {
+            /* Advance the state. */
+            ctx->state = STATE_DONE;
+        }
+        break;
+    case STATE_BODY:
+        /* Don't do anything. */
+        break;
+    case STATE_DONE:
+        return APR_EOF;
+    default:
+        /* Not reachable */
+        return APR_EGENERAL;
+    }
+
+    return status;
+}
+
+static apr_status_t wait_for_body(serf_bucket_t *bkt, incoming_context_t *ctx)
+{
+    apr_status_t status;
+
+    /* Keep reading and moving through states if we aren't at the BODY */
+    while (ctx->state != STATE_BODY) {
+        status = run_machine(bkt, ctx);
+
+        /* Anything other than APR_SUCCESS means that we cannot immediately
+         * read again (for now).
+         */
+        if (status)
+            return status;
+    }
+    /* in STATE_BODY */
+
+    return APR_SUCCESS;
+}
+
+apr_status_t serf_bucket_bwtp_incoming_frame_wait_for_headers(
+    serf_bucket_t *bucket)
+{
+    incoming_context_t *ctx = bucket->data;
+
+    return wait_for_body(bucket, ctx);
+}
+
+static apr_status_t bwtp_incoming_read(serf_bucket_t *bucket,
+                                       apr_size_t requested,
+                                       const char **data, apr_size_t *len)
+{
+    incoming_context_t *ctx = bucket->data;
+    apr_status_t rv;
+
+    rv = wait_for_body(bucket, ctx);
+    if (rv) {
+        /* It's not possible to have read anything yet! */
+        if (APR_STATUS_IS_EOF(rv) || APR_STATUS_IS_EAGAIN(rv)) {
+            *len = 0;
+        }
+        return rv;
+    }
+
+    rv = serf_bucket_read(ctx->body, requested, data, len);
+    if (APR_STATUS_IS_EOF(rv)) {
+        ctx->state = STATE_DONE;
+    }
+    return rv;
+}
+
+static apr_status_t bwtp_incoming_readline(serf_bucket_t *bucket,
+                                           int acceptable, int *found,
+                                           const char **data, apr_size_t *len)
+{
+    incoming_context_t *ctx = bucket->data;
+    apr_status_t rv;
+
+    rv = wait_for_body(bucket, ctx);
+    if (rv) {
+        return rv;
+    }
+
+    /* Delegate to the stream bucket to do the readline. */
+    return serf_bucket_readline(ctx->body, acceptable, found, data, len);
+}
+
+/* ### need to implement */
+#define bwtp_incoming_peek NULL
+
+const serf_bucket_type_t serf_bucket_type_bwtp_incoming_frame = {
+    "BWTP-INCOMING",
+    bwtp_incoming_read,
+    bwtp_incoming_readline,
+    serf_default_read_iovec,
+    serf_default_read_for_sendfile,
+    serf_default_read_bucket,
+    bwtp_incoming_peek,
+    bwtp_incoming_destroy_and_data,
+};

Deleted: vendor/serf/1.3.9/buckets/chunk_buckets.c
===================================================================
--- vendor/serf/dist/buckets/chunk_buckets.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/buckets/chunk_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,235 +0,0 @@
-/* Copyright 2002-2004 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_pools.h>
-#include <apr_strings.h>
-
-#include "serf.h"
-#include "serf_bucket_util.h"
-
-
-typedef struct {
-    enum {
-        STATE_FETCH,
-        STATE_CHUNK,
-        STATE_EOF
-    } state;
-
-    apr_status_t last_status;
-
-    serf_bucket_t *chunk;
-    serf_bucket_t *stream;
-
-    char chunk_hdr[20];
-} chunk_context_t;
-
-
-serf_bucket_t *serf_bucket_chunk_create(
-    serf_bucket_t *stream, serf_bucket_alloc_t *allocator)
-{
-    chunk_context_t *ctx;
-
-    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
-    ctx->state = STATE_FETCH;
-    ctx->chunk = serf_bucket_aggregate_create(allocator);
-    ctx->stream = stream;
-
-    return serf_bucket_create(&serf_bucket_type_chunk, allocator, ctx);
-}
-
-#define CRLF "\r\n"
-
-static apr_status_t create_chunk(serf_bucket_t *bucket)
-{
-    chunk_context_t *ctx = bucket->data;
-    serf_bucket_t *simple_bkt;
-    apr_size_t chunk_len;
-    apr_size_t stream_len;
-    struct iovec vecs[66]; /* 64 + chunk trailer + EOF trailer = 66 */
-    int vecs_read;
-    int i;
-
-    if (ctx->state != STATE_FETCH) {
-        return APR_SUCCESS;
-    }
-
-    ctx->last_status =
-        serf_bucket_read_iovec(ctx->stream, SERF_READ_ALL_AVAIL,
-                               64, vecs, &vecs_read);
-
-    if (SERF_BUCKET_READ_ERROR(ctx->last_status)) {
-        /* Uh-oh. */
-        return ctx->last_status;
-    }
-
-    /* Count the length of the data we read. */
-    stream_len = 0;
-    for (i = 0; i < vecs_read; i++) {
-        stream_len += vecs[i].iov_len;
-    }
-
-    /* assert: stream_len in hex < sizeof(ctx->chunk_hdr) */
-
-    /* Inserting a 0 byte chunk indicates a terminator, which already happens
-     * during the EOF handler below.  Adding another one here will cause the
-     * EOF chunk to be interpreted by the server as a new request.  So,
-     * we'll only do this if we have something to write.
-     */
-    if (stream_len) {
-        /* Build the chunk header. */
-        chunk_len = apr_snprintf(ctx->chunk_hdr, sizeof(ctx->chunk_hdr),
-                                 "%" APR_UINT64_T_HEX_FMT CRLF,
-                                 (apr_uint64_t)stream_len);
-
-        /* Create a copy of the chunk header so we can have multiple chunks
-         * in the pipeline at the same time.
-         */
-        simple_bkt = serf_bucket_simple_copy_create(ctx->chunk_hdr, chunk_len,
-                                                    bucket->allocator);
-        serf_bucket_aggregate_append(ctx->chunk, simple_bkt);
-
-        /* Insert the chunk footer. */
-        vecs[vecs_read].iov_base = CRLF;
-        vecs[vecs_read++].iov_len = sizeof(CRLF) - 1;
-    }
-
-    /* We've reached the end of the line for the stream. */
-    if (APR_STATUS_IS_EOF(ctx->last_status)) {
-        /* Insert the chunk footer. */
-        vecs[vecs_read].iov_base = "0" CRLF CRLF;
-        vecs[vecs_read++].iov_len = sizeof("0" CRLF CRLF) - 1;
-
-        ctx->state = STATE_EOF;
-    }
-    else {
-        /* Okay, we can return data.  */
-        ctx->state = STATE_CHUNK;
-    }
-
-    serf_bucket_aggregate_append_iovec(ctx->chunk, vecs, vecs_read);
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t serf_chunk_read(serf_bucket_t *bucket,
-                                    apr_size_t requested,
-                                    const char **data, apr_size_t *len)
-{
-    chunk_context_t *ctx = bucket->data;
-    apr_status_t status;
-
-    /* Before proceeding, we need to fetch some data from the stream. */
-    if (ctx->state == STATE_FETCH) {
-        status = create_chunk(bucket);
-        if (status) {
-            return status;
-        }
-    }
-
-    status = serf_bucket_read(ctx->chunk, requested, data, len);
-
-    /* Mask EOF from aggregate bucket. */
-    if (APR_STATUS_IS_EOF(status) && ctx->state == STATE_CHUNK) {
-        status = ctx->last_status;
-        ctx->state = STATE_FETCH;
-    }
-
-    return status;
-}
-
-static apr_status_t serf_chunk_readline(serf_bucket_t *bucket,
-                                         int acceptable, int *found,
-                                         const char **data, apr_size_t *len)
-{
-    chunk_context_t *ctx = bucket->data;
-    apr_status_t status;
-
-    status = serf_bucket_readline(ctx->chunk, acceptable, found, data, len);
-
-    /* Mask EOF from aggregate bucket. */
-    if (APR_STATUS_IS_EOF(status) && ctx->state == STATE_CHUNK) {
-        status = APR_EAGAIN;
-        ctx->state = STATE_FETCH;
-    }
-
-    return status;
-}
-
-static apr_status_t serf_chunk_read_iovec(serf_bucket_t *bucket,
-                                          apr_size_t requested,
-                                          int vecs_size,
-                                          struct iovec *vecs,
-                                          int *vecs_used)
-{
-    chunk_context_t *ctx = bucket->data;
-    apr_status_t status;
-
-    /* Before proceeding, we need to fetch some data from the stream. */
-    if (ctx->state == STATE_FETCH) {
-        status = create_chunk(bucket);
-        if (status) {
-            return status;
-        }
-    }
-
-    status = serf_bucket_read_iovec(ctx->chunk, requested, vecs_size, vecs,
-                                    vecs_used);
-
-    /* Mask EOF from aggregate bucket. */
-    if (APR_STATUS_IS_EOF(status) && ctx->state == STATE_CHUNK) {
-        status = ctx->last_status;
-        ctx->state = STATE_FETCH;
-    }
-
-    return status;
-}
-
-static apr_status_t serf_chunk_peek(serf_bucket_t *bucket,
-                                     const char **data,
-                                     apr_size_t *len)
-{
-    chunk_context_t *ctx = bucket->data;
-    apr_status_t status;
-
-    status = serf_bucket_peek(ctx->chunk, data, len);
-
-    /* Mask EOF from aggregate bucket. */
-    if (APR_STATUS_IS_EOF(status) && ctx->state == STATE_CHUNK) {
-        status = APR_EAGAIN;
-    }
-
-    return status;
-}
-
-static void serf_chunk_destroy(serf_bucket_t *bucket)
-{
-    chunk_context_t *ctx = bucket->data;
-
-    serf_bucket_destroy(ctx->stream);
-    serf_bucket_destroy(ctx->chunk);
-
-    serf_default_destroy_and_data(bucket);
-}
-
-const serf_bucket_type_t serf_bucket_type_chunk = {
-    "CHUNK",
-    serf_chunk_read,
-    serf_chunk_readline,
-    serf_chunk_read_iovec,
-    serf_default_read_for_sendfile,
-    serf_default_read_bucket,
-    serf_chunk_peek,
-    serf_chunk_destroy,
-};

Copied: vendor/serf/1.3.9/buckets/chunk_buckets.c (from rev 9259, vendor/serf/dist/buckets/chunk_buckets.c)
===================================================================
--- vendor/serf/1.3.9/buckets/chunk_buckets.c	                        (rev 0)
+++ vendor/serf/1.3.9/buckets/chunk_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,240 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_pools.h>
+#include <apr_strings.h>
+
+#include "serf.h"
+#include "serf_bucket_util.h"
+
+
+typedef struct {
+    enum {
+        STATE_FETCH,
+        STATE_CHUNK,
+        STATE_EOF
+    } state;
+
+    apr_status_t last_status;
+
+    serf_bucket_t *chunk;
+    serf_bucket_t *stream;
+
+    char chunk_hdr[20];
+} chunk_context_t;
+
+
+serf_bucket_t *serf_bucket_chunk_create(
+    serf_bucket_t *stream, serf_bucket_alloc_t *allocator)
+{
+    chunk_context_t *ctx;
+
+    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
+    ctx->state = STATE_FETCH;
+    ctx->chunk = serf_bucket_aggregate_create(allocator);
+    ctx->stream = stream;
+
+    return serf_bucket_create(&serf_bucket_type_chunk, allocator, ctx);
+}
+
+#define CRLF "\r\n"
+
+static apr_status_t create_chunk(serf_bucket_t *bucket)
+{
+    chunk_context_t *ctx = bucket->data;
+    serf_bucket_t *simple_bkt;
+    apr_size_t chunk_len;
+    apr_size_t stream_len;
+    struct iovec vecs[66]; /* 64 + chunk trailer + EOF trailer = 66 */
+    int vecs_read;
+    int i;
+
+    if (ctx->state != STATE_FETCH) {
+        return APR_SUCCESS;
+    }
+
+    ctx->last_status =
+        serf_bucket_read_iovec(ctx->stream, SERF_READ_ALL_AVAIL,
+                               64, vecs, &vecs_read);
+
+    if (SERF_BUCKET_READ_ERROR(ctx->last_status)) {
+        /* Uh-oh. */
+        return ctx->last_status;
+    }
+
+    /* Count the length of the data we read. */
+    stream_len = 0;
+    for (i = 0; i < vecs_read; i++) {
+        stream_len += vecs[i].iov_len;
+    }
+
+    /* assert: stream_len in hex < sizeof(ctx->chunk_hdr) */
+
+    /* Inserting a 0 byte chunk indicates a terminator, which already happens
+     * during the EOF handler below.  Adding another one here will cause the
+     * EOF chunk to be interpreted by the server as a new request.  So,
+     * we'll only do this if we have something to write.
+     */
+    if (stream_len) {
+        /* Build the chunk header. */
+        chunk_len = apr_snprintf(ctx->chunk_hdr, sizeof(ctx->chunk_hdr),
+                                 "%" APR_UINT64_T_HEX_FMT CRLF,
+                                 (apr_uint64_t)stream_len);
+
+        /* Create a copy of the chunk header so we can have multiple chunks
+         * in the pipeline at the same time.
+         */
+        simple_bkt = serf_bucket_simple_copy_create(ctx->chunk_hdr, chunk_len,
+                                                    bucket->allocator);
+        serf_bucket_aggregate_append(ctx->chunk, simple_bkt);
+
+        /* Insert the chunk footer. */
+        vecs[vecs_read].iov_base = CRLF;
+        vecs[vecs_read++].iov_len = sizeof(CRLF) - 1;
+    }
+
+    /* We've reached the end of the line for the stream. */
+    if (APR_STATUS_IS_EOF(ctx->last_status)) {
+        /* Insert the chunk footer. */
+        vecs[vecs_read].iov_base = "0" CRLF CRLF;
+        vecs[vecs_read++].iov_len = sizeof("0" CRLF CRLF) - 1;
+
+        ctx->state = STATE_EOF;
+    }
+    else {
+        /* Okay, we can return data.  */
+        ctx->state = STATE_CHUNK;
+    }
+
+    serf_bucket_aggregate_append_iovec(ctx->chunk, vecs, vecs_read);
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t serf_chunk_read(serf_bucket_t *bucket,
+                                    apr_size_t requested,
+                                    const char **data, apr_size_t *len)
+{
+    chunk_context_t *ctx = bucket->data;
+    apr_status_t status;
+
+    /* Before proceeding, we need to fetch some data from the stream. */
+    if (ctx->state == STATE_FETCH) {
+        status = create_chunk(bucket);
+        if (status) {
+            return status;
+        }
+    }
+
+    status = serf_bucket_read(ctx->chunk, requested, data, len);
+
+    /* Mask EOF from aggregate bucket. */
+    if (APR_STATUS_IS_EOF(status) && ctx->state == STATE_CHUNK) {
+        status = ctx->last_status;
+        ctx->state = STATE_FETCH;
+    }
+
+    return status;
+}
+
+static apr_status_t serf_chunk_readline(serf_bucket_t *bucket,
+                                         int acceptable, int *found,
+                                         const char **data, apr_size_t *len)
+{
+    chunk_context_t *ctx = bucket->data;
+    apr_status_t status;
+
+    status = serf_bucket_readline(ctx->chunk, acceptable, found, data, len);
+
+    /* Mask EOF from aggregate bucket. */
+    if (APR_STATUS_IS_EOF(status) && ctx->state == STATE_CHUNK) {
+        status = APR_EAGAIN;
+        ctx->state = STATE_FETCH;
+    }
+
+    return status;
+}
+
+static apr_status_t serf_chunk_read_iovec(serf_bucket_t *bucket,
+                                          apr_size_t requested,
+                                          int vecs_size,
+                                          struct iovec *vecs,
+                                          int *vecs_used)
+{
+    chunk_context_t *ctx = bucket->data;
+    apr_status_t status;
+
+    /* Before proceeding, we need to fetch some data from the stream. */
+    if (ctx->state == STATE_FETCH) {
+        status = create_chunk(bucket);
+        if (status) {
+            return status;
+        }
+    }
+
+    status = serf_bucket_read_iovec(ctx->chunk, requested, vecs_size, vecs,
+                                    vecs_used);
+
+    /* Mask EOF from aggregate bucket. */
+    if (APR_STATUS_IS_EOF(status) && ctx->state == STATE_CHUNK) {
+        status = ctx->last_status;
+        ctx->state = STATE_FETCH;
+    }
+
+    return status;
+}
+
+static apr_status_t serf_chunk_peek(serf_bucket_t *bucket,
+                                     const char **data,
+                                     apr_size_t *len)
+{
+    chunk_context_t *ctx = bucket->data;
+    apr_status_t status;
+
+    status = serf_bucket_peek(ctx->chunk, data, len);
+
+    /* Mask EOF from aggregate bucket. */
+    if (APR_STATUS_IS_EOF(status) && ctx->state == STATE_CHUNK) {
+        status = APR_EAGAIN;
+    }
+
+    return status;
+}
+
+static void serf_chunk_destroy(serf_bucket_t *bucket)
+{
+    chunk_context_t *ctx = bucket->data;
+
+    serf_bucket_destroy(ctx->stream);
+    serf_bucket_destroy(ctx->chunk);
+
+    serf_default_destroy_and_data(bucket);
+}
+
+const serf_bucket_type_t serf_bucket_type_chunk = {
+    "CHUNK",
+    serf_chunk_read,
+    serf_chunk_readline,
+    serf_chunk_read_iovec,
+    serf_default_read_for_sendfile,
+    serf_default_read_bucket,
+    serf_chunk_peek,
+    serf_chunk_destroy,
+};

Deleted: vendor/serf/1.3.9/buckets/dechunk_buckets.c
===================================================================
--- vendor/serf/dist/buckets/dechunk_buckets.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/buckets/dechunk_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,199 +0,0 @@
-/* Copyright 2002-2004 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_strings.h>
-
-#include "serf.h"
-#include "serf_bucket_util.h"
-
-typedef struct {
-    serf_bucket_t *stream;
-
-    enum {
-        STATE_SIZE,     /* reading the chunk size */
-        STATE_CHUNK,    /* reading the chunk */
-        STATE_TERM,     /* reading the chunk terminator */
-        STATE_DONE      /* body is done; we've returned EOF */
-    } state;
-
-    /* Buffer for accumulating a chunk size. */
-    serf_linebuf_t linebuf;
-
-    /* How much of the chunk, or the terminator, do we have left to read? */
-    apr_int64_t body_left;
-
-} dechunk_context_t;
-
-
-serf_bucket_t *serf_bucket_dechunk_create(
-    serf_bucket_t *stream,
-    serf_bucket_alloc_t *allocator)
-{
-    dechunk_context_t *ctx;
-
-    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
-    ctx->stream = stream;
-    ctx->state = STATE_SIZE;
-
-    serf_linebuf_init(&ctx->linebuf);
-
-    return serf_bucket_create(&serf_bucket_type_dechunk, allocator, ctx);
-}
-
-static void serf_dechunk_destroy_and_data(serf_bucket_t *bucket)
-{
-    dechunk_context_t *ctx = bucket->data;
-
-    serf_bucket_destroy(ctx->stream);
-
-    serf_default_destroy_and_data(bucket);
-}
-
-static apr_status_t serf_dechunk_read(serf_bucket_t *bucket,
-                                      apr_size_t requested,
-                                      const char **data, apr_size_t *len)
-{
-    dechunk_context_t *ctx = bucket->data;
-    apr_status_t status;
-
-    while (1) {
-        switch (ctx->state) {
-        case STATE_SIZE:
-
-            /* fetch a line terminated by CRLF */
-            status = serf_linebuf_fetch(&ctx->linebuf, ctx->stream,
-                                        SERF_NEWLINE_CRLF);
-            if (SERF_BUCKET_READ_ERROR(status))
-                return status;
-
-            /* if a line was read, then parse it. */
-            if (ctx->linebuf.state == SERF_LINEBUF_READY) {
-                /* NUL-terminate the line. if it filled the entire buffer,
-                   then just assume the thing is too large. */
-                if (ctx->linebuf.used == sizeof(ctx->linebuf.line))
-                    return APR_FROM_OS_ERROR(ERANGE);
-                ctx->linebuf.line[ctx->linebuf.used] = '\0';
-
-                /* convert from HEX digits. */
-                ctx->body_left = apr_strtoi64(ctx->linebuf.line, NULL, 16);
-                if (errno == ERANGE) {
-                    return APR_FROM_OS_ERROR(ERANGE);
-                }
-
-                if (ctx->body_left == 0) {
-                    /* Just read the last-chunk marker. We're DONE. */
-                    ctx->state = STATE_DONE;
-                    status = APR_EOF;
-                }
-                else {
-                    /* Got a size, so we'll start reading the chunk now. */
-                    ctx->state = STATE_CHUNK;
-                }
-
-                /* If we can read more, then go do so. */
-                if (!status)
-                    continue;
-            }
-            /* assert: status != 0 */
-
-            /* Note that we didn't actually read anything, so our callers
-             * don't get confused.
-             */
-            *len = 0;
-
-            return status;
-
-        case STATE_CHUNK:
-
-            if (requested > ctx->body_left) {
-                requested = ctx->body_left;
-            }
-
-            /* Delegate to the stream bucket to do the read. */
-            status = serf_bucket_read(ctx->stream, requested, data, len);
-            if (SERF_BUCKET_READ_ERROR(status))
-                return status;
-
-            /* Some data was read, so decrement the amount left and see
-             * if we're done reading this chunk.
-             */
-            ctx->body_left -= *len;
-            if (!ctx->body_left) {
-                ctx->state = STATE_TERM;
-                ctx->body_left = 2;     /* CRLF */
-            }
-
-            /* We need more data but there is no more available. */
-            if (ctx->body_left && APR_STATUS_IS_EOF(status)) {
-                return SERF_ERROR_TRUNCATED_HTTP_RESPONSE;
-            }
-
-            /* Return the data we just read. */
-            return status;
-
-        case STATE_TERM:
-            /* Delegate to the stream bucket to do the read. */
-            status = serf_bucket_read(ctx->stream, ctx->body_left, data, len);
-            if (SERF_BUCKET_READ_ERROR(status))
-                return status;
-
-            /* Some data was read, so decrement the amount left and see
-             * if we're done reading the chunk terminator.
-             */
-            ctx->body_left -= *len;
-
-            /* We need more data but there is no more available. */
-            if (ctx->body_left && APR_STATUS_IS_EOF(status))
-                return SERF_ERROR_TRUNCATED_HTTP_RESPONSE;
-
-            if (!ctx->body_left) {
-                ctx->state = STATE_SIZE;
-            }
-
-            /* Don't return the CR of CRLF to the caller! */
-            *len = 0;
-
-            if (status)
-                return status;
-
-            break;
-
-        case STATE_DONE:
-            /* Just keep returning EOF */
-            *len = 0;
-            return APR_EOF;
-
-        default:
-            /* Not reachable */
-            return APR_EGENERAL;
-        }
-    }
-    /* NOTREACHED */
-}
-
-/* ### need to implement */
-#define serf_dechunk_readline NULL
-#define serf_dechunk_peek NULL
-
-const serf_bucket_type_t serf_bucket_type_dechunk = {
-    "DECHUNK",
-    serf_dechunk_read,
-    serf_dechunk_readline,
-    serf_default_read_iovec,
-    serf_default_read_for_sendfile,
-    serf_default_read_bucket,
-    serf_dechunk_peek,
-    serf_dechunk_destroy_and_data,
-};

Copied: vendor/serf/1.3.9/buckets/dechunk_buckets.c (from rev 9259, vendor/serf/dist/buckets/dechunk_buckets.c)
===================================================================
--- vendor/serf/1.3.9/buckets/dechunk_buckets.c	                        (rev 0)
+++ vendor/serf/1.3.9/buckets/dechunk_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,204 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_strings.h>
+
+#include "serf.h"
+#include "serf_bucket_util.h"
+
+typedef struct {
+    serf_bucket_t *stream;
+
+    enum {
+        STATE_SIZE,     /* reading the chunk size */
+        STATE_CHUNK,    /* reading the chunk */
+        STATE_TERM,     /* reading the chunk terminator */
+        STATE_DONE      /* body is done; we've returned EOF */
+    } state;
+
+    /* Buffer for accumulating a chunk size. */
+    serf_linebuf_t linebuf;
+
+    /* How much of the chunk, or the terminator, do we have left to read? */
+    apr_int64_t body_left;
+
+} dechunk_context_t;
+
+
+serf_bucket_t *serf_bucket_dechunk_create(
+    serf_bucket_t *stream,
+    serf_bucket_alloc_t *allocator)
+{
+    dechunk_context_t *ctx;
+
+    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
+    ctx->stream = stream;
+    ctx->state = STATE_SIZE;
+
+    serf_linebuf_init(&ctx->linebuf);
+
+    return serf_bucket_create(&serf_bucket_type_dechunk, allocator, ctx);
+}
+
+static void serf_dechunk_destroy_and_data(serf_bucket_t *bucket)
+{
+    dechunk_context_t *ctx = bucket->data;
+
+    serf_bucket_destroy(ctx->stream);
+
+    serf_default_destroy_and_data(bucket);
+}
+
+static apr_status_t serf_dechunk_read(serf_bucket_t *bucket,
+                                      apr_size_t requested,
+                                      const char **data, apr_size_t *len)
+{
+    dechunk_context_t *ctx = bucket->data;
+    apr_status_t status;
+
+    while (1) {
+        switch (ctx->state) {
+        case STATE_SIZE:
+
+            /* fetch a line terminated by CRLF */
+            status = serf_linebuf_fetch(&ctx->linebuf, ctx->stream,
+                                        SERF_NEWLINE_CRLF);
+            if (SERF_BUCKET_READ_ERROR(status))
+                return status;
+
+            /* if a line was read, then parse it. */
+            if (ctx->linebuf.state == SERF_LINEBUF_READY) {
+                /* NUL-terminate the line. if it filled the entire buffer,
+                   then just assume the thing is too large. */
+                if (ctx->linebuf.used == sizeof(ctx->linebuf.line))
+                    return APR_FROM_OS_ERROR(ERANGE);
+                ctx->linebuf.line[ctx->linebuf.used] = '\0';
+
+                /* convert from HEX digits. */
+                ctx->body_left = apr_strtoi64(ctx->linebuf.line, NULL, 16);
+                if (errno == ERANGE) {
+                    return APR_FROM_OS_ERROR(ERANGE);
+                }
+
+                if (ctx->body_left == 0) {
+                    /* Just read the last-chunk marker. We're DONE. */
+                    ctx->state = STATE_DONE;
+                    status = APR_EOF;
+                }
+                else {
+                    /* Got a size, so we'll start reading the chunk now. */
+                    ctx->state = STATE_CHUNK;
+                }
+
+                /* If we can read more, then go do so. */
+                if (!status)
+                    continue;
+            }
+            /* assert: status != 0 */
+
+            /* Note that we didn't actually read anything, so our callers
+             * don't get confused.
+             */
+            *len = 0;
+
+            return status;
+
+        case STATE_CHUNK:
+
+            if (requested > ctx->body_left) {
+                requested = ctx->body_left;
+            }
+
+            /* Delegate to the stream bucket to do the read. */
+            status = serf_bucket_read(ctx->stream, requested, data, len);
+            if (SERF_BUCKET_READ_ERROR(status))
+                return status;
+
+            /* Some data was read, so decrement the amount left and see
+             * if we're done reading this chunk.
+             */
+            ctx->body_left -= *len;
+            if (!ctx->body_left) {
+                ctx->state = STATE_TERM;
+                ctx->body_left = 2;     /* CRLF */
+            }
+
+            /* We need more data but there is no more available. */
+            if (ctx->body_left && APR_STATUS_IS_EOF(status)) {
+                return SERF_ERROR_TRUNCATED_HTTP_RESPONSE;
+            }
+
+            /* Return the data we just read. */
+            return status;
+
+        case STATE_TERM:
+            /* Delegate to the stream bucket to do the read. */
+            status = serf_bucket_read(ctx->stream, ctx->body_left, data, len);
+            if (SERF_BUCKET_READ_ERROR(status))
+                return status;
+
+            /* Some data was read, so decrement the amount left and see
+             * if we're done reading the chunk terminator.
+             */
+            ctx->body_left -= *len;
+
+            /* We need more data but there is no more available. */
+            if (ctx->body_left && APR_STATUS_IS_EOF(status))
+                return SERF_ERROR_TRUNCATED_HTTP_RESPONSE;
+
+            if (!ctx->body_left) {
+                ctx->state = STATE_SIZE;
+            }
+
+            /* Don't return the CR of CRLF to the caller! */
+            *len = 0;
+
+            if (status)
+                return status;
+
+            break;
+
+        case STATE_DONE:
+            /* Just keep returning EOF */
+            *len = 0;
+            return APR_EOF;
+
+        default:
+            /* Not reachable */
+            return APR_EGENERAL;
+        }
+    }
+    /* NOTREACHED */
+}
+
+/* ### need to implement */
+#define serf_dechunk_readline NULL
+#define serf_dechunk_peek NULL
+
+const serf_bucket_type_t serf_bucket_type_dechunk = {
+    "DECHUNK",
+    serf_dechunk_read,
+    serf_dechunk_readline,
+    serf_default_read_iovec,
+    serf_default_read_for_sendfile,
+    serf_default_read_bucket,
+    serf_dechunk_peek,
+    serf_dechunk_destroy_and_data,
+};

Deleted: vendor/serf/1.3.9/buckets/deflate_buckets.c
===================================================================
--- vendor/serf/dist/buckets/deflate_buckets.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/buckets/deflate_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,403 +0,0 @@
-/* Copyright 2002-2004 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_strings.h>
-
-#include <zlib.h>
-
-/* This conditional isn't defined anywhere yet. */
-#ifdef HAVE_ZUTIL_H
-#include <zutil.h>
-#endif
-
-#include "serf.h"
-#include "serf_bucket_util.h"
-
-/* magic header */
-static char deflate_magic[2] = { '\037', '\213' };
-#define DEFLATE_MAGIC_SIZE 10
-#define DEFLATE_VERIFY_SIZE 8
-#define DEFLATE_BUFFER_SIZE 8096
-
-static const int DEFLATE_WINDOW_SIZE = -15;
-static const int DEFLATE_MEMLEVEL = 9;
-
-typedef struct {
-    serf_bucket_t *stream;
-    serf_bucket_t *inflate_stream;
-
-    int format;                 /* Are we 'deflate' or 'gzip'? */
-
-    enum {
-        STATE_READING_HEADER,   /* reading the gzip header */
-        STATE_HEADER,           /* read the gzip header */
-        STATE_INIT,             /* init'ing zlib functions */
-        STATE_INFLATE,          /* inflating the content now */
-        STATE_READING_VERIFY,   /* reading the final gzip CRC */
-        STATE_VERIFY,           /* verifying the final gzip CRC */
-        STATE_FINISH,           /* clean up after reading body */
-        STATE_DONE,             /* body is done; we'll return EOF here */
-    } state;
-
-    z_stream zstream;
-    char hdr_buffer[DEFLATE_MAGIC_SIZE];
-    unsigned char buffer[DEFLATE_BUFFER_SIZE];
-    unsigned long crc;
-    int windowSize;
-    int memLevel;
-    int bufferSize;
-
-    /* How much of the chunk, or the terminator, do we have left to read? */
-    apr_size_t stream_left;
-
-    /* How much are we supposed to read? */
-    apr_size_t stream_size;
-
-    int stream_status; /* What was the last status we read? */
-
-} deflate_context_t;
-
-/* Inputs a string and returns a long.  */
-static unsigned long getLong(unsigned char *string)
-{
-    return ((unsigned long)string[0])
-          | (((unsigned long)string[1]) << 8)
-          | (((unsigned long)string[2]) << 16)
-          | (((unsigned long)string[3]) << 24);
-}
-
-serf_bucket_t *serf_bucket_deflate_create(
-    serf_bucket_t *stream,
-    serf_bucket_alloc_t *allocator,
-    int format)
-{
-    deflate_context_t *ctx;
-
-    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
-    ctx->stream = stream;
-    ctx->stream_status = APR_SUCCESS;
-    ctx->inflate_stream = serf_bucket_aggregate_create(allocator);
-    ctx->format = format;
-    ctx->crc = 0;
-    /* zstream must be NULL'd out. */
-    memset(&ctx->zstream, 0, sizeof(ctx->zstream));
-
-    switch (ctx->format) {
-        case SERF_DEFLATE_GZIP:
-            ctx->state = STATE_READING_HEADER;
-            break;
-        case SERF_DEFLATE_DEFLATE:
-            /* deflate doesn't have a header. */
-            ctx->state = STATE_INIT;
-            break;
-        default:
-            /* Not reachable */
-            return NULL;
-    }
-
-    /* Initial size of gzip header. */
-    ctx->stream_left = ctx->stream_size = DEFLATE_MAGIC_SIZE;
-
-    ctx->windowSize = DEFLATE_WINDOW_SIZE;
-    ctx->memLevel = DEFLATE_MEMLEVEL;
-    ctx->bufferSize = DEFLATE_BUFFER_SIZE;
-
-    return serf_bucket_create(&serf_bucket_type_deflate, allocator, ctx);
-}
-
-static void serf_deflate_destroy_and_data(serf_bucket_t *bucket)
-{
-    deflate_context_t *ctx = bucket->data;
-
-    if (ctx->state > STATE_INIT &&
-        ctx->state <= STATE_FINISH)
-        inflateEnd(&ctx->zstream);
-
-    /* We may have appended inflate_stream into the stream bucket.
-     * If so, avoid free'ing it twice.
-     */
-    if (ctx->inflate_stream) {
-        serf_bucket_destroy(ctx->inflate_stream);
-    }
-    serf_bucket_destroy(ctx->stream);
-
-    serf_default_destroy_and_data(bucket);
-}
-
-static apr_status_t serf_deflate_read(serf_bucket_t *bucket,
-                                      apr_size_t requested,
-                                      const char **data, apr_size_t *len)
-{
-    deflate_context_t *ctx = bucket->data;
-    apr_status_t status;
-    const char *private_data;
-    apr_size_t private_len;
-    int zRC;
-
-    while (1) {
-        switch (ctx->state) {
-        case STATE_READING_HEADER:
-        case STATE_READING_VERIFY:
-            status = serf_bucket_read(ctx->stream, ctx->stream_left,
-                                      &private_data, &private_len);
-
-            if (SERF_BUCKET_READ_ERROR(status)) {
-                return status;
-            }
-
-            memcpy(ctx->hdr_buffer + (ctx->stream_size - ctx->stream_left),
-                   private_data, private_len);
-
-            ctx->stream_left -= private_len;
-
-            if (ctx->stream_left == 0) {
-                ctx->state++;
-                if (APR_STATUS_IS_EAGAIN(status)) {
-                    *len = 0;
-                    return status;
-                }
-            }
-            else if (status) {
-                *len = 0;
-                return status;
-            }
-            break;
-        case STATE_HEADER:
-            if (ctx->hdr_buffer[0] != deflate_magic[0] ||
-                ctx->hdr_buffer[1] != deflate_magic[1]) {
-                return SERF_ERROR_DECOMPRESSION_FAILED;
-            }
-            if (ctx->hdr_buffer[3] != 0) {
-                return SERF_ERROR_DECOMPRESSION_FAILED;
-            }
-            ctx->state++;
-            break;
-        case STATE_VERIFY:
-        {
-            unsigned long compCRC, compLen, actualLen;
-
-            /* Do the checksum computation. */
-            compCRC = getLong((unsigned char*)ctx->hdr_buffer);
-            if (ctx->crc != compCRC) {
-                return SERF_ERROR_DECOMPRESSION_FAILED;
-            }
-            compLen = getLong((unsigned char*)ctx->hdr_buffer + 4);
-            /* The length in the trailer is module 2^32, so do the same for
-               the actual length. */
-            actualLen = ctx->zstream.total_out;
-            actualLen &= 0xFFFFFFFF;
-            if (actualLen != compLen) {
-                return SERF_ERROR_DECOMPRESSION_FAILED;
-            }
-            ctx->state++;
-            break;
-        }
-        case STATE_INIT:
-            zRC = inflateInit2(&ctx->zstream, ctx->windowSize);
-            if (zRC != Z_OK) {
-                return SERF_ERROR_DECOMPRESSION_FAILED;
-            }
-            ctx->zstream.next_out = ctx->buffer;
-            ctx->zstream.avail_out = ctx->bufferSize;
-            ctx->state++;
-            break;
-        case STATE_FINISH:
-            inflateEnd(&ctx->zstream);
-            serf_bucket_aggregate_prepend(ctx->stream, ctx->inflate_stream);
-            ctx->inflate_stream = 0;
-            ctx->state++;
-            break;
-        case STATE_INFLATE:
-            /* Do we have anything already uncompressed to read? */
-            status = serf_bucket_read(ctx->inflate_stream, requested, data,
-                                      len);
-            if (SERF_BUCKET_READ_ERROR(status)) {
-                return status;
-            }
-            /* Hide EOF. */
-            if (APR_STATUS_IS_EOF(status)) {
-                status = ctx->stream_status;
-                if (APR_STATUS_IS_EOF(status)) {
-                    /* We've read all of the data from our stream, but we
-                     * need to continue to iterate until we flush
-                     * out the zlib buffer.
-                     */
-                    status = APR_SUCCESS;
-                }
-            }
-            if (*len != 0) {
-                return status;
-            }
-
-            /* We tried; but we have nothing buffered. Fetch more. */
-
-            /* It is possible that we maxed out avail_out before
-             * exhausting avail_in; therefore, continue using the
-             * previous buffer.  Otherwise, fetch more data from
-             * our stream bucket.
-             */
-            if (ctx->zstream.avail_in == 0) {
-                /* When we empty our inflated stream, we'll return this
-                 * status - this allow us to eventually pass up EAGAINs.
-                 */
-                ctx->stream_status = serf_bucket_read(ctx->stream,
-                                                      ctx->bufferSize,
-                                                      &private_data,
-                                                      &private_len);
-
-                if (SERF_BUCKET_READ_ERROR(ctx->stream_status)) {
-                    return ctx->stream_status;
-                }
-
-                if (!private_len && APR_STATUS_IS_EAGAIN(ctx->stream_status)) {
-                    *len = 0;
-                    status = ctx->stream_status;
-                    ctx->stream_status = APR_SUCCESS;
-                    return status;
-                }
-
-                ctx->zstream.next_in = (unsigned char*)private_data;
-                ctx->zstream.avail_in = private_len;
-            }
-
-            while (1) {
-
-                zRC = inflate(&ctx->zstream, Z_NO_FLUSH);
-
-                /* We're full or zlib requires more space. Either case, clear
-                   out our buffer, reset, and return. */
-                if (zRC == Z_BUF_ERROR || ctx->zstream.avail_out == 0) {
-                    serf_bucket_t *tmp;
-                    ctx->zstream.next_out = ctx->buffer;
-                    private_len = ctx->bufferSize - ctx->zstream.avail_out;
-
-                    ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer,
-                                     private_len);
-
-                    /* FIXME: There probably needs to be a free func. */
-                    tmp = SERF_BUCKET_SIMPLE_STRING_LEN((char *)ctx->buffer,
-                                                        private_len,
-                                                        bucket->allocator);
-                    serf_bucket_aggregate_append(ctx->inflate_stream, tmp);
-                    ctx->zstream.avail_out = ctx->bufferSize;
-                    break;
-                }
-
-                if (zRC == Z_STREAM_END) {
-                    serf_bucket_t *tmp;
-
-                    private_len = ctx->bufferSize - ctx->zstream.avail_out;
-                    ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer,
-                                     private_len);
-                    /* FIXME: There probably needs to be a free func. */
-                    tmp = SERF_BUCKET_SIMPLE_STRING_LEN((char *)ctx->buffer,
-                                                        private_len,
-                                                        bucket->allocator);
-                    serf_bucket_aggregate_append(ctx->inflate_stream, tmp);
-
-                    ctx->zstream.avail_out = ctx->bufferSize;
-
-                    /* Push back the remaining data to be read. */
-                    tmp = serf_bucket_aggregate_create(bucket->allocator);
-                    serf_bucket_aggregate_prepend(tmp, ctx->stream);
-                    ctx->stream = tmp;
-
-                    /* We now need to take the remaining avail_in and
-                     * throw it in ctx->stream so our next read picks it up.
-                     */
-                    tmp = SERF_BUCKET_SIMPLE_STRING_LEN(
-                                        (const char*)ctx->zstream.next_in,
-                                                     ctx->zstream.avail_in,
-                                                     bucket->allocator);
-                    serf_bucket_aggregate_prepend(ctx->stream, tmp);
-
-                    switch (ctx->format) {
-                    case SERF_DEFLATE_GZIP:
-                        ctx->stream_left = ctx->stream_size =
-                            DEFLATE_VERIFY_SIZE;
-                        ctx->state++;
-                        break;
-                    case SERF_DEFLATE_DEFLATE:
-                        /* Deflate does not have a verify footer. */
-                        ctx->state = STATE_FINISH;
-                        break;
-                    default:
-                        /* Not reachable */
-                        return APR_EGENERAL;
-                    }
-
-                    break;
-                }
-
-                /* Any other error? */
-                if (zRC != Z_OK) {
-                    return SERF_ERROR_DECOMPRESSION_FAILED;
-                }
-
-                /* As long as zRC == Z_OK, just keep looping. */
-            }
-            /* Okay, we've inflated.  Try to read. */
-            status = serf_bucket_read(ctx->inflate_stream, requested, data,
-                                      len);
-            /* Hide EOF. */
-            if (APR_STATUS_IS_EOF(status)) {
-                status = ctx->stream_status;
-
-                /* If the inflation wasn't finished, return APR_SUCCESS. */
-                if (zRC != Z_STREAM_END)
-                    return APR_SUCCESS;
-
-                /* If our stream is finished too and all data was inflated,
-                 * return SUCCESS so we'll iterate one more time.
-                 */
-                if (APR_STATUS_IS_EOF(status)) {
-                    /* No more data to read from the stream, and everything
-                       inflated. If all data was received correctly, state
-                       should have been advanced to STATE_READING_VERIFY or
-                       STATE_FINISH. If not, then the data was incomplete
-                       and we have an error. */
-                    if (ctx->state != STATE_INFLATE)
-                        return APR_SUCCESS;
-                    else
-                        return SERF_ERROR_DECOMPRESSION_FAILED;
-                }
-            }
-            return status;
-        case STATE_DONE:
-            /* We're done inflating.  Use our finished buffer. */
-            return serf_bucket_read(ctx->stream, requested, data, len);
-        default:
-            /* Not reachable */
-            return APR_EGENERAL;
-        }
-    }
-
-    /* NOTREACHED */
-}
-
-/* ### need to implement */
-#define serf_deflate_readline NULL
-#define serf_deflate_peek NULL
-
-const serf_bucket_type_t serf_bucket_type_deflate = {
-    "DEFLATE",
-    serf_deflate_read,
-    serf_deflate_readline,
-    serf_default_read_iovec,
-    serf_default_read_for_sendfile,
-    serf_default_read_bucket,
-    serf_deflate_peek,
-    serf_deflate_destroy_and_data,
-};

Copied: vendor/serf/1.3.9/buckets/deflate_buckets.c (from rev 9259, vendor/serf/dist/buckets/deflate_buckets.c)
===================================================================
--- vendor/serf/1.3.9/buckets/deflate_buckets.c	                        (rev 0)
+++ vendor/serf/1.3.9/buckets/deflate_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,408 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_strings.h>
+
+#include <zlib.h>
+
+/* This conditional isn't defined anywhere yet. */
+#ifdef HAVE_ZUTIL_H
+#include <zutil.h>
+#endif
+
+#include "serf.h"
+#include "serf_bucket_util.h"
+
+/* magic header */
+static char deflate_magic[2] = { '\037', '\213' };
+#define DEFLATE_MAGIC_SIZE 10
+#define DEFLATE_VERIFY_SIZE 8
+#define DEFLATE_BUFFER_SIZE 8096
+
+static const int DEFLATE_WINDOW_SIZE = -15;
+static const int DEFLATE_MEMLEVEL = 9;
+
+typedef struct {
+    serf_bucket_t *stream;
+    serf_bucket_t *inflate_stream;
+
+    int format;                 /* Are we 'deflate' or 'gzip'? */
+
+    enum {
+        STATE_READING_HEADER,   /* reading the gzip header */
+        STATE_HEADER,           /* read the gzip header */
+        STATE_INIT,             /* init'ing zlib functions */
+        STATE_INFLATE,          /* inflating the content now */
+        STATE_READING_VERIFY,   /* reading the final gzip CRC */
+        STATE_VERIFY,           /* verifying the final gzip CRC */
+        STATE_FINISH,           /* clean up after reading body */
+        STATE_DONE,             /* body is done; we'll return EOF here */
+    } state;
+
+    z_stream zstream;
+    char hdr_buffer[DEFLATE_MAGIC_SIZE];
+    unsigned char buffer[DEFLATE_BUFFER_SIZE];
+    unsigned long crc;
+    int windowSize;
+    int memLevel;
+    int bufferSize;
+
+    /* How much of the chunk, or the terminator, do we have left to read? */
+    apr_size_t stream_left;
+
+    /* How much are we supposed to read? */
+    apr_size_t stream_size;
+
+    int stream_status; /* What was the last status we read? */
+
+} deflate_context_t;
+
+/* Inputs a string and returns a long.  */
+static unsigned long getLong(unsigned char *string)
+{
+    return ((unsigned long)string[0])
+          | (((unsigned long)string[1]) << 8)
+          | (((unsigned long)string[2]) << 16)
+          | (((unsigned long)string[3]) << 24);
+}
+
+serf_bucket_t *serf_bucket_deflate_create(
+    serf_bucket_t *stream,
+    serf_bucket_alloc_t *allocator,
+    int format)
+{
+    deflate_context_t *ctx;
+
+    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
+    ctx->stream = stream;
+    ctx->stream_status = APR_SUCCESS;
+    ctx->inflate_stream = serf_bucket_aggregate_create(allocator);
+    ctx->format = format;
+    ctx->crc = 0;
+    /* zstream must be NULL'd out. */
+    memset(&ctx->zstream, 0, sizeof(ctx->zstream));
+
+    switch (ctx->format) {
+        case SERF_DEFLATE_GZIP:
+            ctx->state = STATE_READING_HEADER;
+            break;
+        case SERF_DEFLATE_DEFLATE:
+            /* deflate doesn't have a header. */
+            ctx->state = STATE_INIT;
+            break;
+        default:
+            /* Not reachable */
+            return NULL;
+    }
+
+    /* Initial size of gzip header. */
+    ctx->stream_left = ctx->stream_size = DEFLATE_MAGIC_SIZE;
+
+    ctx->windowSize = DEFLATE_WINDOW_SIZE;
+    ctx->memLevel = DEFLATE_MEMLEVEL;
+    ctx->bufferSize = DEFLATE_BUFFER_SIZE;
+
+    return serf_bucket_create(&serf_bucket_type_deflate, allocator, ctx);
+}
+
+static void serf_deflate_destroy_and_data(serf_bucket_t *bucket)
+{
+    deflate_context_t *ctx = bucket->data;
+
+    if (ctx->state > STATE_INIT &&
+        ctx->state <= STATE_FINISH)
+        inflateEnd(&ctx->zstream);
+
+    /* We may have appended inflate_stream into the stream bucket.
+     * If so, avoid free'ing it twice.
+     */
+    if (ctx->inflate_stream) {
+        serf_bucket_destroy(ctx->inflate_stream);
+    }
+    serf_bucket_destroy(ctx->stream);
+
+    serf_default_destroy_and_data(bucket);
+}
+
+static apr_status_t serf_deflate_read(serf_bucket_t *bucket,
+                                      apr_size_t requested,
+                                      const char **data, apr_size_t *len)
+{
+    deflate_context_t *ctx = bucket->data;
+    apr_status_t status;
+    const char *private_data;
+    apr_size_t private_len;
+    int zRC;
+
+    while (1) {
+        switch (ctx->state) {
+        case STATE_READING_HEADER:
+        case STATE_READING_VERIFY:
+            status = serf_bucket_read(ctx->stream, ctx->stream_left,
+                                      &private_data, &private_len);
+
+            if (SERF_BUCKET_READ_ERROR(status)) {
+                return status;
+            }
+
+            memcpy(ctx->hdr_buffer + (ctx->stream_size - ctx->stream_left),
+                   private_data, private_len);
+
+            ctx->stream_left -= private_len;
+
+            if (ctx->stream_left == 0) {
+                ctx->state++;
+                if (APR_STATUS_IS_EAGAIN(status)) {
+                    *len = 0;
+                    return status;
+                }
+            }
+            else if (status) {
+                *len = 0;
+                return status;
+            }
+            break;
+        case STATE_HEADER:
+            if (ctx->hdr_buffer[0] != deflate_magic[0] ||
+                ctx->hdr_buffer[1] != deflate_magic[1]) {
+                return SERF_ERROR_DECOMPRESSION_FAILED;
+            }
+            if (ctx->hdr_buffer[3] != 0) {
+                return SERF_ERROR_DECOMPRESSION_FAILED;
+            }
+            ctx->state++;
+            break;
+        case STATE_VERIFY:
+        {
+            unsigned long compCRC, compLen, actualLen;
+
+            /* Do the checksum computation. */
+            compCRC = getLong((unsigned char*)ctx->hdr_buffer);
+            if (ctx->crc != compCRC) {
+                return SERF_ERROR_DECOMPRESSION_FAILED;
+            }
+            compLen = getLong((unsigned char*)ctx->hdr_buffer + 4);
+            /* The length in the trailer is module 2^32, so do the same for
+               the actual length. */
+            actualLen = ctx->zstream.total_out;
+            actualLen &= 0xFFFFFFFF;
+            if (actualLen != compLen) {
+                return SERF_ERROR_DECOMPRESSION_FAILED;
+            }
+            ctx->state++;
+            break;
+        }
+        case STATE_INIT:
+            zRC = inflateInit2(&ctx->zstream, ctx->windowSize);
+            if (zRC != Z_OK) {
+                return SERF_ERROR_DECOMPRESSION_FAILED;
+            }
+            ctx->zstream.next_out = ctx->buffer;
+            ctx->zstream.avail_out = ctx->bufferSize;
+            ctx->state++;
+            break;
+        case STATE_FINISH:
+            inflateEnd(&ctx->zstream);
+            serf_bucket_aggregate_prepend(ctx->stream, ctx->inflate_stream);
+            ctx->inflate_stream = 0;
+            ctx->state++;
+            break;
+        case STATE_INFLATE:
+            /* Do we have anything already uncompressed to read? */
+            status = serf_bucket_read(ctx->inflate_stream, requested, data,
+                                      len);
+            if (SERF_BUCKET_READ_ERROR(status)) {
+                return status;
+            }
+            /* Hide EOF. */
+            if (APR_STATUS_IS_EOF(status)) {
+                status = ctx->stream_status;
+                if (APR_STATUS_IS_EOF(status)) {
+                    /* We've read all of the data from our stream, but we
+                     * need to continue to iterate until we flush
+                     * out the zlib buffer.
+                     */
+                    status = APR_SUCCESS;
+                }
+            }
+            if (*len != 0) {
+                return status;
+            }
+
+            /* We tried; but we have nothing buffered. Fetch more. */
+
+            /* It is possible that we maxed out avail_out before
+             * exhausting avail_in; therefore, continue using the
+             * previous buffer.  Otherwise, fetch more data from
+             * our stream bucket.
+             */
+            if (ctx->zstream.avail_in == 0) {
+                /* When we empty our inflated stream, we'll return this
+                 * status - this allow us to eventually pass up EAGAINs.
+                 */
+                ctx->stream_status = serf_bucket_read(ctx->stream,
+                                                      ctx->bufferSize,
+                                                      &private_data,
+                                                      &private_len);
+
+                if (SERF_BUCKET_READ_ERROR(ctx->stream_status)) {
+                    return ctx->stream_status;
+                }
+
+                if (!private_len && APR_STATUS_IS_EAGAIN(ctx->stream_status)) {
+                    *len = 0;
+                    status = ctx->stream_status;
+                    ctx->stream_status = APR_SUCCESS;
+                    return status;
+                }
+
+                ctx->zstream.next_in = (unsigned char*)private_data;
+                ctx->zstream.avail_in = private_len;
+            }
+
+            while (1) {
+
+                zRC = inflate(&ctx->zstream, Z_NO_FLUSH);
+
+                /* We're full or zlib requires more space. Either case, clear
+                   out our buffer, reset, and return. */
+                if (zRC == Z_BUF_ERROR || ctx->zstream.avail_out == 0) {
+                    serf_bucket_t *tmp;
+                    ctx->zstream.next_out = ctx->buffer;
+                    private_len = ctx->bufferSize - ctx->zstream.avail_out;
+
+                    ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer,
+                                     private_len);
+
+                    /* FIXME: There probably needs to be a free func. */
+                    tmp = SERF_BUCKET_SIMPLE_STRING_LEN((char *)ctx->buffer,
+                                                        private_len,
+                                                        bucket->allocator);
+                    serf_bucket_aggregate_append(ctx->inflate_stream, tmp);
+                    ctx->zstream.avail_out = ctx->bufferSize;
+                    break;
+                }
+
+                if (zRC == Z_STREAM_END) {
+                    serf_bucket_t *tmp;
+
+                    private_len = ctx->bufferSize - ctx->zstream.avail_out;
+                    ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer,
+                                     private_len);
+                    /* FIXME: There probably needs to be a free func. */
+                    tmp = SERF_BUCKET_SIMPLE_STRING_LEN((char *)ctx->buffer,
+                                                        private_len,
+                                                        bucket->allocator);
+                    serf_bucket_aggregate_append(ctx->inflate_stream, tmp);
+
+                    ctx->zstream.avail_out = ctx->bufferSize;
+
+                    /* Push back the remaining data to be read. */
+                    tmp = serf_bucket_aggregate_create(bucket->allocator);
+                    serf_bucket_aggregate_prepend(tmp, ctx->stream);
+                    ctx->stream = tmp;
+
+                    /* We now need to take the remaining avail_in and
+                     * throw it in ctx->stream so our next read picks it up.
+                     */
+                    tmp = SERF_BUCKET_SIMPLE_STRING_LEN(
+                                        (const char*)ctx->zstream.next_in,
+                                                     ctx->zstream.avail_in,
+                                                     bucket->allocator);
+                    serf_bucket_aggregate_prepend(ctx->stream, tmp);
+
+                    switch (ctx->format) {
+                    case SERF_DEFLATE_GZIP:
+                        ctx->stream_left = ctx->stream_size =
+                            DEFLATE_VERIFY_SIZE;
+                        ctx->state++;
+                        break;
+                    case SERF_DEFLATE_DEFLATE:
+                        /* Deflate does not have a verify footer. */
+                        ctx->state = STATE_FINISH;
+                        break;
+                    default:
+                        /* Not reachable */
+                        return APR_EGENERAL;
+                    }
+
+                    break;
+                }
+
+                /* Any other error? */
+                if (zRC != Z_OK) {
+                    return SERF_ERROR_DECOMPRESSION_FAILED;
+                }
+
+                /* As long as zRC == Z_OK, just keep looping. */
+            }
+            /* Okay, we've inflated.  Try to read. */
+            status = serf_bucket_read(ctx->inflate_stream, requested, data,
+                                      len);
+            /* Hide EOF. */
+            if (APR_STATUS_IS_EOF(status)) {
+                status = ctx->stream_status;
+
+                /* If the inflation wasn't finished, return APR_SUCCESS. */
+                if (zRC != Z_STREAM_END)
+                    return APR_SUCCESS;
+
+                /* If our stream is finished too and all data was inflated,
+                 * return SUCCESS so we'll iterate one more time.
+                 */
+                if (APR_STATUS_IS_EOF(status)) {
+                    /* No more data to read from the stream, and everything
+                       inflated. If all data was received correctly, state
+                       should have been advanced to STATE_READING_VERIFY or
+                       STATE_FINISH. If not, then the data was incomplete
+                       and we have an error. */
+                    if (ctx->state != STATE_INFLATE)
+                        return APR_SUCCESS;
+                    else
+                        return SERF_ERROR_DECOMPRESSION_FAILED;
+                }
+            }
+            return status;
+        case STATE_DONE:
+            /* We're done inflating.  Use our finished buffer. */
+            return serf_bucket_read(ctx->stream, requested, data, len);
+        default:
+            /* Not reachable */
+            return APR_EGENERAL;
+        }
+    }
+
+    /* NOTREACHED */
+}
+
+/* ### need to implement */
+#define serf_deflate_readline NULL
+#define serf_deflate_peek NULL
+
+const serf_bucket_type_t serf_bucket_type_deflate = {
+    "DEFLATE",
+    serf_deflate_read,
+    serf_deflate_readline,
+    serf_default_read_iovec,
+    serf_default_read_for_sendfile,
+    serf_default_read_bucket,
+    serf_deflate_peek,
+    serf_deflate_destroy_and_data,
+};

Deleted: vendor/serf/1.3.9/buckets/file_buckets.c
===================================================================
--- vendor/serf/dist/buckets/file_buckets.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/buckets/file_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,117 +0,0 @@
-/* Copyright 2002-2004 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_pools.h>
-
-#include "serf.h"
-#include "serf_bucket_util.h"
-
-typedef struct {
-    apr_file_t *file;
-
-    serf_databuf_t databuf;
-
-} file_context_t;
-
-
-static apr_status_t file_reader(void *baton, apr_size_t bufsize,
-                                char *buf, apr_size_t *len)
-{
-    file_context_t *ctx = baton;
-
-    *len = bufsize;
-    return apr_file_read(ctx->file, buf, len);
-}
-
-serf_bucket_t *serf_bucket_file_create(
-    apr_file_t *file,
-    serf_bucket_alloc_t *allocator)
-{
-    file_context_t *ctx;
-#if APR_HAS_MMAP
-    apr_finfo_t finfo;
-    const char *file_path;
-
-    /* See if we'd be better off mmap'ing this file instead.
-     *
-     * Note that there is a failure case here that we purposely fall through:
-     * if a file is buffered, apr_mmap will reject it.  However, on older
-     * versions of APR, we have no way of knowing this - but apr_mmap_create
-     * will check for this and return APR_EBADF.
-     */
-    apr_file_name_get(&file_path, file);
-    apr_stat(&finfo, file_path, APR_FINFO_SIZE,
-             serf_bucket_allocator_get_pool(allocator));
-    if (APR_MMAP_CANDIDATE(finfo.size)) {
-        apr_status_t status;
-        apr_mmap_t *file_mmap;
-        status = apr_mmap_create(&file_mmap, file, 0, finfo.size,
-                                 APR_MMAP_READ,
-                                 serf_bucket_allocator_get_pool(allocator));
-
-        if (status == APR_SUCCESS) {
-            return serf_bucket_mmap_create(file_mmap, allocator);
-        }
-    }
-#endif
-
-    /* Oh, well. */
-    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
-    ctx->file = file;
-
-    serf_databuf_init(&ctx->databuf);
-    ctx->databuf.read = file_reader;
-    ctx->databuf.read_baton = ctx;
-
-    return serf_bucket_create(&serf_bucket_type_file, allocator, ctx);
-}
-
-static apr_status_t serf_file_read(serf_bucket_t *bucket,
-                                   apr_size_t requested,
-                                   const char **data, apr_size_t *len)
-{
-    file_context_t *ctx = bucket->data;
-
-    return serf_databuf_read(&ctx->databuf, requested, data, len);
-}
-
-static apr_status_t serf_file_readline(serf_bucket_t *bucket,
-                                       int acceptable, int *found,
-                                       const char **data, apr_size_t *len)
-{
-    file_context_t *ctx = bucket->data;
-
-    return serf_databuf_readline(&ctx->databuf, acceptable, found, data, len);
-}
-
-static apr_status_t serf_file_peek(serf_bucket_t *bucket,
-                                   const char **data,
-                                   apr_size_t *len)
-{
-    file_context_t *ctx = bucket->data;
-
-    return serf_databuf_peek(&ctx->databuf, data, len);
-}
-
-const serf_bucket_type_t serf_bucket_type_file = {
-    "FILE",
-    serf_file_read,
-    serf_file_readline,
-    serf_default_read_iovec,
-    serf_default_read_for_sendfile,
-    serf_default_read_bucket,
-    serf_file_peek,
-    serf_default_destroy_and_data,
-};

Copied: vendor/serf/1.3.9/buckets/file_buckets.c (from rev 9259, vendor/serf/dist/buckets/file_buckets.c)
===================================================================
--- vendor/serf/1.3.9/buckets/file_buckets.c	                        (rev 0)
+++ vendor/serf/1.3.9/buckets/file_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,122 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_pools.h>
+
+#include "serf.h"
+#include "serf_bucket_util.h"
+
+typedef struct {
+    apr_file_t *file;
+
+    serf_databuf_t databuf;
+
+} file_context_t;
+
+
+static apr_status_t file_reader(void *baton, apr_size_t bufsize,
+                                char *buf, apr_size_t *len)
+{
+    file_context_t *ctx = baton;
+
+    *len = bufsize;
+    return apr_file_read(ctx->file, buf, len);
+}
+
+serf_bucket_t *serf_bucket_file_create(
+    apr_file_t *file,
+    serf_bucket_alloc_t *allocator)
+{
+    file_context_t *ctx;
+#if APR_HAS_MMAP
+    apr_finfo_t finfo;
+    const char *file_path;
+
+    /* See if we'd be better off mmap'ing this file instead.
+     *
+     * Note that there is a failure case here that we purposely fall through:
+     * if a file is buffered, apr_mmap will reject it.  However, on older
+     * versions of APR, we have no way of knowing this - but apr_mmap_create
+     * will check for this and return APR_EBADF.
+     */
+    apr_file_name_get(&file_path, file);
+    apr_stat(&finfo, file_path, APR_FINFO_SIZE,
+             serf_bucket_allocator_get_pool(allocator));
+    if (APR_MMAP_CANDIDATE(finfo.size)) {
+        apr_status_t status;
+        apr_mmap_t *file_mmap;
+        status = apr_mmap_create(&file_mmap, file, 0, finfo.size,
+                                 APR_MMAP_READ,
+                                 serf_bucket_allocator_get_pool(allocator));
+
+        if (status == APR_SUCCESS) {
+            return serf_bucket_mmap_create(file_mmap, allocator);
+        }
+    }
+#endif
+
+    /* Oh, well. */
+    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
+    ctx->file = file;
+
+    serf_databuf_init(&ctx->databuf);
+    ctx->databuf.read = file_reader;
+    ctx->databuf.read_baton = ctx;
+
+    return serf_bucket_create(&serf_bucket_type_file, allocator, ctx);
+}
+
+static apr_status_t serf_file_read(serf_bucket_t *bucket,
+                                   apr_size_t requested,
+                                   const char **data, apr_size_t *len)
+{
+    file_context_t *ctx = bucket->data;
+
+    return serf_databuf_read(&ctx->databuf, requested, data, len);
+}
+
+static apr_status_t serf_file_readline(serf_bucket_t *bucket,
+                                       int acceptable, int *found,
+                                       const char **data, apr_size_t *len)
+{
+    file_context_t *ctx = bucket->data;
+
+    return serf_databuf_readline(&ctx->databuf, acceptable, found, data, len);
+}
+
+static apr_status_t serf_file_peek(serf_bucket_t *bucket,
+                                   const char **data,
+                                   apr_size_t *len)
+{
+    file_context_t *ctx = bucket->data;
+
+    return serf_databuf_peek(&ctx->databuf, data, len);
+}
+
+const serf_bucket_type_t serf_bucket_type_file = {
+    "FILE",
+    serf_file_read,
+    serf_file_readline,
+    serf_default_read_iovec,
+    serf_default_read_for_sendfile,
+    serf_default_read_bucket,
+    serf_file_peek,
+    serf_default_destroy_and_data,
+};

Deleted: vendor/serf/1.3.9/buckets/headers_buckets.c
===================================================================
--- vendor/serf/dist/buckets/headers_buckets.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/buckets/headers_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,456 +0,0 @@
-/* Copyright 2004 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_general.h>  /* for strcasecmp() */
-
-#include "serf.h"
-#include "serf_bucket_util.h"
-
-#include "serf_private.h" /* for serf__bucket_headers_remove */
-
-
-typedef struct header_list {
-    const char *header;
-    const char *value;
-
-    apr_size_t header_size;
-    apr_size_t value_size;
-
-    int alloc_flags;
-#define ALLOC_HEADER 0x0001  /* header lives in our allocator */
-#define ALLOC_VALUE  0x0002  /* value lives in our allocator */
-
-    struct header_list *next;
-} header_list_t;
-
-typedef struct {
-    header_list_t *list;
-    header_list_t *last;
-
-    header_list_t *cur_read;
-    enum {
-        READ_START,     /* haven't started reading yet */
-        READ_HEADER,    /* reading cur_read->header */
-        READ_SEP,       /* reading ": " */
-        READ_VALUE,     /* reading cur_read->value */
-        READ_CRLF,      /* reading "\r\n" */
-        READ_TERM,      /* reading the final "\r\n" */
-        READ_DONE       /* no more data to read */
-    } state;
-    apr_size_t amt_read; /* how much of the current state we've read */
-
-} headers_context_t;
-
-
-serf_bucket_t *serf_bucket_headers_create(
-    serf_bucket_alloc_t *allocator)
-{
-    headers_context_t *ctx;
-
-    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
-    ctx->list = NULL;
-    ctx->last = NULL;
-    ctx->state = READ_START;
-
-    return serf_bucket_create(&serf_bucket_type_headers, allocator, ctx);
-}
-
-void serf_bucket_headers_setx(
-    serf_bucket_t *bkt,
-    const char *header, apr_size_t header_size, int header_copy,
-    const char *value, apr_size_t value_size, int value_copy)
-{
-    headers_context_t *ctx = bkt->data;
-    header_list_t *hdr;
-
-#if 0
-    /* ### include this? */
-    if (ctx->cur_read) {
-        /* we started reading. can't change now. */
-        abort();
-    }
-#endif
-
-    hdr = serf_bucket_mem_alloc(bkt->allocator, sizeof(*hdr));
-    hdr->header_size = header_size;
-    hdr->value_size = value_size;
-    hdr->alloc_flags = 0;
-    hdr->next = NULL;
-
-    if (header_copy) {
-        hdr->header = serf_bstrmemdup(bkt->allocator, header, header_size);
-        hdr->alloc_flags |= ALLOC_HEADER;
-    }
-    else {
-        hdr->header = header;
-    }
-
-    if (value_copy) {
-        hdr->value = serf_bstrmemdup(bkt->allocator, value, value_size);
-        hdr->alloc_flags |= ALLOC_VALUE;
-    }
-    else {
-        hdr->value = value;
-    }
-
-    /* Add the new header at the end of the list. */
-    if (ctx->last)
-        ctx->last->next = hdr;
-    else
-        ctx->list = hdr;
-
-    ctx->last = hdr;
-}
-
-void serf_bucket_headers_set(
-    serf_bucket_t *headers_bucket,
-    const char *header,
-    const char *value)
-{
-    serf_bucket_headers_setx(headers_bucket,
-                             header, strlen(header), 0,
-                             value, strlen(value), 1);
-}
-
-void serf_bucket_headers_setc(
-    serf_bucket_t *headers_bucket,
-    const char *header,
-    const char *value)
-{
-    serf_bucket_headers_setx(headers_bucket,
-                             header, strlen(header), 1,
-                             value, strlen(value), 1);
-}
-
-void serf_bucket_headers_setn(
-    serf_bucket_t *headers_bucket,
-    const char *header,
-    const char *value)
-{
-    serf_bucket_headers_setx(headers_bucket,
-                             header, strlen(header), 0,
-                             value, strlen(value), 0);
-}
-
-const char *serf_bucket_headers_get(
-    serf_bucket_t *headers_bucket,
-    const char *header)
-{
-    headers_context_t *ctx = headers_bucket->data;
-    header_list_t *found = ctx->list;
-    const char *val = NULL;
-    int value_size = 0;
-    int val_alloc = 0;
-
-    while (found) {
-        if (strcasecmp(found->header, header) == 0) {
-            if (val) {
-                /* 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; the +1 in the alloc
-                   call is for the terminating '\0' */
-                apr_size_t new_size = found->value_size + value_size + 1;
-                char *new_val = serf_bucket_mem_alloc(headers_bucket->allocator,
-                                                      new_size + 1);
-                memcpy(new_val, val, value_size);
-                new_val[value_size] = ',';
-                memcpy(new_val + value_size + 1, found->value,
-                       found->value_size);
-                new_val[new_size] = '\0';
-                /* Copy the new value over the already existing value. */
-                if (val_alloc)
-                    serf_bucket_mem_free(headers_bucket->allocator, (void*)val);
-                val_alloc |= ALLOC_VALUE;
-                val = new_val;
-                value_size = new_size;
-            }
-            else {
-                val = found->value;
-                value_size = found->value_size;
-            }
-        }
-        found = found->next;
-    }
-
-    return val;
-}
-
-void serf__bucket_headers_remove(serf_bucket_t *bucket, const char *header)
-{
-    headers_context_t *ctx = bucket->data;
-    header_list_t *scan = ctx->list, *prev = NULL;
-
-    /* Find and delete all items with the same header (case insensitive) */
-    while (scan) {
-        if (strcasecmp(scan->header, header) == 0) {
-            if (prev) {
-                prev->next = scan->next;
-            } else {
-                ctx->list = scan->next;
-            }
-            if (ctx->last == scan) {
-                ctx->last = NULL;
-            }
-        } else {
-            prev = scan;
-        }
-        scan = scan->next;
-    }
-}
-
-void serf_bucket_headers_do(
-    serf_bucket_t *headers_bucket,
-    serf_bucket_headers_do_callback_fn_t func,
-    void *baton)
-{
-    headers_context_t *ctx = headers_bucket->data;
-    header_list_t *scan = ctx->list;
-
-    while (scan) {
-        if (func(baton, scan->header, scan->value) != 0) {
-            break;
-        }
-        scan = scan->next;
-    }
-}
-
-static void serf_headers_destroy_and_data(serf_bucket_t *bucket)
-{
-    headers_context_t *ctx = bucket->data;
-    header_list_t *scan = ctx->list;
-
-    while (scan) {
-        header_list_t *next_hdr = scan->next;
-
-        if (scan->alloc_flags & ALLOC_HEADER)
-            serf_bucket_mem_free(bucket->allocator, (void *)scan->header);
-        if (scan->alloc_flags & ALLOC_VALUE)
-            serf_bucket_mem_free(bucket->allocator, (void *)scan->value);
-        serf_bucket_mem_free(bucket->allocator, scan);
-
-        scan = next_hdr;
-    }
-
-    serf_default_destroy_and_data(bucket);
-}
-
-static void select_value(
-    headers_context_t *ctx,
-    const char **value,
-    apr_size_t *len)
-{
-    const char *v;
-    apr_size_t l;
-
-    if (ctx->state == READ_START) {
-        if (ctx->list == NULL) {
-            /* No headers. Move straight to the TERM state. */
-            ctx->state = READ_TERM;
-        }
-        else {
-            ctx->state = READ_HEADER;
-            ctx->cur_read = ctx->list;
-        }
-        ctx->amt_read = 0;
-    }
-
-    switch (ctx->state) {
-    case READ_HEADER:
-        v = ctx->cur_read->header;
-        l = ctx->cur_read->header_size;
-        break;
-    case READ_SEP:
-        v = ": ";
-        l = 2;
-        break;
-    case READ_VALUE:
-        v = ctx->cur_read->value;
-        l = ctx->cur_read->value_size;
-        break;
-    case READ_CRLF:
-    case READ_TERM:
-        v = "\r\n";
-        l = 2;
-        break;
-    case READ_DONE:
-        *len = 0;
-        return;
-    default:
-        /* Not reachable */
-        return;
-    }
-
-    *value = v + ctx->amt_read;
-    *len = l - ctx->amt_read;
-}
-
-/* the current data chunk has been read/consumed. move our internal state. */
-static apr_status_t consume_chunk(headers_context_t *ctx)
-{
-    /* move to the next state, resetting the amount read. */
-    ++ctx->state;
-    ctx->amt_read = 0;
-
-    /* just sent the terminator and moved to DONE. signal completion. */
-    if (ctx->state == READ_DONE)
-        return APR_EOF;
-
-    /* end of this header. move to the next one. */
-    if (ctx->state == READ_TERM) {
-        ctx->cur_read = ctx->cur_read->next;
-        if (ctx->cur_read != NULL) {
-            /* We've got another head to send. Reset the read state. */
-            ctx->state = READ_HEADER;
-        }
-        /* else leave in READ_TERM */
-    }
-
-    /* there is more data which can be read immediately. */
-    return APR_SUCCESS;
-}
-
-static apr_status_t serf_headers_peek(serf_bucket_t *bucket,
-                                      const char **data,
-                                      apr_size_t *len)
-{
-    headers_context_t *ctx = bucket->data;
-
-    select_value(ctx, data, len);
-
-    /* already done or returning the CRLF terminator? return EOF */
-    if (ctx->state == READ_DONE || ctx->state == READ_TERM)
-        return APR_EOF;
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t serf_headers_read(serf_bucket_t *bucket,
-                                      apr_size_t requested,
-                                      const char **data, apr_size_t *len)
-{
-    headers_context_t *ctx = bucket->data;
-    apr_size_t avail;
-
-    select_value(ctx, data, &avail);
-    if (ctx->state == READ_DONE) {
-        *len = avail;
-        return APR_EOF;
-    }
-
-    if (requested >= avail) {
-        /* return everything from this chunk */
-        *len = avail;
-
-        /* we consumed this chunk. advance the state. */
-        return consume_chunk(ctx);
-    }
-
-    /* return just the amount requested, and advance our pointer */
-    *len = requested;
-    ctx->amt_read += requested;
-
-    /* there is more that can be read immediately */
-    return APR_SUCCESS;
-}
-
-static apr_status_t serf_headers_readline(serf_bucket_t *bucket,
-                                          int acceptable, int *found,
-                                          const char **data, apr_size_t *len)
-{
-    headers_context_t *ctx = bucket->data;
-    apr_status_t status;
-
-    /* ### what behavior should we use here? APR_EGENERAL for now */
-    if ((acceptable & SERF_NEWLINE_CRLF) == 0)
-        return APR_EGENERAL;
-
-    /* get whatever is in this chunk */
-    select_value(ctx, data, len);
-    if (ctx->state == READ_DONE)
-        return APR_EOF;
-
-    /* we consumed this chunk. advance the state. */
-    status = consume_chunk(ctx);
-
-    /* the type of newline found is easy... */
-    *found = (ctx->state == READ_CRLF || ctx->state == READ_TERM)
-        ? SERF_NEWLINE_CRLF : SERF_NEWLINE_NONE;
-
-    return status;
-}
-
-static apr_status_t serf_headers_read_iovec(serf_bucket_t *bucket,
-                                            apr_size_t requested,
-                                            int vecs_size,
-                                            struct iovec *vecs,
-                                            int *vecs_used)
-{
-    apr_size_t avail = requested;
-    int i;
-
-    *vecs_used = 0;
-
-    for (i = 0; i < vecs_size; i++) {
-        const char *data;
-        apr_size_t len;
-        apr_status_t status;
-
-        /* Calling read() would not be a safe opt in the general case, but it
-         * is here for the header bucket as it only frees all of the header
-         * keys and values when the entire bucket goes away - not on a
-         * per-read() basis as is normally the case.
-         */
-        status = serf_headers_read(bucket, avail, &data, &len);
-
-        if (len) {
-            vecs[*vecs_used].iov_base = (char*)data;
-            vecs[*vecs_used].iov_len = len;
-
-            (*vecs_used)++;
-
-            if (avail != SERF_READ_ALL_AVAIL) {
-                avail -= len;
-
-                /* If we reach 0, then read()'s status will suffice.  */
-                if (avail == 0) {
-                    return status;
-                }
-            }
-        }
-
-        if (status) {
-            return status;
-        }
-    }
-
-    return APR_SUCCESS;
-}
-
-const serf_bucket_type_t serf_bucket_type_headers = {
-    "HEADERS",
-    serf_headers_read,
-    serf_headers_readline,
-    serf_headers_read_iovec,
-    serf_default_read_for_sendfile,
-    serf_default_read_bucket,
-    serf_headers_peek,
-    serf_headers_destroy_and_data,
-};

Copied: vendor/serf/1.3.9/buckets/headers_buckets.c (from rev 9259, vendor/serf/dist/buckets/headers_buckets.c)
===================================================================
--- vendor/serf/1.3.9/buckets/headers_buckets.c	                        (rev 0)
+++ vendor/serf/1.3.9/buckets/headers_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,461 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_general.h>  /* for strcasecmp() */
+
+#include "serf.h"
+#include "serf_bucket_util.h"
+
+#include "serf_private.h" /* for serf__bucket_headers_remove */
+
+
+typedef struct header_list {
+    const char *header;
+    const char *value;
+
+    apr_size_t header_size;
+    apr_size_t value_size;
+
+    int alloc_flags;
+#define ALLOC_HEADER 0x0001  /* header lives in our allocator */
+#define ALLOC_VALUE  0x0002  /* value lives in our allocator */
+
+    struct header_list *next;
+} header_list_t;
+
+typedef struct {
+    header_list_t *list;
+    header_list_t *last;
+
+    header_list_t *cur_read;
+    enum {
+        READ_START,     /* haven't started reading yet */
+        READ_HEADER,    /* reading cur_read->header */
+        READ_SEP,       /* reading ": " */
+        READ_VALUE,     /* reading cur_read->value */
+        READ_CRLF,      /* reading "\r\n" */
+        READ_TERM,      /* reading the final "\r\n" */
+        READ_DONE       /* no more data to read */
+    } state;
+    apr_size_t amt_read; /* how much of the current state we've read */
+
+} headers_context_t;
+
+
+serf_bucket_t *serf_bucket_headers_create(
+    serf_bucket_alloc_t *allocator)
+{
+    headers_context_t *ctx;
+
+    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
+    ctx->list = NULL;
+    ctx->last = NULL;
+    ctx->state = READ_START;
+
+    return serf_bucket_create(&serf_bucket_type_headers, allocator, ctx);
+}
+
+void serf_bucket_headers_setx(
+    serf_bucket_t *bkt,
+    const char *header, apr_size_t header_size, int header_copy,
+    const char *value, apr_size_t value_size, int value_copy)
+{
+    headers_context_t *ctx = bkt->data;
+    header_list_t *hdr;
+
+#if 0
+    /* ### include this? */
+    if (ctx->cur_read) {
+        /* we started reading. can't change now. */
+        abort();
+    }
+#endif
+
+    hdr = serf_bucket_mem_alloc(bkt->allocator, sizeof(*hdr));
+    hdr->header_size = header_size;
+    hdr->value_size = value_size;
+    hdr->alloc_flags = 0;
+    hdr->next = NULL;
+
+    if (header_copy) {
+        hdr->header = serf_bstrmemdup(bkt->allocator, header, header_size);
+        hdr->alloc_flags |= ALLOC_HEADER;
+    }
+    else {
+        hdr->header = header;
+    }
+
+    if (value_copy) {
+        hdr->value = serf_bstrmemdup(bkt->allocator, value, value_size);
+        hdr->alloc_flags |= ALLOC_VALUE;
+    }
+    else {
+        hdr->value = value;
+    }
+
+    /* Add the new header at the end of the list. */
+    if (ctx->last)
+        ctx->last->next = hdr;
+    else
+        ctx->list = hdr;
+
+    ctx->last = hdr;
+}
+
+void serf_bucket_headers_set(
+    serf_bucket_t *headers_bucket,
+    const char *header,
+    const char *value)
+{
+    serf_bucket_headers_setx(headers_bucket,
+                             header, strlen(header), 0,
+                             value, strlen(value), 1);
+}
+
+void serf_bucket_headers_setc(
+    serf_bucket_t *headers_bucket,
+    const char *header,
+    const char *value)
+{
+    serf_bucket_headers_setx(headers_bucket,
+                             header, strlen(header), 1,
+                             value, strlen(value), 1);
+}
+
+void serf_bucket_headers_setn(
+    serf_bucket_t *headers_bucket,
+    const char *header,
+    const char *value)
+{
+    serf_bucket_headers_setx(headers_bucket,
+                             header, strlen(header), 0,
+                             value, strlen(value), 0);
+}
+
+const char *serf_bucket_headers_get(
+    serf_bucket_t *headers_bucket,
+    const char *header)
+{
+    headers_context_t *ctx = headers_bucket->data;
+    header_list_t *found = ctx->list;
+    const char *val = NULL;
+    int value_size = 0;
+    int val_alloc = 0;
+
+    while (found) {
+        if (strcasecmp(found->header, header) == 0) {
+            if (val) {
+                /* 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; the +1 in the alloc
+                   call is for the terminating '\0' */
+                apr_size_t new_size = found->value_size + value_size + 1;
+                char *new_val = serf_bucket_mem_alloc(headers_bucket->allocator,
+                                                      new_size + 1);
+                memcpy(new_val, val, value_size);
+                new_val[value_size] = ',';
+                memcpy(new_val + value_size + 1, found->value,
+                       found->value_size);
+                new_val[new_size] = '\0';
+                /* Copy the new value over the already existing value. */
+                if (val_alloc)
+                    serf_bucket_mem_free(headers_bucket->allocator, (void*)val);
+                val_alloc |= ALLOC_VALUE;
+                val = new_val;
+                value_size = new_size;
+            }
+            else {
+                val = found->value;
+                value_size = found->value_size;
+            }
+        }
+        found = found->next;
+    }
+
+    return val;
+}
+
+void serf__bucket_headers_remove(serf_bucket_t *bucket, const char *header)
+{
+    headers_context_t *ctx = bucket->data;
+    header_list_t *scan = ctx->list, *prev = NULL;
+
+    /* Find and delete all items with the same header (case insensitive) */
+    while (scan) {
+        if (strcasecmp(scan->header, header) == 0) {
+            if (prev) {
+                prev->next = scan->next;
+            } else {
+                ctx->list = scan->next;
+            }
+            if (ctx->last == scan) {
+                ctx->last = NULL;
+            }
+        } else {
+            prev = scan;
+        }
+        scan = scan->next;
+    }
+}
+
+void serf_bucket_headers_do(
+    serf_bucket_t *headers_bucket,
+    serf_bucket_headers_do_callback_fn_t func,
+    void *baton)
+{
+    headers_context_t *ctx = headers_bucket->data;
+    header_list_t *scan = ctx->list;
+
+    while (scan) {
+        if (func(baton, scan->header, scan->value) != 0) {
+            break;
+        }
+        scan = scan->next;
+    }
+}
+
+static void serf_headers_destroy_and_data(serf_bucket_t *bucket)
+{
+    headers_context_t *ctx = bucket->data;
+    header_list_t *scan = ctx->list;
+
+    while (scan) {
+        header_list_t *next_hdr = scan->next;
+
+        if (scan->alloc_flags & ALLOC_HEADER)
+            serf_bucket_mem_free(bucket->allocator, (void *)scan->header);
+        if (scan->alloc_flags & ALLOC_VALUE)
+            serf_bucket_mem_free(bucket->allocator, (void *)scan->value);
+        serf_bucket_mem_free(bucket->allocator, scan);
+
+        scan = next_hdr;
+    }
+
+    serf_default_destroy_and_data(bucket);
+}
+
+static void select_value(
+    headers_context_t *ctx,
+    const char **value,
+    apr_size_t *len)
+{
+    const char *v;
+    apr_size_t l;
+
+    if (ctx->state == READ_START) {
+        if (ctx->list == NULL) {
+            /* No headers. Move straight to the TERM state. */
+            ctx->state = READ_TERM;
+        }
+        else {
+            ctx->state = READ_HEADER;
+            ctx->cur_read = ctx->list;
+        }
+        ctx->amt_read = 0;
+    }
+
+    switch (ctx->state) {
+    case READ_HEADER:
+        v = ctx->cur_read->header;
+        l = ctx->cur_read->header_size;
+        break;
+    case READ_SEP:
+        v = ": ";
+        l = 2;
+        break;
+    case READ_VALUE:
+        v = ctx->cur_read->value;
+        l = ctx->cur_read->value_size;
+        break;
+    case READ_CRLF:
+    case READ_TERM:
+        v = "\r\n";
+        l = 2;
+        break;
+    case READ_DONE:
+        *len = 0;
+        return;
+    default:
+        /* Not reachable */
+        return;
+    }
+
+    *value = v + ctx->amt_read;
+    *len = l - ctx->amt_read;
+}
+
+/* the current data chunk has been read/consumed. move our internal state. */
+static apr_status_t consume_chunk(headers_context_t *ctx)
+{
+    /* move to the next state, resetting the amount read. */
+    ++ctx->state;
+    ctx->amt_read = 0;
+
+    /* just sent the terminator and moved to DONE. signal completion. */
+    if (ctx->state == READ_DONE)
+        return APR_EOF;
+
+    /* end of this header. move to the next one. */
+    if (ctx->state == READ_TERM) {
+        ctx->cur_read = ctx->cur_read->next;
+        if (ctx->cur_read != NULL) {
+            /* We've got another head to send. Reset the read state. */
+            ctx->state = READ_HEADER;
+        }
+        /* else leave in READ_TERM */
+    }
+
+    /* there is more data which can be read immediately. */
+    return APR_SUCCESS;
+}
+
+static apr_status_t serf_headers_peek(serf_bucket_t *bucket,
+                                      const char **data,
+                                      apr_size_t *len)
+{
+    headers_context_t *ctx = bucket->data;
+
+    select_value(ctx, data, len);
+
+    /* already done or returning the CRLF terminator? return EOF */
+    if (ctx->state == READ_DONE || ctx->state == READ_TERM)
+        return APR_EOF;
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t serf_headers_read(serf_bucket_t *bucket,
+                                      apr_size_t requested,
+                                      const char **data, apr_size_t *len)
+{
+    headers_context_t *ctx = bucket->data;
+    apr_size_t avail;
+
+    select_value(ctx, data, &avail);
+    if (ctx->state == READ_DONE) {
+        *len = avail;
+        return APR_EOF;
+    }
+
+    if (requested >= avail) {
+        /* return everything from this chunk */
+        *len = avail;
+
+        /* we consumed this chunk. advance the state. */
+        return consume_chunk(ctx);
+    }
+
+    /* return just the amount requested, and advance our pointer */
+    *len = requested;
+    ctx->amt_read += requested;
+
+    /* there is more that can be read immediately */
+    return APR_SUCCESS;
+}
+
+static apr_status_t serf_headers_readline(serf_bucket_t *bucket,
+                                          int acceptable, int *found,
+                                          const char **data, apr_size_t *len)
+{
+    headers_context_t *ctx = bucket->data;
+    apr_status_t status;
+
+    /* ### what behavior should we use here? APR_EGENERAL for now */
+    if ((acceptable & SERF_NEWLINE_CRLF) == 0)
+        return APR_EGENERAL;
+
+    /* get whatever is in this chunk */
+    select_value(ctx, data, len);
+    if (ctx->state == READ_DONE)
+        return APR_EOF;
+
+    /* we consumed this chunk. advance the state. */
+    status = consume_chunk(ctx);
+
+    /* the type of newline found is easy... */
+    *found = (ctx->state == READ_CRLF || ctx->state == READ_TERM)
+        ? SERF_NEWLINE_CRLF : SERF_NEWLINE_NONE;
+
+    return status;
+}
+
+static apr_status_t serf_headers_read_iovec(serf_bucket_t *bucket,
+                                            apr_size_t requested,
+                                            int vecs_size,
+                                            struct iovec *vecs,
+                                            int *vecs_used)
+{
+    apr_size_t avail = requested;
+    int i;
+
+    *vecs_used = 0;
+
+    for (i = 0; i < vecs_size; i++) {
+        const char *data;
+        apr_size_t len;
+        apr_status_t status;
+
+        /* Calling read() would not be a safe opt in the general case, but it
+         * is here for the header bucket as it only frees all of the header
+         * keys and values when the entire bucket goes away - not on a
+         * per-read() basis as is normally the case.
+         */
+        status = serf_headers_read(bucket, avail, &data, &len);
+
+        if (len) {
+            vecs[*vecs_used].iov_base = (char*)data;
+            vecs[*vecs_used].iov_len = len;
+
+            (*vecs_used)++;
+
+            if (avail != SERF_READ_ALL_AVAIL) {
+                avail -= len;
+
+                /* If we reach 0, then read()'s status will suffice.  */
+                if (avail == 0) {
+                    return status;
+                }
+            }
+        }
+
+        if (status) {
+            return status;
+        }
+    }
+
+    return APR_SUCCESS;
+}
+
+const serf_bucket_type_t serf_bucket_type_headers = {
+    "HEADERS",
+    serf_headers_read,
+    serf_headers_readline,
+    serf_headers_read_iovec,
+    serf_default_read_for_sendfile,
+    serf_default_read_bucket,
+    serf_headers_peek,
+    serf_headers_destroy_and_data,
+};

Deleted: vendor/serf/1.3.9/buckets/iovec_buckets.c
===================================================================
--- vendor/serf/dist/buckets/iovec_buckets.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/buckets/iovec_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,169 +0,0 @@
-/* Copyright 2011 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_pools.h>
-
-#include "serf.h"
-#include "serf_bucket_util.h"
-
-
-typedef struct {
-    struct iovec *vecs;
-
-    /* Total number of buffer stored in the vecs var. */
-    int vecs_len;
-    /* Points to the first unread buffer. */
-    int current_vec;
-    /* First buffer offset. */
-    int offset;
-} iovec_context_t;
-
-serf_bucket_t *serf_bucket_iovec_create(
-    struct iovec vecs[],
-    int len,
-    serf_bucket_alloc_t *allocator)
-{
-    iovec_context_t *ctx;
-    int i;
-
-    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
-    ctx->vecs = serf_bucket_mem_alloc(allocator, len * sizeof(struct iovec));
-    ctx->vecs_len = len;
-    ctx->current_vec = 0;
-    ctx->offset = 0;
-
-    /* copy all buffers to our iovec. */
-    for (i = 0; i < len; i++) {
-        ctx->vecs[i].iov_base = vecs[i].iov_base;
-        ctx->vecs[i].iov_len = vecs[i].iov_len;
-    }
-
-    return serf_bucket_create(&serf_bucket_type_iovec, allocator, ctx);
-}
-
-static apr_status_t serf_iovec_readline(serf_bucket_t *bucket,
-                                         int acceptable, int *found,
-                                         const char **data, apr_size_t *len)
-{
-    return APR_ENOTIMPL;
-}
-
-static apr_status_t serf_iovec_read_iovec(serf_bucket_t *bucket,
-                                          apr_size_t requested,
-                                          int vecs_size,
-                                          struct iovec *vecs,
-                                          int *vecs_used)
-{
-    iovec_context_t *ctx = bucket->data;
-
-    *vecs_used = 0;
-
-    /* copy the requested amount of buffers to the provided iovec. */
-    for (; ctx->current_vec < ctx->vecs_len; ctx->current_vec++) {
-        struct iovec vec = ctx->vecs[ctx->current_vec];
-        apr_size_t remaining;
-
-        if (requested != SERF_READ_ALL_AVAIL && requested <= 0)
-            break;
-        if (*vecs_used >= vecs_size)
-            break;
-
-        vecs[*vecs_used].iov_base = (char*)vec.iov_base + ctx->offset;
-        remaining = vec.iov_len - ctx->offset;
-
-        /* Less bytes requested than remaining in the current buffer. */
-        if (requested != SERF_READ_ALL_AVAIL && requested < remaining) {
-            vecs[*vecs_used].iov_len = requested;
-            ctx->offset += requested;
-            requested = 0;
-            (*vecs_used)++;
-            break;
-        } else {
-            /* Copy the complete buffer. */
-            vecs[*vecs_used].iov_len = remaining;
-            ctx->offset = 0;
-            if (requested != SERF_READ_ALL_AVAIL)
-                requested -= remaining;
-            (*vecs_used)++;
-        }
-    }
-
-    if (ctx->current_vec == ctx->vecs_len && !ctx->offset)
-        return APR_EOF;
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t serf_iovec_read(serf_bucket_t *bucket,
-                                    apr_size_t requested,
-                                    const char **data, apr_size_t *len)
-{
-    struct iovec vec[1];
-    apr_status_t status;
-    int vecs_used;
-
-    status = serf_iovec_read_iovec(bucket, requested, 1, vec, &vecs_used);
-
-    if (vecs_used) {
-        *data = vec[0].iov_base;
-        *len = vec[0].iov_len;
-    } else {
-        *len = 0;
-    }
-
-    return status;
-}
-
-static apr_status_t serf_iovec_peek(serf_bucket_t *bucket,
-                                    const char **data,
-                                    apr_size_t *len)
-{
-    iovec_context_t *ctx = bucket->data;
-
-    if (ctx->current_vec >= ctx->vecs_len) {
-        *len = 0;
-        return APR_EOF;
-    }
-
-    /* Return the first unread buffer, don't bother combining all
-       remaining data. */
-    *data = ctx->vecs[ctx->current_vec].iov_base;
-    *len = ctx->vecs[ctx->current_vec].iov_len;
-
-    if (ctx->current_vec + 1 == ctx->vecs_len)
-        return APR_EOF;
-
-    return APR_SUCCESS;
-}
-
-static void serf_iovec_destroy(serf_bucket_t *bucket)
-{
-    iovec_context_t *ctx = bucket->data;
-
-    serf_bucket_mem_free(bucket->allocator, ctx->vecs);
-    serf_default_destroy_and_data(bucket);
-}
-
-
-const serf_bucket_type_t serf_bucket_type_iovec = {
-    "IOVEC",
-    serf_iovec_read,
-    serf_iovec_readline,
-    serf_iovec_read_iovec,
-    serf_default_read_for_sendfile,
-    serf_default_read_bucket,
-    serf_iovec_peek,
-    serf_iovec_destroy,
-};

Copied: vendor/serf/1.3.9/buckets/iovec_buckets.c (from rev 9259, vendor/serf/dist/buckets/iovec_buckets.c)
===================================================================
--- vendor/serf/1.3.9/buckets/iovec_buckets.c	                        (rev 0)
+++ vendor/serf/1.3.9/buckets/iovec_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,174 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_pools.h>
+
+#include "serf.h"
+#include "serf_bucket_util.h"
+
+
+typedef struct {
+    struct iovec *vecs;
+
+    /* Total number of buffer stored in the vecs var. */
+    int vecs_len;
+    /* Points to the first unread buffer. */
+    int current_vec;
+    /* First buffer offset. */
+    int offset;
+} iovec_context_t;
+
+serf_bucket_t *serf_bucket_iovec_create(
+    struct iovec vecs[],
+    int len,
+    serf_bucket_alloc_t *allocator)
+{
+    iovec_context_t *ctx;
+    int i;
+
+    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
+    ctx->vecs = serf_bucket_mem_alloc(allocator, len * sizeof(struct iovec));
+    ctx->vecs_len = len;
+    ctx->current_vec = 0;
+    ctx->offset = 0;
+
+    /* copy all buffers to our iovec. */
+    for (i = 0; i < len; i++) {
+        ctx->vecs[i].iov_base = vecs[i].iov_base;
+        ctx->vecs[i].iov_len = vecs[i].iov_len;
+    }
+
+    return serf_bucket_create(&serf_bucket_type_iovec, allocator, ctx);
+}
+
+static apr_status_t serf_iovec_readline(serf_bucket_t *bucket,
+                                         int acceptable, int *found,
+                                         const char **data, apr_size_t *len)
+{
+    return APR_ENOTIMPL;
+}
+
+static apr_status_t serf_iovec_read_iovec(serf_bucket_t *bucket,
+                                          apr_size_t requested,
+                                          int vecs_size,
+                                          struct iovec *vecs,
+                                          int *vecs_used)
+{
+    iovec_context_t *ctx = bucket->data;
+
+    *vecs_used = 0;
+
+    /* copy the requested amount of buffers to the provided iovec. */
+    for (; ctx->current_vec < ctx->vecs_len; ctx->current_vec++) {
+        struct iovec vec = ctx->vecs[ctx->current_vec];
+        apr_size_t remaining;
+
+        if (requested != SERF_READ_ALL_AVAIL && requested <= 0)
+            break;
+        if (*vecs_used >= vecs_size)
+            break;
+
+        vecs[*vecs_used].iov_base = (char*)vec.iov_base + ctx->offset;
+        remaining = vec.iov_len - ctx->offset;
+
+        /* Less bytes requested than remaining in the current buffer. */
+        if (requested != SERF_READ_ALL_AVAIL && requested < remaining) {
+            vecs[*vecs_used].iov_len = requested;
+            ctx->offset += requested;
+            requested = 0;
+            (*vecs_used)++;
+            break;
+        } else {
+            /* Copy the complete buffer. */
+            vecs[*vecs_used].iov_len = remaining;
+            ctx->offset = 0;
+            if (requested != SERF_READ_ALL_AVAIL)
+                requested -= remaining;
+            (*vecs_used)++;
+        }
+    }
+
+    if (ctx->current_vec == ctx->vecs_len && !ctx->offset)
+        return APR_EOF;
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t serf_iovec_read(serf_bucket_t *bucket,
+                                    apr_size_t requested,
+                                    const char **data, apr_size_t *len)
+{
+    struct iovec vec[1];
+    apr_status_t status;
+    int vecs_used;
+
+    status = serf_iovec_read_iovec(bucket, requested, 1, vec, &vecs_used);
+
+    if (vecs_used) {
+        *data = vec[0].iov_base;
+        *len = vec[0].iov_len;
+    } else {
+        *len = 0;
+    }
+
+    return status;
+}
+
+static apr_status_t serf_iovec_peek(serf_bucket_t *bucket,
+                                    const char **data,
+                                    apr_size_t *len)
+{
+    iovec_context_t *ctx = bucket->data;
+
+    if (ctx->current_vec >= ctx->vecs_len) {
+        *len = 0;
+        return APR_EOF;
+    }
+
+    /* Return the first unread buffer, don't bother combining all
+       remaining data. */
+    *data = ctx->vecs[ctx->current_vec].iov_base;
+    *len = ctx->vecs[ctx->current_vec].iov_len;
+
+    if (ctx->current_vec + 1 == ctx->vecs_len)
+        return APR_EOF;
+
+    return APR_SUCCESS;
+}
+
+static void serf_iovec_destroy(serf_bucket_t *bucket)
+{
+    iovec_context_t *ctx = bucket->data;
+
+    serf_bucket_mem_free(bucket->allocator, ctx->vecs);
+    serf_default_destroy_and_data(bucket);
+}
+
+
+const serf_bucket_type_t serf_bucket_type_iovec = {
+    "IOVEC",
+    serf_iovec_read,
+    serf_iovec_readline,
+    serf_iovec_read_iovec,
+    serf_default_read_for_sendfile,
+    serf_default_read_bucket,
+    serf_iovec_peek,
+    serf_iovec_destroy,
+};

Deleted: vendor/serf/1.3.9/buckets/limit_buckets.c
===================================================================
--- vendor/serf/dist/buckets/limit_buckets.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/buckets/limit_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,127 +0,0 @@
-/* Copyright 2002-2004 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_pools.h>
-
-#include "serf.h"
-#include "serf_bucket_util.h"
-#include "serf_private.h"
-
-typedef struct {
-    serf_bucket_t *stream;
-    apr_uint64_t remaining;
-} limit_context_t;
-
-
-serf_bucket_t *serf_bucket_limit_create(
-    serf_bucket_t *stream, apr_uint64_t len, serf_bucket_alloc_t *allocator)
-{
-    limit_context_t *ctx;
-
-    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
-    ctx->stream = stream;
-    ctx->remaining = len;
-
-    return serf_bucket_create(&serf_bucket_type_limit, allocator, ctx);
-}
-
-static apr_status_t serf_limit_read(serf_bucket_t *bucket,
-                                    apr_size_t requested,
-                                    const char **data, apr_size_t *len)
-{
-    limit_context_t *ctx = bucket->data;
-    apr_status_t status;
-
-    if (!ctx->remaining) {
-        *len = 0;
-        return APR_EOF;
-    }
-
-    if (requested == SERF_READ_ALL_AVAIL || requested > ctx->remaining) {
-        if (ctx->remaining <= REQUESTED_MAX) {
-            requested = (apr_size_t) ctx->remaining;
-        } else {
-            requested = REQUESTED_MAX;
-        }
-    }
-
-    status = serf_bucket_read(ctx->stream, requested, data, len);
-
-    if (!SERF_BUCKET_READ_ERROR(status)) {
-        ctx->remaining -= *len;
-    }
-
-    /* If we have met our limit and don't have a status, return EOF. */
-    if (!ctx->remaining && !status) {
-        status = APR_EOF;
-    }
-
-    return status;
-}
-
-static apr_status_t serf_limit_readline(serf_bucket_t *bucket,
-                                         int acceptable, int *found,
-                                         const char **data, apr_size_t *len)
-{
-    limit_context_t *ctx = bucket->data;
-    apr_status_t status;
-
-    if (!ctx->remaining) {
-        *len = 0;
-        return APR_EOF;
-    }
-
-    status = serf_bucket_readline(ctx->stream, acceptable, found, data, len);
-
-    if (!SERF_BUCKET_READ_ERROR(status)) {
-        ctx->remaining -= *len;
-    }
-
-    /* If we have met our limit and don't have a status, return EOF. */
-    if (!ctx->remaining && !status) {
-        status = APR_EOF;
-    }
-
-    return status;
-}
-
-static apr_status_t serf_limit_peek(serf_bucket_t *bucket,
-                                     const char **data,
-                                     apr_size_t *len)
-{
-    limit_context_t *ctx = bucket->data;
-
-    return serf_bucket_peek(ctx->stream, data, len);
-}
-
-static void serf_limit_destroy(serf_bucket_t *bucket)
-{
-    limit_context_t *ctx = bucket->data;
-
-    serf_bucket_destroy(ctx->stream);
-
-    serf_default_destroy_and_data(bucket);
-}
-
-const serf_bucket_type_t serf_bucket_type_limit = {
-    "LIMIT",
-    serf_limit_read,
-    serf_limit_readline,
-    serf_default_read_iovec,
-    serf_default_read_for_sendfile,
-    serf_default_read_bucket,
-    serf_limit_peek,
-    serf_limit_destroy,
-};

Copied: vendor/serf/1.3.9/buckets/limit_buckets.c (from rev 9259, vendor/serf/dist/buckets/limit_buckets.c)
===================================================================
--- vendor/serf/1.3.9/buckets/limit_buckets.c	                        (rev 0)
+++ vendor/serf/1.3.9/buckets/limit_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,132 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_pools.h>
+
+#include "serf.h"
+#include "serf_bucket_util.h"
+#include "serf_private.h"
+
+typedef struct {
+    serf_bucket_t *stream;
+    apr_uint64_t remaining;
+} limit_context_t;
+
+
+serf_bucket_t *serf_bucket_limit_create(
+    serf_bucket_t *stream, apr_uint64_t len, serf_bucket_alloc_t *allocator)
+{
+    limit_context_t *ctx;
+
+    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
+    ctx->stream = stream;
+    ctx->remaining = len;
+
+    return serf_bucket_create(&serf_bucket_type_limit, allocator, ctx);
+}
+
+static apr_status_t serf_limit_read(serf_bucket_t *bucket,
+                                    apr_size_t requested,
+                                    const char **data, apr_size_t *len)
+{
+    limit_context_t *ctx = bucket->data;
+    apr_status_t status;
+
+    if (!ctx->remaining) {
+        *len = 0;
+        return APR_EOF;
+    }
+
+    if (requested == SERF_READ_ALL_AVAIL || requested > ctx->remaining) {
+        if (ctx->remaining <= REQUESTED_MAX) {
+            requested = (apr_size_t) ctx->remaining;
+        } else {
+            requested = REQUESTED_MAX;
+        }
+    }
+
+    status = serf_bucket_read(ctx->stream, requested, data, len);
+
+    if (!SERF_BUCKET_READ_ERROR(status)) {
+        ctx->remaining -= *len;
+    }
+
+    /* If we have met our limit and don't have a status, return EOF. */
+    if (!ctx->remaining && !status) {
+        status = APR_EOF;
+    }
+
+    return status;
+}
+
+static apr_status_t serf_limit_readline(serf_bucket_t *bucket,
+                                         int acceptable, int *found,
+                                         const char **data, apr_size_t *len)
+{
+    limit_context_t *ctx = bucket->data;
+    apr_status_t status;
+
+    if (!ctx->remaining) {
+        *len = 0;
+        return APR_EOF;
+    }
+
+    status = serf_bucket_readline(ctx->stream, acceptable, found, data, len);
+
+    if (!SERF_BUCKET_READ_ERROR(status)) {
+        ctx->remaining -= *len;
+    }
+
+    /* If we have met our limit and don't have a status, return EOF. */
+    if (!ctx->remaining && !status) {
+        status = APR_EOF;
+    }
+
+    return status;
+}
+
+static apr_status_t serf_limit_peek(serf_bucket_t *bucket,
+                                     const char **data,
+                                     apr_size_t *len)
+{
+    limit_context_t *ctx = bucket->data;
+
+    return serf_bucket_peek(ctx->stream, data, len);
+}
+
+static void serf_limit_destroy(serf_bucket_t *bucket)
+{
+    limit_context_t *ctx = bucket->data;
+
+    serf_bucket_destroy(ctx->stream);
+
+    serf_default_destroy_and_data(bucket);
+}
+
+const serf_bucket_type_t serf_bucket_type_limit = {
+    "LIMIT",
+    serf_limit_read,
+    serf_limit_readline,
+    serf_default_read_iovec,
+    serf_default_read_for_sendfile,
+    serf_default_read_bucket,
+    serf_limit_peek,
+    serf_limit_destroy,
+};

Deleted: vendor/serf/1.3.9/buckets/mmap_buckets.c
===================================================================
--- vendor/serf/dist/buckets/mmap_buckets.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/buckets/mmap_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,140 +0,0 @@
-/* Copyright 2002-2004 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_pools.h>
-#include <apr_mmap.h>
-
-#include "serf.h"
-#include "serf_bucket_util.h"
-
-#if APR_HAS_MMAP
-
-typedef struct {
-    apr_mmap_t *mmap;
-    void *current;
-    apr_off_t offset;
-    apr_off_t remaining;
-} mmap_context_t;
-
-
-serf_bucket_t *serf_bucket_mmap_create(
-    apr_mmap_t *file_mmap,
-    serf_bucket_alloc_t *allocator)
-{
-    mmap_context_t *ctx;
-
-    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
-    ctx->mmap = file_mmap;
-    ctx->current = NULL;
-    ctx->offset = 0;
-    ctx->remaining = ctx->mmap->size;
-
-    return serf_bucket_create(&serf_bucket_type_mmap, allocator, ctx);
-}
-
-static apr_status_t serf_mmap_read(serf_bucket_t *bucket,
-                                     apr_size_t requested,
-                                     const char **data, apr_size_t *len)
-{
-    mmap_context_t *ctx = bucket->data;
-
-    if (requested == SERF_READ_ALL_AVAIL || requested > ctx->remaining) {
-        *len = ctx->remaining;
-    }
-    else {
-        *len = requested;
-    }
-
-    /* ### Would it be faster to call this once and do the offset ourselves? */
-    apr_mmap_offset((void**)data, ctx->mmap, ctx->offset);
-
-    /* For the next read... */
-    ctx->offset += *len;
-    ctx->remaining -= *len;
-
-    if (ctx->remaining == 0) {
-        return APR_EOF;
-    }
-    return APR_SUCCESS;
-}
-
-static apr_status_t serf_mmap_readline(serf_bucket_t *bucket,
-                                         int acceptable, int *found,
-                                         const char **data, apr_size_t *len)
-{
-    mmap_context_t *ctx = bucket->data;
-    const char *end;
-
-    /* ### Would it be faster to call this once and do the offset ourselves? */
-    apr_mmap_offset((void**)data, ctx->mmap, ctx->offset);
-    end = *data;
-
-    /* XXX An overflow is generated if we pass &ctx->remaining to readline.
-     * Not real clear why.
-     */
-    *len = ctx->remaining;
-
-    serf_util_readline(&end, len, acceptable, found);
-
-    *len = end - *data;
-
-    ctx->offset += *len;
-    ctx->remaining -= *len;
-
-    if (ctx->remaining == 0) {
-        return APR_EOF;
-    }
-    return APR_SUCCESS;
-}
-
-static apr_status_t serf_mmap_peek(serf_bucket_t *bucket,
-                                     const char **data,
-                                     apr_size_t *len)
-{
-    /* Oh, bah. */
-    return APR_ENOTIMPL;
-}
-
-const serf_bucket_type_t serf_bucket_type_mmap = {
-    "MMAP",
-    serf_mmap_read,
-    serf_mmap_readline,
-    serf_default_read_iovec,
-    serf_default_read_for_sendfile,
-    serf_default_read_bucket,
-    serf_mmap_peek,
-    serf_default_destroy_and_data,
-};
-
-#else /* !APR_HAS_MMAP */
-
-serf_bucket_t *serf_bucket_mmap_create(apr_mmap_t *file_mmap,
-                                       serf_bucket_alloc_t *allocator)
-{
-    return NULL;
-}
-
-const serf_bucket_type_t serf_bucket_type_mmap = {
-    "MMAP",
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-};
-
-#endif

Copied: vendor/serf/1.3.9/buckets/mmap_buckets.c (from rev 9259, vendor/serf/dist/buckets/mmap_buckets.c)
===================================================================
--- vendor/serf/1.3.9/buckets/mmap_buckets.c	                        (rev 0)
+++ vendor/serf/1.3.9/buckets/mmap_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,145 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_pools.h>
+#include <apr_mmap.h>
+
+#include "serf.h"
+#include "serf_bucket_util.h"
+
+#if APR_HAS_MMAP
+
+typedef struct {
+    apr_mmap_t *mmap;
+    void *current;
+    apr_off_t offset;
+    apr_off_t remaining;
+} mmap_context_t;
+
+
+serf_bucket_t *serf_bucket_mmap_create(
+    apr_mmap_t *file_mmap,
+    serf_bucket_alloc_t *allocator)
+{
+    mmap_context_t *ctx;
+
+    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
+    ctx->mmap = file_mmap;
+    ctx->current = NULL;
+    ctx->offset = 0;
+    ctx->remaining = ctx->mmap->size;
+
+    return serf_bucket_create(&serf_bucket_type_mmap, allocator, ctx);
+}
+
+static apr_status_t serf_mmap_read(serf_bucket_t *bucket,
+                                     apr_size_t requested,
+                                     const char **data, apr_size_t *len)
+{
+    mmap_context_t *ctx = bucket->data;
+
+    if (requested == SERF_READ_ALL_AVAIL || requested > ctx->remaining) {
+        *len = ctx->remaining;
+    }
+    else {
+        *len = requested;
+    }
+
+    /* ### Would it be faster to call this once and do the offset ourselves? */
+    apr_mmap_offset((void**)data, ctx->mmap, ctx->offset);
+
+    /* For the next read... */
+    ctx->offset += *len;
+    ctx->remaining -= *len;
+
+    if (ctx->remaining == 0) {
+        return APR_EOF;
+    }
+    return APR_SUCCESS;
+}
+
+static apr_status_t serf_mmap_readline(serf_bucket_t *bucket,
+                                         int acceptable, int *found,
+                                         const char **data, apr_size_t *len)
+{
+    mmap_context_t *ctx = bucket->data;
+    const char *end;
+
+    /* ### Would it be faster to call this once and do the offset ourselves? */
+    apr_mmap_offset((void**)data, ctx->mmap, ctx->offset);
+    end = *data;
+
+    /* XXX An overflow is generated if we pass &ctx->remaining to readline.
+     * Not real clear why.
+     */
+    *len = ctx->remaining;
+
+    serf_util_readline(&end, len, acceptable, found);
+
+    *len = end - *data;
+
+    ctx->offset += *len;
+    ctx->remaining -= *len;
+
+    if (ctx->remaining == 0) {
+        return APR_EOF;
+    }
+    return APR_SUCCESS;
+}
+
+static apr_status_t serf_mmap_peek(serf_bucket_t *bucket,
+                                     const char **data,
+                                     apr_size_t *len)
+{
+    /* Oh, bah. */
+    return APR_ENOTIMPL;
+}
+
+const serf_bucket_type_t serf_bucket_type_mmap = {
+    "MMAP",
+    serf_mmap_read,
+    serf_mmap_readline,
+    serf_default_read_iovec,
+    serf_default_read_for_sendfile,
+    serf_default_read_bucket,
+    serf_mmap_peek,
+    serf_default_destroy_and_data,
+};
+
+#else /* !APR_HAS_MMAP */
+
+serf_bucket_t *serf_bucket_mmap_create(apr_mmap_t *file_mmap,
+                                       serf_bucket_alloc_t *allocator)
+{
+    return NULL;
+}
+
+const serf_bucket_type_t serf_bucket_type_mmap = {
+    "MMAP",
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+};
+
+#endif

Deleted: vendor/serf/1.3.9/buckets/request_buckets.c
===================================================================
--- vendor/serf/dist/buckets/request_buckets.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/buckets/request_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,223 +0,0 @@
-/* Copyright 2002-2004 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_pools.h>
-#include <apr_strings.h>
-
-#include "serf.h"
-#include "serf_bucket_util.h"
-
-
-typedef struct {
-    const char *method;
-    const char *uri;
-    serf_bucket_t *headers;
-    serf_bucket_t *body;
-    apr_int64_t len;
-} request_context_t;
-
-#define LENGTH_UNKNOWN ((apr_int64_t)-1)
-
-
-serf_bucket_t *serf_bucket_request_create(
-    const char *method,
-    const char *URI,
-    serf_bucket_t *body,
-    serf_bucket_alloc_t *allocator)
-{
-    request_context_t *ctx;
-
-    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
-    ctx->method = method;
-    ctx->uri = URI;
-    ctx->headers = serf_bucket_headers_create(allocator);
-    ctx->body = body;
-    ctx->len = LENGTH_UNKNOWN;
-
-    return serf_bucket_create(&serf_bucket_type_request, allocator, ctx);
-}
-
-void serf_bucket_request_set_CL(
-    serf_bucket_t *bucket,
-    apr_int64_t len)
-{
-    request_context_t *ctx = (request_context_t *)bucket->data;
-
-    ctx->len = len;
-}
-
-serf_bucket_t *serf_bucket_request_get_headers(
-    serf_bucket_t *bucket)
-{
-    return ((request_context_t *)bucket->data)->headers;
-}
-
-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;
-    serf_bucket_t *new_bucket;
-    const char *new_data;
-    struct iovec iov[4];
-    apr_size_t nbytes;
-
-    /* Serialize the request-line and headers into one mother string,
-     * and wrap a bucket around it.
-     */
-    iov[0].iov_base = (char*)ctx->method;
-    iov[0].iov_len = strlen(ctx->method);
-    iov[1].iov_base = " ";
-    iov[1].iov_len = sizeof(" ") - 1;
-    iov[2].iov_base = (char*)ctx->uri;
-    iov[2].iov_len = strlen(ctx->uri);
-    iov[3].iov_base = " HTTP/1.1\r\n";
-    iov[3].iov_len = sizeof(" HTTP/1.1\r\n") - 1;
-
-    /* Create a new bucket for this string with a flat string.  */
-    new_data = serf_bstrcatv(bucket->allocator, iov, 4, &nbytes);
-    new_bucket = serf_bucket_simple_own_create(new_data, nbytes,
-                                               bucket->allocator);
-
-    /* Build up the new bucket structure.
-     *
-     * Note that self needs to become an aggregate bucket so that a
-     * pointer to self still represents the "right" data.
-     */
-    serf_bucket_aggregate_become(bucket);
-
-    /* Insert the two buckets. */
-    serf_bucket_aggregate_append(bucket, new_bucket);
-    serf_bucket_aggregate_append(bucket, ctx->headers);
-
-    /* If we know the length, then use C-L and the raw body. Otherwise,
-       use chunked encoding for the request.  */
-    if (ctx->len != LENGTH_UNKNOWN) {
-        char buf[30];
-        sprintf(buf, "%" APR_INT64_T_FMT, ctx->len);
-        serf_bucket_headers_set(ctx->headers, "Content-Length", buf);
-        if (ctx->body != NULL)
-            serf_bucket_aggregate_append(bucket, ctx->body);
-    }
-    else if (ctx->body != NULL) {
-        /* Morph the body bucket to a chunked encoding bucket for now. */
-        serf_bucket_headers_setn(ctx->headers, "Transfer-Encoding", "chunked");
-        ctx->body = serf_bucket_chunk_create(ctx->body, bucket->allocator);
-        serf_bucket_aggregate_append(bucket, ctx->body);
-    }
-
-    /* Our private context is no longer needed, and is not referred to by
-     * any existing bucket. Toss it.
-     */
-    serf_bucket_mem_free(bucket->allocator, ctx);
-}
-
-static apr_status_t serf_request_read(serf_bucket_t *bucket,
-                                      apr_size_t requested,
-                                      const char **data, apr_size_t *len)
-{
-    /* Seralize our private data into a new aggregate bucket. */
-    serialize_data(bucket);
-
-    /* Delegate to the "new" aggregate bucket to do the read. */
-    return serf_bucket_read(bucket, requested, data, len);
-}
-
-static apr_status_t serf_request_readline(serf_bucket_t *bucket,
-                                          int acceptable, int *found,
-                                          const char **data, apr_size_t *len)
-{
-    /* Seralize our private data into a new aggregate bucket. */
-    serialize_data(bucket);
-
-    /* Delegate to the "new" aggregate bucket to do the readline. */
-    return serf_bucket_readline(bucket, acceptable, found, data, len);
-}
-
-static apr_status_t serf_request_read_iovec(serf_bucket_t *bucket,
-                                            apr_size_t requested,
-                                            int vecs_size,
-                                            struct iovec *vecs,
-                                            int *vecs_used)
-{
-    /* Seralize our private data into a new aggregate bucket. */
-    serialize_data(bucket);
-
-    /* Delegate to the "new" aggregate bucket to do the read. */
-    return serf_bucket_read_iovec(bucket, requested,
-                                  vecs_size, vecs, vecs_used);
-}
-
-static apr_status_t serf_request_peek(serf_bucket_t *bucket,
-                                      const char **data,
-                                      apr_size_t *len)
-{
-    /* Seralize our private data into a new aggregate bucket. */
-    serialize_data(bucket);
-
-    /* Delegate to the "new" aggregate bucket to do the peek. */
-    return serf_bucket_peek(bucket, data, len);
-}
-
-void serf_bucket_request_become(
-    serf_bucket_t *bucket,
-    const char *method,
-    const char *uri,
-    serf_bucket_t *body)
-{
-    request_context_t *ctx;
-
-    ctx = serf_bucket_mem_alloc(bucket->allocator, sizeof(*ctx));
-    ctx->method = method;
-    ctx->uri = uri;
-    ctx->headers = serf_bucket_headers_create(bucket->allocator);
-    ctx->body = body;
-
-    bucket->type = &serf_bucket_type_request;
-    bucket->data = ctx;
-
-    /* The allocator remains the same. */
-}
-
-const serf_bucket_type_t serf_bucket_type_request = {
-    "REQUEST",
-    serf_request_read,
-    serf_request_readline,
-    serf_request_read_iovec,
-    serf_default_read_for_sendfile,
-    serf_default_read_bucket,
-    serf_request_peek,
-    serf_default_destroy_and_data,
-};
-

Copied: vendor/serf/1.3.9/buckets/request_buckets.c (from rev 9259, vendor/serf/dist/buckets/request_buckets.c)
===================================================================
--- vendor/serf/1.3.9/buckets/request_buckets.c	                        (rev 0)
+++ vendor/serf/1.3.9/buckets/request_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,242 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_pools.h>
+#include <apr_strings.h>
+
+#include "serf.h"
+#include "serf_bucket_util.h"
+
+
+typedef struct {
+    const char *method;
+    const char *uri;
+    serf_bucket_t *headers;
+    serf_bucket_t *body;
+    apr_int64_t len;
+} request_context_t;
+
+#define LENGTH_UNKNOWN ((apr_int64_t)-1)
+
+
+serf_bucket_t *serf_bucket_request_create(
+    const char *method,
+    const char *URI,
+    serf_bucket_t *body,
+    serf_bucket_alloc_t *allocator)
+{
+    request_context_t *ctx;
+
+    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
+    ctx->method = method;
+    ctx->uri = URI;
+    ctx->headers = serf_bucket_headers_create(allocator);
+    ctx->body = body;
+    ctx->len = LENGTH_UNKNOWN;
+
+    return serf_bucket_create(&serf_bucket_type_request, allocator, ctx);
+}
+
+void serf_bucket_request_set_CL(
+    serf_bucket_t *bucket,
+    apr_int64_t len)
+{
+    request_context_t *ctx = (request_context_t *)bucket->data;
+
+    ctx->len = len;
+}
+
+serf_bucket_t *serf_bucket_request_get_headers(
+    serf_bucket_t *bucket)
+{
+    return ((request_context_t *)bucket->data)->headers;
+}
+
+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;
+    serf_bucket_t *new_bucket;
+    const char *new_data;
+    struct iovec iov[4];
+    apr_size_t nbytes;
+
+    /* Serialize the request-line and headers into one mother string,
+     * and wrap a bucket around it.
+     */
+    iov[0].iov_base = (char*)ctx->method;
+    iov[0].iov_len = strlen(ctx->method);
+    iov[1].iov_base = " ";
+    iov[1].iov_len = sizeof(" ") - 1;
+    iov[2].iov_base = (char*)ctx->uri;
+    iov[2].iov_len = strlen(ctx->uri);
+    iov[3].iov_base = " HTTP/1.1\r\n";
+    iov[3].iov_len = sizeof(" HTTP/1.1\r\n") - 1;
+
+    /* Create a new bucket for this string with a flat string.  */
+    new_data = serf_bstrcatv(bucket->allocator, iov, 4, &nbytes);
+    new_bucket = serf_bucket_simple_own_create(new_data, nbytes,
+                                               bucket->allocator);
+
+    /* Build up the new bucket structure.
+     *
+     * Note that self needs to become an aggregate bucket so that a
+     * pointer to self still represents the "right" data.
+     */
+    serf_bucket_aggregate_become(bucket);
+
+    /* Insert the two buckets. */
+    serf_bucket_aggregate_append(bucket, new_bucket);
+    serf_bucket_aggregate_append(bucket, ctx->headers);
+
+    /* If we know the length, then use C-L and the raw body. Otherwise,
+       use chunked encoding for the request.  */
+    if (ctx->len != LENGTH_UNKNOWN) {
+        char buf[30];
+        sprintf(buf, "%" APR_INT64_T_FMT, ctx->len);
+        serf_bucket_headers_set(ctx->headers, "Content-Length", buf);
+        if (ctx->body != NULL)
+            serf_bucket_aggregate_append(bucket, ctx->body);
+    }
+    else if (ctx->body != NULL) {
+        /* Morph the body bucket to a chunked encoding bucket for now. */
+        serf_bucket_headers_setn(ctx->headers, "Transfer-Encoding", "chunked");
+        ctx->body = serf_bucket_chunk_create(ctx->body, bucket->allocator);
+        serf_bucket_aggregate_append(bucket, ctx->body);
+    }
+
+    /* Our private context is no longer needed, and is not referred to by
+     * any existing bucket. Toss it.
+     */
+    serf_bucket_mem_free(bucket->allocator, ctx);
+}
+
+static apr_status_t serf_request_read(serf_bucket_t *bucket,
+                                      apr_size_t requested,
+                                      const char **data, apr_size_t *len)
+{
+    /* Seralize our private data into a new aggregate bucket. */
+    serialize_data(bucket);
+
+    /* Delegate to the "new" aggregate bucket to do the read. */
+    return serf_bucket_read(bucket, requested, data, len);
+}
+
+static apr_status_t serf_request_readline(serf_bucket_t *bucket,
+                                          int acceptable, int *found,
+                                          const char **data, apr_size_t *len)
+{
+    /* Seralize our private data into a new aggregate bucket. */
+    serialize_data(bucket);
+
+    /* Delegate to the "new" aggregate bucket to do the readline. */
+    return serf_bucket_readline(bucket, acceptable, found, data, len);
+}
+
+static apr_status_t serf_request_read_iovec(serf_bucket_t *bucket,
+                                            apr_size_t requested,
+                                            int vecs_size,
+                                            struct iovec *vecs,
+                                            int *vecs_used)
+{
+    /* Seralize our private data into a new aggregate bucket. */
+    serialize_data(bucket);
+
+    /* Delegate to the "new" aggregate bucket to do the read. */
+    return serf_bucket_read_iovec(bucket, requested,
+                                  vecs_size, vecs, vecs_used);
+}
+
+static apr_status_t serf_request_peek(serf_bucket_t *bucket,
+                                      const char **data,
+                                      apr_size_t *len)
+{
+    /* Seralize our private data into a new aggregate bucket. */
+    serialize_data(bucket);
+
+    /* Delegate to the "new" aggregate bucket to do the peek. */
+    return serf_bucket_peek(bucket, data, len);
+}
+
+/* Note that this function is only called when serialize_data()
+   hasn't been called on the bucket */
+static void serf_request_destroy(serf_bucket_t *bucket)
+{
+  request_context_t *ctx = bucket->data;
+
+  serf_bucket_destroy(ctx->headers);
+
+  if (ctx->body)
+    serf_bucket_destroy(ctx->body);
+
+  serf_default_destroy_and_data(bucket);
+}
+
+void serf_bucket_request_become(
+    serf_bucket_t *bucket,
+    const char *method,
+    const char *uri,
+    serf_bucket_t *body)
+{
+    request_context_t *ctx;
+
+    ctx = serf_bucket_mem_alloc(bucket->allocator, sizeof(*ctx));
+    ctx->method = method;
+    ctx->uri = uri;
+    ctx->headers = serf_bucket_headers_create(bucket->allocator);
+    ctx->body = body;
+
+    bucket->type = &serf_bucket_type_request;
+    bucket->data = ctx;
+
+    /* The allocator remains the same. */
+}
+
+const serf_bucket_type_t serf_bucket_type_request = {
+    "REQUEST",
+    serf_request_read,
+    serf_request_readline,
+    serf_request_read_iovec,
+    serf_default_read_for_sendfile,
+    serf_default_read_bucket,
+    serf_request_peek,
+    serf_request_destroy,
+};
+

Deleted: vendor/serf/1.3.9/buckets/response_body_buckets.c
===================================================================
--- vendor/serf/dist/buckets/response_body_buckets.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/buckets/response_body_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,135 +0,0 @@
-/* Copyright 2002-2004 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_pools.h>
-
-#include "serf.h"
-#include "serf_bucket_util.h"
-
-/* Older versions of APR do not have this macro.  */
-#ifdef APR_SIZE_MAX
-#define REQUESTED_MAX APR_SIZE_MAX
-#else
-#define REQUESTED_MAX (~((apr_size_t)0))
-#endif
-
-
-typedef struct {
-    serf_bucket_t *stream;
-    apr_uint64_t remaining;
-} body_context_t;
-
-serf_bucket_t *serf_bucket_response_body_create(
-    serf_bucket_t *stream, apr_uint64_t len, serf_bucket_alloc_t *allocator)
-{
-    body_context_t *ctx;
-
-    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
-    ctx->stream = stream;
-    ctx->remaining = len;
-
-    return serf_bucket_create(&serf_bucket_type_response_body, allocator, ctx);
-}
-
-static apr_status_t serf_response_body_read(serf_bucket_t *bucket,
-                                            apr_size_t requested,
-                                            const char **data,
-                                            apr_size_t *len)
-{
-    body_context_t *ctx = bucket->data;
-    apr_status_t status;
-
-    if (!ctx->remaining) {
-        *len = 0;
-        return APR_EOF;
-    }
-
-    if (requested == SERF_READ_ALL_AVAIL || requested > ctx->remaining) {
-        if (ctx->remaining <= REQUESTED_MAX) {
-            requested = (apr_size_t) ctx->remaining;
-        } else {
-            requested = REQUESTED_MAX;
-        }
-    }
-
-    status = serf_bucket_read(ctx->stream, requested, data, len);
-
-    if (!SERF_BUCKET_READ_ERROR(status)) {
-        ctx->remaining -= *len;
-    }
-
-    if (APR_STATUS_IS_EOF(status) && ctx->remaining > 0) {
-        /* The server sent less data than expected. */
-        status = SERF_ERROR_TRUNCATED_HTTP_RESPONSE;
-    }
-
-    return status;
-}
-
-static apr_status_t serf_response_body_readline(serf_bucket_t *bucket,
-                                                int acceptable, int *found,
-                                                const char **data,
-                                                apr_size_t *len)
-{
-    body_context_t *ctx = bucket->data;
-    apr_status_t status;
-
-    if (!ctx->remaining) {
-        *len = 0;
-        return APR_EOF;
-    }
-
-    status = serf_bucket_readline(ctx->stream, acceptable, found, data, len);
-
-    if (!SERF_BUCKET_READ_ERROR(status)) {
-        ctx->remaining -= *len;
-    }
-
-    if (APR_STATUS_IS_EOF(status) && ctx->remaining > 0) {
-        /* The server sent less data than expected. */
-        status = SERF_ERROR_TRUNCATED_HTTP_RESPONSE;
-    }
-
-    return status;
-}
-
-static apr_status_t serf_response_body_peek(serf_bucket_t *bucket,
-                                            const char **data,
-                                            apr_size_t *len)
-{
-    body_context_t *ctx = bucket->data;
-
-    return serf_bucket_peek(ctx->stream, data, len);
-}
-
-static void serf_response_body_destroy(serf_bucket_t *bucket)
-{
-    body_context_t *ctx = bucket->data;
-
-    serf_bucket_destroy(ctx->stream);
-
-    serf_default_destroy_and_data(bucket);
-}
-
-const serf_bucket_type_t serf_bucket_type_response_body = {
-    "RESPONSE_BODY",
-    serf_response_body_read,
-    serf_response_body_readline,
-    serf_default_read_iovec,
-    serf_default_read_for_sendfile,
-    serf_default_read_bucket,
-    serf_response_body_peek,
-    serf_response_body_destroy,
-};

Copied: vendor/serf/1.3.9/buckets/response_body_buckets.c (from rev 9259, vendor/serf/dist/buckets/response_body_buckets.c)
===================================================================
--- vendor/serf/1.3.9/buckets/response_body_buckets.c	                        (rev 0)
+++ vendor/serf/1.3.9/buckets/response_body_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,140 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_pools.h>
+
+#include "serf.h"
+#include "serf_bucket_util.h"
+
+/* Older versions of APR do not have this macro.  */
+#ifdef APR_SIZE_MAX
+#define REQUESTED_MAX APR_SIZE_MAX
+#else
+#define REQUESTED_MAX (~((apr_size_t)0))
+#endif
+
+
+typedef struct {
+    serf_bucket_t *stream;
+    apr_uint64_t remaining;
+} body_context_t;
+
+serf_bucket_t *serf_bucket_response_body_create(
+    serf_bucket_t *stream, apr_uint64_t len, serf_bucket_alloc_t *allocator)
+{
+    body_context_t *ctx;
+
+    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
+    ctx->stream = stream;
+    ctx->remaining = len;
+
+    return serf_bucket_create(&serf_bucket_type_response_body, allocator, ctx);
+}
+
+static apr_status_t serf_response_body_read(serf_bucket_t *bucket,
+                                            apr_size_t requested,
+                                            const char **data,
+                                            apr_size_t *len)
+{
+    body_context_t *ctx = bucket->data;
+    apr_status_t status;
+
+    if (!ctx->remaining) {
+        *len = 0;
+        return APR_EOF;
+    }
+
+    if (requested == SERF_READ_ALL_AVAIL || requested > ctx->remaining) {
+        if (ctx->remaining <= REQUESTED_MAX) {
+            requested = (apr_size_t) ctx->remaining;
+        } else {
+            requested = REQUESTED_MAX;
+        }
+    }
+
+    status = serf_bucket_read(ctx->stream, requested, data, len);
+
+    if (!SERF_BUCKET_READ_ERROR(status)) {
+        ctx->remaining -= *len;
+    }
+
+    if (APR_STATUS_IS_EOF(status) && ctx->remaining > 0) {
+        /* The server sent less data than expected. */
+        status = SERF_ERROR_TRUNCATED_HTTP_RESPONSE;
+    }
+
+    return status;
+}
+
+static apr_status_t serf_response_body_readline(serf_bucket_t *bucket,
+                                                int acceptable, int *found,
+                                                const char **data,
+                                                apr_size_t *len)
+{
+    body_context_t *ctx = bucket->data;
+    apr_status_t status;
+
+    if (!ctx->remaining) {
+        *len = 0;
+        return APR_EOF;
+    }
+
+    status = serf_bucket_readline(ctx->stream, acceptable, found, data, len);
+
+    if (!SERF_BUCKET_READ_ERROR(status)) {
+        ctx->remaining -= *len;
+    }
+
+    if (APR_STATUS_IS_EOF(status) && ctx->remaining > 0) {
+        /* The server sent less data than expected. */
+        status = SERF_ERROR_TRUNCATED_HTTP_RESPONSE;
+    }
+
+    return status;
+}
+
+static apr_status_t serf_response_body_peek(serf_bucket_t *bucket,
+                                            const char **data,
+                                            apr_size_t *len)
+{
+    body_context_t *ctx = bucket->data;
+
+    return serf_bucket_peek(ctx->stream, data, len);
+}
+
+static void serf_response_body_destroy(serf_bucket_t *bucket)
+{
+    body_context_t *ctx = bucket->data;
+
+    serf_bucket_destroy(ctx->stream);
+
+    serf_default_destroy_and_data(bucket);
+}
+
+const serf_bucket_type_t serf_bucket_type_response_body = {
+    "RESPONSE_BODY",
+    serf_response_body_read,
+    serf_response_body_readline,
+    serf_default_read_iovec,
+    serf_default_read_for_sendfile,
+    serf_default_read_bucket,
+    serf_response_body_peek,
+    serf_response_body_destroy,
+};

Deleted: vendor/serf/1.3.9/buckets/response_buckets.c
===================================================================
--- vendor/serf/dist/buckets/response_buckets.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/buckets/response_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,488 +0,0 @@
-/* Copyright 2002-2004 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_lib.h>
-#include <apr_strings.h>
-#include <apr_date.h>
-
-#include "serf.h"
-#include "serf_bucket_util.h"
-#include "serf_private.h"
-
-typedef struct {
-    serf_bucket_t *stream;
-    serf_bucket_t *body;        /* Pointer to the stream wrapping the body. */
-    serf_bucket_t *headers;     /* holds parsed headers */
-
-    enum {
-        STATE_STATUS_LINE,      /* reading status line */
-        STATE_HEADERS,          /* reading headers */
-        STATE_BODY,             /* reading body */
-        STATE_TRAILERS,         /* reading trailers */
-        STATE_DONE              /* we've sent EOF */
-    } state;
-
-    /* Buffer for accumulating a line from the response. */
-    serf_linebuf_t linebuf;
-
-    serf_status_line sl;
-
-    int chunked;                /* Do we need to read trailers? */
-    int head_req;               /* Was this a HEAD request? */
-} response_context_t;
-
-/* Returns 1 if according to RFC2626 this response can have a body, 0 if it
-   must not have a body. */
-static int expect_body(response_context_t *ctx)
-{
-    if (ctx->head_req)
-        return 0;
-
-    /* 100 Continue and 101 Switching Protocols */
-    if (ctx->sl.code >= 100 && ctx->sl.code < 200)
-        return 0;
-
-    /* 204 No Content */
-    if (ctx->sl.code == 204)
-        return 0;
-
-    /* 205? */
-
-    /* 304 Not Modified */
-    if (ctx->sl.code == 304)
-        return 0;
-
-    return 1;
-}
-
-serf_bucket_t *serf_bucket_response_create(
-    serf_bucket_t *stream,
-    serf_bucket_alloc_t *allocator)
-{
-    response_context_t *ctx;
-
-    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
-    ctx->stream = stream;
-    ctx->body = NULL;
-    ctx->headers = serf_bucket_headers_create(allocator);
-    ctx->state = STATE_STATUS_LINE;
-    ctx->chunked = 0;
-    ctx->head_req = 0;
-
-    serf_linebuf_init(&ctx->linebuf);
-
-    return serf_bucket_create(&serf_bucket_type_response, allocator, ctx);
-}
-
-void serf_bucket_response_set_head(
-    serf_bucket_t *bucket)
-{
-    response_context_t *ctx = bucket->data;
-
-    ctx->head_req = 1;
-}
-
-serf_bucket_t *serf_bucket_response_get_headers(
-    serf_bucket_t *bucket)
-{
-    return ((response_context_t *)bucket->data)->headers;
-}
-
-
-static void serf_response_destroy_and_data(serf_bucket_t *bucket)
-{
-    response_context_t *ctx = bucket->data;
-
-    if (ctx->state != STATE_STATUS_LINE) {
-        serf_bucket_mem_free(bucket->allocator, (void*)ctx->sl.reason);
-    }
-
-    serf_bucket_destroy(ctx->stream);
-    if (ctx->body != NULL)
-        serf_bucket_destroy(ctx->body);
-    serf_bucket_destroy(ctx->headers);
-
-    serf_default_destroy_and_data(bucket);
-}
-
-static apr_status_t fetch_line(response_context_t *ctx, int acceptable)
-{
-    return serf_linebuf_fetch(&ctx->linebuf, ctx->stream, acceptable);
-}
-
-static apr_status_t parse_status_line(response_context_t *ctx,
-                                      serf_bucket_alloc_t *allocator)
-{
-    int res;
-    char *reason; /* ### stupid APR interface makes this non-const */
-
-    /* ctx->linebuf.line should be of form: HTTP/1.1 200 OK */
-    res = apr_date_checkmask(ctx->linebuf.line, "HTTP/#.# ###*");
-    if (!res) {
-        /* Not an HTTP response?  Well, at least we won't understand it. */
-        return SERF_ERROR_BAD_HTTP_RESPONSE;
-    }
-
-    ctx->sl.version = SERF_HTTP_VERSION(ctx->linebuf.line[5] - '0',
-                                        ctx->linebuf.line[7] - '0');
-    ctx->sl.code = apr_strtoi64(ctx->linebuf.line + 8, &reason, 10);
-
-    /* Skip leading spaces for the reason string. */
-    if (apr_isspace(*reason)) {
-        reason++;
-    }
-
-    /* Copy the reason value out of the line buffer. */
-    ctx->sl.reason = serf_bstrmemdup(allocator, reason,
-                                     ctx->linebuf.used
-                                     - (reason - ctx->linebuf.line));
-
-    return APR_SUCCESS;
-}
-
-/* This code should be replaced with header buckets. */
-static apr_status_t fetch_headers(serf_bucket_t *bkt, response_context_t *ctx)
-{
-    apr_status_t status;
-
-    /* RFC 2616 says that CRLF is the only line ending, but we can easily
-     * accept any kind of line ending.
-     */
-    status = fetch_line(ctx, SERF_NEWLINE_ANY);
-    if (SERF_BUCKET_READ_ERROR(status)) {
-        return status;
-    }
-    /* Something was read. Process it. */
-
-    if (ctx->linebuf.state == SERF_LINEBUF_READY && ctx->linebuf.used) {
-        const char *end_key;
-        const char *c;
-
-        end_key = c = memchr(ctx->linebuf.line, ':', ctx->linebuf.used);
-        if (!c) {
-            /* Bad headers? */
-            return SERF_ERROR_BAD_HTTP_RESPONSE;
-        }
-
-        /* Skip over initial ':' */
-        c++;
-
-        /* And skip all whitespaces. */
-        for(; c < ctx->linebuf.line + ctx->linebuf.used; c++)
-        {
-            if (!apr_isspace(*c))
-            {
-              break;
-            }
-        }
-
-        /* Always copy the headers (from the linebuf into new mem). */
-        /* ### we should be able to optimize some mem copies */
-        serf_bucket_headers_setx(
-            ctx->headers,
-            ctx->linebuf.line, end_key - ctx->linebuf.line, 1,
-            c, ctx->linebuf.line + ctx->linebuf.used - c, 1);
-    }
-
-    return status;
-}
-
-/* Perform one iteration of the state machine.
- *
- * Will return when one the following conditions occurred:
- *  1) a state change
- *  2) an error
- *  3) the stream is not ready or at EOF
- *  4) APR_SUCCESS, meaning the machine can be run again immediately
- */
-static apr_status_t run_machine(serf_bucket_t *bkt, response_context_t *ctx)
-{
-    apr_status_t status = APR_SUCCESS; /* initialize to avoid gcc warnings */
-
-    switch (ctx->state) {
-    case STATE_STATUS_LINE:
-        /* RFC 2616 says that CRLF is the only line ending, but we can easily
-         * accept any kind of line ending.
-         */
-        status = fetch_line(ctx, SERF_NEWLINE_ANY);
-        if (SERF_BUCKET_READ_ERROR(status))
-            return status;
-
-        if (ctx->linebuf.state == SERF_LINEBUF_READY) {
-            /* The Status-Line is in the line buffer. Process it. */
-            status = parse_status_line(ctx, bkt->allocator);
-            if (status)
-                return status;
-
-            /* Good times ahead: we're switching protocols! */
-            if (ctx->sl.code == 101) {
-                ctx->body =
-                    serf_bucket_barrier_create(ctx->stream, bkt->allocator);
-                ctx->state = STATE_DONE;
-                break;
-            }
-
-            /* Okay... move on to reading the headers. */
-            ctx->state = STATE_HEADERS;
-        }
-        else {
-            /* The connection closed before we could get the next
-             * response.  Treat the request as lost so that our upper
-             * end knows the server never tried to give us a response.
-             */
-            if (APR_STATUS_IS_EOF(status)) {
-                return SERF_ERROR_REQUEST_LOST;
-            }
-        }
-        break;
-    case STATE_HEADERS:
-        status = fetch_headers(bkt, ctx);
-        if (SERF_BUCKET_READ_ERROR(status))
-            return status;
-
-        /* If an empty line was read, then we hit the end of the headers.
-         * Move on to the body.
-         */
-        if (ctx->linebuf.state == SERF_LINEBUF_READY && !ctx->linebuf.used) {
-            const void *v;
-
-            /* Advance the state. */
-            ctx->state = STATE_BODY;
-
-            /* If this is a response to a HEAD request, or code == 1xx,204 or304
-               then we don't receive a real body. */
-            if (!expect_body(ctx)) {
-                ctx->body = serf_bucket_simple_create(NULL, 0, NULL, NULL,
-                                                      bkt->allocator);
-                ctx->state = STATE_BODY;
-                break;
-            }
-
-            ctx->body =
-                serf_bucket_barrier_create(ctx->stream, bkt->allocator);
-
-            /* Are we C-L, chunked, or conn close? */
-            v = serf_bucket_headers_get(ctx->headers, "Content-Length");
-            if (v) {
-                apr_uint64_t length;
-                length = apr_strtoi64(v, NULL, 10);
-                if (errno == ERANGE) {
-                    return APR_FROM_OS_ERROR(ERANGE);
-                }
-                ctx->body = serf_bucket_response_body_create(
-                              ctx->body, length, bkt->allocator);
-            }
-            else {
-                v = serf_bucket_headers_get(ctx->headers, "Transfer-Encoding");
-
-                /* Need to handle multiple transfer-encoding. */
-                if (v && strcasecmp("chunked", v) == 0) {
-                    ctx->chunked = 1;
-                    ctx->body = serf_bucket_dechunk_create(ctx->body,
-                                                           bkt->allocator);
-                }
-            }
-            v = serf_bucket_headers_get(ctx->headers, "Content-Encoding");
-            if (v) {
-                /* Need to handle multiple content-encoding. */
-                if (v && strcasecmp("gzip", v) == 0) {
-                    ctx->body =
-                        serf_bucket_deflate_create(ctx->body, bkt->allocator,
-                                                   SERF_DEFLATE_GZIP);
-                }
-                else if (v && strcasecmp("deflate", v) == 0) {
-                    ctx->body =
-                        serf_bucket_deflate_create(ctx->body, bkt->allocator,
-                                                   SERF_DEFLATE_DEFLATE);
-                }
-            }
-        }
-        break;
-    case STATE_BODY:
-        /* Don't do anything. */
-        break;
-    case STATE_TRAILERS:
-        status = fetch_headers(bkt, ctx);
-        if (SERF_BUCKET_READ_ERROR(status))
-            return status;
-
-        /* If an empty line was read, then we're done. */
-        if (ctx->linebuf.state == SERF_LINEBUF_READY && !ctx->linebuf.used) {
-            ctx->state = STATE_DONE;
-            return APR_EOF;
-        }
-        break;
-    case STATE_DONE:
-        return APR_EOF;
-    default:
-        /* Not reachable */
-        return APR_EGENERAL;
-    }
-
-    return status;
-}
-
-static apr_status_t wait_for_body(serf_bucket_t *bkt, response_context_t *ctx)
-{
-    apr_status_t status;
-
-    /* Keep reading and moving through states if we aren't at the BODY */
-    while (ctx->state != STATE_BODY) {
-        status = run_machine(bkt, ctx);
-
-        /* Anything other than APR_SUCCESS means that we cannot immediately
-         * read again (for now).
-         */
-        if (status)
-            return status;
-    }
-    /* in STATE_BODY */
-
-    return APR_SUCCESS;
-}
-
-apr_status_t serf_bucket_response_wait_for_headers(
-    serf_bucket_t *bucket)
-{
-    response_context_t *ctx = bucket->data;
-
-    return wait_for_body(bucket, ctx);
-}
-
-apr_status_t serf_bucket_response_status(
-    serf_bucket_t *bkt,
-    serf_status_line *sline)
-{
-    response_context_t *ctx = bkt->data;
-    apr_status_t status;
-
-    if (ctx->state != STATE_STATUS_LINE) {
-        /* We already read it and moved on. Just return it. */
-        *sline = ctx->sl;
-        return APR_SUCCESS;
-    }
-
-    /* Running the state machine once will advance the machine, or state
-     * that the stream isn't ready with enough data. There isn't ever a
-     * need to run the machine more than once to try and satisfy this. We
-     * have to look at the state to tell whether it advanced, though, as
-     * it is quite possible to advance *and* to return APR_EAGAIN.
-     */
-    status = run_machine(bkt, ctx);
-    if (ctx->state == STATE_HEADERS) {
-        *sline = ctx->sl;
-    }
-    else {
-        /* Indicate that we don't have the information yet. */
-        sline->version = 0;
-    }
-
-    return status;
-}
-
-static apr_status_t serf_response_read(serf_bucket_t *bucket,
-                                       apr_size_t requested,
-                                       const char **data, apr_size_t *len)
-{
-    response_context_t *ctx = bucket->data;
-    apr_status_t rv;
-
-    rv = wait_for_body(bucket, ctx);
-    if (rv) {
-        /* It's not possible to have read anything yet! */
-        if (APR_STATUS_IS_EOF(rv) || APR_STATUS_IS_EAGAIN(rv)) {
-            *len = 0;
-        }
-        return rv;
-    }
-
-    rv = serf_bucket_read(ctx->body, requested, data, len);
-    if (SERF_BUCKET_READ_ERROR(rv))
-        return rv;
-
-    if (APR_STATUS_IS_EOF(rv)) {
-        if (ctx->chunked) {
-            ctx->state = STATE_TRAILERS;
-            /* Mask the result. */
-            rv = APR_SUCCESS;
-        } else {
-            ctx->state = STATE_DONE;
-        }
-    }
-    return rv;
-}
-
-static apr_status_t serf_response_readline(serf_bucket_t *bucket,
-                                           int acceptable, int *found,
-                                           const char **data, apr_size_t *len)
-{
-    response_context_t *ctx = bucket->data;
-    apr_status_t rv;
-
-    rv = wait_for_body(bucket, ctx);
-    if (rv) {
-        return rv;
-    }
-
-    /* Delegate to the stream bucket to do the readline. */
-    return serf_bucket_readline(ctx->body, acceptable, found, data, len);
-}
-
-apr_status_t serf_response_full_become_aggregate(serf_bucket_t *bucket)
-{
-    response_context_t *ctx = bucket->data;
-    serf_bucket_t *bkt;
-    char buf[256];
-    int size;
-
-    serf_bucket_aggregate_become(bucket);
-
-    /* Add reconstructed status line. */
-    size = apr_snprintf(buf, 256, "HTTP/%d.%d %d ",
-                        SERF_HTTP_VERSION_MAJOR(ctx->sl.version),
-                        SERF_HTTP_VERSION_MINOR(ctx->sl.version),
-                        ctx->sl.code);
-    bkt = serf_bucket_simple_copy_create(buf, size,
-                                         bucket->allocator);
-    serf_bucket_aggregate_append(bucket, bkt);
-    bkt = serf_bucket_simple_copy_create(ctx->sl.reason, strlen(ctx->sl.reason),
-                                         bucket->allocator);
-    serf_bucket_aggregate_append(bucket, bkt);
-    bkt = SERF_BUCKET_SIMPLE_STRING_LEN("\r\n", 2,
-                                        bucket->allocator);
-    serf_bucket_aggregate_append(bucket, bkt);
-
-    /* Add headers and stream buckets in order. */
-    serf_bucket_aggregate_append(bucket, ctx->headers);
-    serf_bucket_aggregate_append(bucket, ctx->stream);
-
-    serf_bucket_mem_free(bucket->allocator, ctx);
-
-    return APR_SUCCESS;
-}
-
-/* ### need to implement */
-#define serf_response_peek NULL
-
-const serf_bucket_type_t serf_bucket_type_response = {
-    "RESPONSE",
-    serf_response_read,
-    serf_response_readline,
-    serf_default_read_iovec,
-    serf_default_read_for_sendfile,
-    serf_default_read_bucket,
-    serf_response_peek,
-    serf_response_destroy_and_data,
-};

Copied: vendor/serf/1.3.9/buckets/response_buckets.c (from rev 9259, vendor/serf/dist/buckets/response_buckets.c)
===================================================================
--- vendor/serf/1.3.9/buckets/response_buckets.c	                        (rev 0)
+++ vendor/serf/1.3.9/buckets/response_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,503 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_lib.h>
+#include <apr_strings.h>
+#include <apr_date.h>
+
+#include "serf.h"
+#include "serf_bucket_util.h"
+#include "serf_private.h"
+
+typedef struct {
+    serf_bucket_t *stream;
+    serf_bucket_t *body;        /* Pointer to the stream wrapping the body. */
+    serf_bucket_t *headers;     /* holds parsed headers */
+
+    enum {
+        STATE_STATUS_LINE,      /* reading status line */
+        STATE_HEADERS,          /* reading headers */
+        STATE_BODY,             /* reading body */
+        STATE_TRAILERS,         /* reading trailers */
+        STATE_DONE              /* we've sent EOF */
+    } state;
+
+    /* Buffer for accumulating a line from the response. */
+    serf_linebuf_t linebuf;
+
+    serf_status_line sl;
+
+    int chunked;                /* Do we need to read trailers? */
+    int head_req;               /* Was this a HEAD request? */
+} response_context_t;
+
+/* Returns 1 if according to RFC2626 this response can have a body, 0 if it
+   must not have a body. */
+static int expect_body(response_context_t *ctx)
+{
+    if (ctx->head_req)
+        return 0;
+
+    /* 100 Continue and 101 Switching Protocols */
+    if (ctx->sl.code >= 100 && ctx->sl.code < 200)
+        return 0;
+
+    /* 204 No Content */
+    if (ctx->sl.code == 204)
+        return 0;
+
+    /* 205? */
+
+    /* 304 Not Modified */
+    if (ctx->sl.code == 304)
+        return 0;
+
+    return 1;
+}
+
+serf_bucket_t *serf_bucket_response_create(
+    serf_bucket_t *stream,
+    serf_bucket_alloc_t *allocator)
+{
+    response_context_t *ctx;
+
+    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
+    ctx->stream = stream;
+    ctx->body = NULL;
+    ctx->headers = serf_bucket_headers_create(allocator);
+    ctx->state = STATE_STATUS_LINE;
+    ctx->chunked = 0;
+    ctx->head_req = 0;
+
+    serf_linebuf_init(&ctx->linebuf);
+
+    return serf_bucket_create(&serf_bucket_type_response, allocator, ctx);
+}
+
+void serf_bucket_response_set_head(
+    serf_bucket_t *bucket)
+{
+    response_context_t *ctx = bucket->data;
+
+    ctx->head_req = 1;
+}
+
+serf_bucket_t *serf_bucket_response_get_headers(
+    serf_bucket_t *bucket)
+{
+    return ((response_context_t *)bucket->data)->headers;
+}
+
+
+static void serf_response_destroy_and_data(serf_bucket_t *bucket)
+{
+    response_context_t *ctx = bucket->data;
+
+    if (ctx->state != STATE_STATUS_LINE) {
+        serf_bucket_mem_free(bucket->allocator, (void*)ctx->sl.reason);
+    }
+
+    serf_bucket_destroy(ctx->stream);
+    if (ctx->body != NULL)
+        serf_bucket_destroy(ctx->body);
+    serf_bucket_destroy(ctx->headers);
+
+    serf_default_destroy_and_data(bucket);
+}
+
+static apr_status_t fetch_line(response_context_t *ctx, int acceptable)
+{
+    return serf_linebuf_fetch(&ctx->linebuf, ctx->stream, acceptable);
+}
+
+static apr_status_t parse_status_line(response_context_t *ctx,
+                                      serf_bucket_alloc_t *allocator)
+{
+    int res;
+    char *reason; /* ### stupid APR interface makes this non-const */
+
+    /* Ensure a valid length, to avoid overflow on the final '\0' */
+    if (ctx->linebuf.used >= SERF_LINEBUF_LIMIT) {
+       return SERF_ERROR_BAD_HTTP_RESPONSE;
+    }
+
+    /* apr_date_checkmask assumes its arguments are valid C strings */
+    ctx->linebuf.line[ctx->linebuf.used] = '\0';
+
+    /* ctx->linebuf.line should be of form: 'HTTP/1.1 200 OK',
+       but we also explicitly allow the forms 'HTTP/1.1 200' (no reason)
+       and 'HTTP/1.1 401.1 Logon failed' (iis extended error codes) */
+    res = apr_date_checkmask(ctx->linebuf.line, "HTTP/#.# ###*");
+    if (!res) {
+        /* Not an HTTP response?  Well, at least we won't understand it. */
+        return SERF_ERROR_BAD_HTTP_RESPONSE;
+    }
+
+    ctx->sl.version = SERF_HTTP_VERSION(ctx->linebuf.line[5] - '0',
+                                        ctx->linebuf.line[7] - '0');
+    ctx->sl.code = apr_strtoi64(ctx->linebuf.line + 8, &reason, 10);
+
+    /* Skip leading spaces for the reason string. */
+    if (apr_isspace(*reason)) {
+        reason++;
+    }
+
+    /* Copy the reason value out of the line buffer. */
+    ctx->sl.reason = serf_bstrmemdup(allocator, reason,
+                                     ctx->linebuf.used
+                                     - (reason - ctx->linebuf.line));
+
+    return APR_SUCCESS;
+}
+
+/* This code should be replaced with header buckets. */
+static apr_status_t fetch_headers(serf_bucket_t *bkt, response_context_t *ctx)
+{
+    apr_status_t status;
+
+    /* RFC 2616 says that CRLF is the only line ending, but we can easily
+     * accept any kind of line ending.
+     */
+    status = fetch_line(ctx, SERF_NEWLINE_ANY);
+    if (SERF_BUCKET_READ_ERROR(status)) {
+        return status;
+    }
+    /* Something was read. Process it. */
+
+    if (ctx->linebuf.state == SERF_LINEBUF_READY && ctx->linebuf.used) {
+        const char *end_key;
+        const char *c;
+
+        end_key = c = memchr(ctx->linebuf.line, ':', ctx->linebuf.used);
+        if (!c) {
+            /* Bad headers? */
+            return SERF_ERROR_BAD_HTTP_RESPONSE;
+        }
+
+        /* Skip over initial ':' */
+        c++;
+
+        /* And skip all whitespaces. */
+        for(; c < ctx->linebuf.line + ctx->linebuf.used; c++)
+        {
+            if (!apr_isspace(*c))
+            {
+              break;
+            }
+        }
+
+        /* Always copy the headers (from the linebuf into new mem). */
+        /* ### we should be able to optimize some mem copies */
+        serf_bucket_headers_setx(
+            ctx->headers,
+            ctx->linebuf.line, end_key - ctx->linebuf.line, 1,
+            c, ctx->linebuf.line + ctx->linebuf.used - c, 1);
+    }
+
+    return status;
+}
+
+/* Perform one iteration of the state machine.
+ *
+ * Will return when one the following conditions occurred:
+ *  1) a state change
+ *  2) an error
+ *  3) the stream is not ready or at EOF
+ *  4) APR_SUCCESS, meaning the machine can be run again immediately
+ */
+static apr_status_t run_machine(serf_bucket_t *bkt, response_context_t *ctx)
+{
+    apr_status_t status = APR_SUCCESS; /* initialize to avoid gcc warnings */
+
+    switch (ctx->state) {
+    case STATE_STATUS_LINE:
+        /* RFC 2616 says that CRLF is the only line ending, but we can easily
+         * accept any kind of line ending.
+         */
+        status = fetch_line(ctx, SERF_NEWLINE_ANY);
+        if (SERF_BUCKET_READ_ERROR(status))
+            return status;
+
+        if (ctx->linebuf.state == SERF_LINEBUF_READY) {
+            /* The Status-Line is in the line buffer. Process it. */
+            status = parse_status_line(ctx, bkt->allocator);
+            if (status)
+                return status;
+
+            /* Good times ahead: we're switching protocols! */
+            if (ctx->sl.code == 101) {
+                ctx->body =
+                    serf_bucket_barrier_create(ctx->stream, bkt->allocator);
+                ctx->state = STATE_DONE;
+                break;
+            }
+
+            /* Okay... move on to reading the headers. */
+            ctx->state = STATE_HEADERS;
+        }
+        else {
+            /* The connection closed before we could get the next
+             * response.  Treat the request as lost so that our upper
+             * end knows the server never tried to give us a response.
+             */
+            if (APR_STATUS_IS_EOF(status)) {
+                return SERF_ERROR_REQUEST_LOST;
+            }
+        }
+        break;
+    case STATE_HEADERS:
+        status = fetch_headers(bkt, ctx);
+        if (SERF_BUCKET_READ_ERROR(status))
+            return status;
+
+        /* If an empty line was read, then we hit the end of the headers.
+         * Move on to the body.
+         */
+        if (ctx->linebuf.state == SERF_LINEBUF_READY && !ctx->linebuf.used) {
+            const void *v;
+
+            /* Advance the state. */
+            ctx->state = STATE_BODY;
+
+            /* If this is a response to a HEAD request, or code == 1xx,204 or304
+               then we don't receive a real body. */
+            if (!expect_body(ctx)) {
+                ctx->body = serf_bucket_simple_create(NULL, 0, NULL, NULL,
+                                                      bkt->allocator);
+                ctx->state = STATE_BODY;
+                break;
+            }
+
+            ctx->body =
+                serf_bucket_barrier_create(ctx->stream, bkt->allocator);
+
+            /* Are we C-L, chunked, or conn close? */
+            v = serf_bucket_headers_get(ctx->headers, "Content-Length");
+            if (v) {
+                apr_uint64_t length;
+                length = apr_strtoi64(v, NULL, 10);
+                if (errno == ERANGE) {
+                    return APR_FROM_OS_ERROR(ERANGE);
+                }
+                ctx->body = serf_bucket_response_body_create(
+                              ctx->body, length, bkt->allocator);
+            }
+            else {
+                v = serf_bucket_headers_get(ctx->headers, "Transfer-Encoding");
+
+                /* Need to handle multiple transfer-encoding. */
+                if (v && strcasecmp("chunked", v) == 0) {
+                    ctx->chunked = 1;
+                    ctx->body = serf_bucket_dechunk_create(ctx->body,
+                                                           bkt->allocator);
+                }
+            }
+            v = serf_bucket_headers_get(ctx->headers, "Content-Encoding");
+            if (v) {
+                /* Need to handle multiple content-encoding. */
+                if (v && strcasecmp("gzip", v) == 0) {
+                    ctx->body =
+                        serf_bucket_deflate_create(ctx->body, bkt->allocator,
+                                                   SERF_DEFLATE_GZIP);
+                }
+                else if (v && strcasecmp("deflate", v) == 0) {
+                    ctx->body =
+                        serf_bucket_deflate_create(ctx->body, bkt->allocator,
+                                                   SERF_DEFLATE_DEFLATE);
+                }
+            }
+        }
+        break;
+    case STATE_BODY:
+        /* Don't do anything. */
+        break;
+    case STATE_TRAILERS:
+        status = fetch_headers(bkt, ctx);
+        if (SERF_BUCKET_READ_ERROR(status))
+            return status;
+
+        /* If an empty line was read, then we're done. */
+        if (ctx->linebuf.state == SERF_LINEBUF_READY && !ctx->linebuf.used) {
+            ctx->state = STATE_DONE;
+            return APR_EOF;
+        }
+        break;
+    case STATE_DONE:
+        return APR_EOF;
+    default:
+        /* Not reachable */
+        return APR_EGENERAL;
+    }
+
+    return status;
+}
+
+static apr_status_t wait_for_body(serf_bucket_t *bkt, response_context_t *ctx)
+{
+    apr_status_t status;
+
+    /* Keep reading and moving through states if we aren't at the BODY */
+    while (ctx->state != STATE_BODY) {
+        status = run_machine(bkt, ctx);
+
+        /* Anything other than APR_SUCCESS means that we cannot immediately
+         * read again (for now).
+         */
+        if (status)
+            return status;
+    }
+    /* in STATE_BODY */
+
+    return APR_SUCCESS;
+}
+
+apr_status_t serf_bucket_response_wait_for_headers(
+    serf_bucket_t *bucket)
+{
+    response_context_t *ctx = bucket->data;
+
+    return wait_for_body(bucket, ctx);
+}
+
+apr_status_t serf_bucket_response_status(
+    serf_bucket_t *bkt,
+    serf_status_line *sline)
+{
+    response_context_t *ctx = bkt->data;
+    apr_status_t status;
+
+    if (ctx->state != STATE_STATUS_LINE) {
+        /* We already read it and moved on. Just return it. */
+        *sline = ctx->sl;
+        return APR_SUCCESS;
+    }
+
+    /* Running the state machine once will advance the machine, or state
+     * that the stream isn't ready with enough data. There isn't ever a
+     * need to run the machine more than once to try and satisfy this. We
+     * have to look at the state to tell whether it advanced, though, as
+     * it is quite possible to advance *and* to return APR_EAGAIN.
+     */
+    status = run_machine(bkt, ctx);
+    if (ctx->state == STATE_HEADERS) {
+        *sline = ctx->sl;
+    }
+    else {
+        /* Indicate that we don't have the information yet. */
+        sline->version = 0;
+    }
+
+    return status;
+}
+
+static apr_status_t serf_response_read(serf_bucket_t *bucket,
+                                       apr_size_t requested,
+                                       const char **data, apr_size_t *len)
+{
+    response_context_t *ctx = bucket->data;
+    apr_status_t rv;
+
+    rv = wait_for_body(bucket, ctx);
+    if (rv) {
+        /* It's not possible to have read anything yet! */
+        if (APR_STATUS_IS_EOF(rv) || APR_STATUS_IS_EAGAIN(rv)) {
+            *len = 0;
+        }
+        return rv;
+    }
+
+    rv = serf_bucket_read(ctx->body, requested, data, len);
+    if (SERF_BUCKET_READ_ERROR(rv))
+        return rv;
+
+    if (APR_STATUS_IS_EOF(rv)) {
+        if (ctx->chunked) {
+            ctx->state = STATE_TRAILERS;
+            /* Mask the result. */
+            rv = APR_SUCCESS;
+        } else {
+            ctx->state = STATE_DONE;
+        }
+    }
+    return rv;
+}
+
+static apr_status_t serf_response_readline(serf_bucket_t *bucket,
+                                           int acceptable, int *found,
+                                           const char **data, apr_size_t *len)
+{
+    response_context_t *ctx = bucket->data;
+    apr_status_t rv;
+
+    rv = wait_for_body(bucket, ctx);
+    if (rv) {
+        return rv;
+    }
+
+    /* Delegate to the stream bucket to do the readline. */
+    return serf_bucket_readline(ctx->body, acceptable, found, data, len);
+}
+
+apr_status_t serf_response_full_become_aggregate(serf_bucket_t *bucket)
+{
+    response_context_t *ctx = bucket->data;
+    serf_bucket_t *bkt;
+    char buf[256];
+    int size;
+
+    serf_bucket_aggregate_become(bucket);
+
+    /* Add reconstructed status line. */
+    size = apr_snprintf(buf, 256, "HTTP/%d.%d %d ",
+                        SERF_HTTP_VERSION_MAJOR(ctx->sl.version),
+                        SERF_HTTP_VERSION_MINOR(ctx->sl.version),
+                        ctx->sl.code);
+    bkt = serf_bucket_simple_copy_create(buf, size,
+                                         bucket->allocator);
+    serf_bucket_aggregate_append(bucket, bkt);
+    bkt = serf_bucket_simple_copy_create(ctx->sl.reason, strlen(ctx->sl.reason),
+                                         bucket->allocator);
+    serf_bucket_aggregate_append(bucket, bkt);
+    bkt = SERF_BUCKET_SIMPLE_STRING_LEN("\r\n", 2,
+                                        bucket->allocator);
+    serf_bucket_aggregate_append(bucket, bkt);
+
+    /* Add headers and stream buckets in order. */
+    serf_bucket_aggregate_append(bucket, ctx->headers);
+    serf_bucket_aggregate_append(bucket, ctx->stream);
+
+    serf_bucket_mem_free(bucket->allocator, ctx);
+
+    return APR_SUCCESS;
+}
+
+/* ### need to implement */
+#define serf_response_peek NULL
+
+const serf_bucket_type_t serf_bucket_type_response = {
+    "RESPONSE",
+    serf_response_read,
+    serf_response_readline,
+    serf_default_read_iovec,
+    serf_default_read_for_sendfile,
+    serf_default_read_bucket,
+    serf_response_peek,
+    serf_response_destroy_and_data,
+};

Deleted: vendor/serf/1.3.9/buckets/simple_buckets.c
===================================================================
--- vendor/serf/dist/buckets/simple_buckets.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/buckets/simple_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,159 +0,0 @@
-/* Copyright 2002-2004 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_pools.h>
-
-#include "serf.h"
-#include "serf_bucket_util.h"
-
-
-typedef struct {
-    const char *original;
-    const char *current;
-    apr_size_t remaining;
-
-    serf_simple_freefunc_t freefunc;
-    void *baton;
-
-} simple_context_t;
-
-
-static void free_copied_data(void *baton, const char *data)
-{
-    serf_bucket_mem_free(baton, (char*)data);
-}
-
-serf_bucket_t *serf_bucket_simple_create(
-    const char *data,
-    apr_size_t len,
-    serf_simple_freefunc_t freefunc,
-    void *freefunc_baton,
-    serf_bucket_alloc_t *allocator)
-{
-    simple_context_t *ctx;
-
-    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
-    ctx->original = ctx->current = data;
-    ctx->remaining = len;
-    ctx->freefunc = freefunc;
-    ctx->baton = freefunc_baton;
-
-    return serf_bucket_create(&serf_bucket_type_simple, allocator, ctx);
-}
-
-serf_bucket_t *serf_bucket_simple_copy_create(
-    const char *data, apr_size_t len,
-    serf_bucket_alloc_t *allocator)
-{
-    simple_context_t *ctx;
-
-    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
-
-    ctx->original = ctx->current = serf_bucket_mem_alloc(allocator, len);
-    memcpy((char*)ctx->original, data, len);
-
-    ctx->remaining = len;
-    ctx->freefunc = free_copied_data;
-    ctx->baton = allocator;
-
-    return serf_bucket_create(&serf_bucket_type_simple, allocator, ctx);
-}
-
-serf_bucket_t *serf_bucket_simple_own_create(
-    const char *data, apr_size_t len,
-    serf_bucket_alloc_t *allocator)
-{
-    simple_context_t *ctx;
-
-    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
-
-    ctx->original = ctx->current = data;
-
-    ctx->remaining = len;
-    ctx->freefunc = free_copied_data;
-    ctx->baton = allocator;
-
-    return serf_bucket_create(&serf_bucket_type_simple, allocator, ctx);
-}
-
-static apr_status_t serf_simple_read(serf_bucket_t *bucket,
-                                     apr_size_t requested,
-                                     const char **data, apr_size_t *len)
-{
-    simple_context_t *ctx = bucket->data;
-
-    if (requested == SERF_READ_ALL_AVAIL || requested > ctx->remaining)
-        requested = ctx->remaining;
-
-    *data = ctx->current;
-    *len = requested;
-
-    ctx->current += requested;
-    ctx->remaining -= requested;
-
-    return ctx->remaining ? APR_SUCCESS : APR_EOF;
-}
-
-static apr_status_t serf_simple_readline(serf_bucket_t *bucket,
-                                         int acceptable, int *found,
-                                         const char **data, apr_size_t *len)
-{
-    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,
-                                     const char **data,
-                                     apr_size_t *len)
-{
-    simple_context_t *ctx = bucket->data;
-
-    /* return whatever we have left */
-    *data = ctx->current;
-    *len = ctx->remaining;
-
-    /* we returned everything this bucket will ever hold */
-    return APR_EOF;
-}
-
-static void serf_simple_destroy(serf_bucket_t *bucket)
-{
-    simple_context_t *ctx = bucket->data;
-
-    if (ctx->freefunc)
-        (*ctx->freefunc)(ctx->baton, ctx->original);
-
-    serf_default_destroy_and_data(bucket);
-}
-
-
-const serf_bucket_type_t serf_bucket_type_simple = {
-    "SIMPLE",
-    serf_simple_read,
-    serf_simple_readline,
-    serf_default_read_iovec,
-    serf_default_read_for_sendfile,
-    serf_default_read_bucket,
-    serf_simple_peek,
-    serf_simple_destroy,
-};

Copied: vendor/serf/1.3.9/buckets/simple_buckets.c (from rev 9259, vendor/serf/dist/buckets/simple_buckets.c)
===================================================================
--- vendor/serf/1.3.9/buckets/simple_buckets.c	                        (rev 0)
+++ vendor/serf/1.3.9/buckets/simple_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,164 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_pools.h>
+
+#include "serf.h"
+#include "serf_bucket_util.h"
+
+
+typedef struct {
+    const char *original;
+    const char *current;
+    apr_size_t remaining;
+
+    serf_simple_freefunc_t freefunc;
+    void *baton;
+
+} simple_context_t;
+
+
+static void free_copied_data(void *baton, const char *data)
+{
+    serf_bucket_mem_free(baton, (char*)data);
+}
+
+serf_bucket_t *serf_bucket_simple_create(
+    const char *data,
+    apr_size_t len,
+    serf_simple_freefunc_t freefunc,
+    void *freefunc_baton,
+    serf_bucket_alloc_t *allocator)
+{
+    simple_context_t *ctx;
+
+    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
+    ctx->original = ctx->current = data;
+    ctx->remaining = len;
+    ctx->freefunc = freefunc;
+    ctx->baton = freefunc_baton;
+
+    return serf_bucket_create(&serf_bucket_type_simple, allocator, ctx);
+}
+
+serf_bucket_t *serf_bucket_simple_copy_create(
+    const char *data, apr_size_t len,
+    serf_bucket_alloc_t *allocator)
+{
+    simple_context_t *ctx;
+
+    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
+
+    ctx->original = ctx->current = serf_bucket_mem_alloc(allocator, len);
+    memcpy((char*)ctx->original, data, len);
+
+    ctx->remaining = len;
+    ctx->freefunc = free_copied_data;
+    ctx->baton = allocator;
+
+    return serf_bucket_create(&serf_bucket_type_simple, allocator, ctx);
+}
+
+serf_bucket_t *serf_bucket_simple_own_create(
+    const char *data, apr_size_t len,
+    serf_bucket_alloc_t *allocator)
+{
+    simple_context_t *ctx;
+
+    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
+
+    ctx->original = ctx->current = data;
+
+    ctx->remaining = len;
+    ctx->freefunc = free_copied_data;
+    ctx->baton = allocator;
+
+    return serf_bucket_create(&serf_bucket_type_simple, allocator, ctx);
+}
+
+static apr_status_t serf_simple_read(serf_bucket_t *bucket,
+                                     apr_size_t requested,
+                                     const char **data, apr_size_t *len)
+{
+    simple_context_t *ctx = bucket->data;
+
+    if (requested == SERF_READ_ALL_AVAIL || requested > ctx->remaining)
+        requested = ctx->remaining;
+
+    *data = ctx->current;
+    *len = requested;
+
+    ctx->current += requested;
+    ctx->remaining -= requested;
+
+    return ctx->remaining ? APR_SUCCESS : APR_EOF;
+}
+
+static apr_status_t serf_simple_readline(serf_bucket_t *bucket,
+                                         int acceptable, int *found,
+                                         const char **data, apr_size_t *len)
+{
+    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,
+                                     const char **data,
+                                     apr_size_t *len)
+{
+    simple_context_t *ctx = bucket->data;
+
+    /* return whatever we have left */
+    *data = ctx->current;
+    *len = ctx->remaining;
+
+    /* we returned everything this bucket will ever hold */
+    return APR_EOF;
+}
+
+static void serf_simple_destroy(serf_bucket_t *bucket)
+{
+    simple_context_t *ctx = bucket->data;
+
+    if (ctx->freefunc)
+        (*ctx->freefunc)(ctx->baton, ctx->original);
+
+    serf_default_destroy_and_data(bucket);
+}
+
+
+const serf_bucket_type_t serf_bucket_type_simple = {
+    "SIMPLE",
+    serf_simple_read,
+    serf_simple_readline,
+    serf_default_read_iovec,
+    serf_default_read_for_sendfile,
+    serf_default_read_bucket,
+    serf_simple_peek,
+    serf_simple_destroy,
+};

Deleted: vendor/serf/1.3.9/buckets/socket_buckets.c
===================================================================
--- vendor/serf/dist/buckets/socket_buckets.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/buckets/socket_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,125 +0,0 @@
-/* Copyright 2002-2004 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_pools.h>
-#include <apr_network_io.h>
-
-#include "serf.h"
-#include "serf_private.h"
-#include "serf_bucket_util.h"
-
-
-typedef struct {
-    apr_socket_t *skt;
-
-    serf_databuf_t databuf;
-
-    /* Progress callback */
-    serf_progress_t progress_func;
-    void *progress_baton;
-} socket_context_t;
-
-
-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;
-    status = apr_socket_recv(ctx->skt, buf, len);
-
-    if (status && !APR_STATUS_IS_EAGAIN(status))
-        serf__log_skt(SOCK_VERBOSE, __FILE__, ctx->skt,
-                      "socket_recv error %d\n", status);
-
-    if (*len)
-        serf__log_skt(SOCK_MSG_VERBOSE, __FILE__, ctx->skt,
-                      "--- socket_recv:\n%.*s\n-(%d)-\n",
-                      *len, buf, *len);
-
-    if (ctx->progress_func && *len)
-        ctx->progress_func(ctx->progress_baton, *len, 0);
-
-    return status;
-}
-
-serf_bucket_t *serf_bucket_socket_create(
-    apr_socket_t *skt,
-    serf_bucket_alloc_t *allocator)
-{
-    socket_context_t *ctx;
-
-    /* Oh, well. */
-    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
-    ctx->skt = skt;
-
-    serf_databuf_init(&ctx->databuf);
-    ctx->databuf.read = socket_reader;
-    ctx->databuf.read_baton = ctx;
-
-    ctx->progress_func = NULL;
-    ctx->progress_baton = NULL;
-    return serf_bucket_create(&serf_bucket_type_socket, allocator, ctx);
-}
-
-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)
-{
-    socket_context_t *ctx = bucket->data;
-
-    return serf_databuf_read(&ctx->databuf, requested, data, len);
-}
-
-static apr_status_t serf_socket_readline(serf_bucket_t *bucket,
-                                         int acceptable, int *found,
-                                         const char **data, apr_size_t *len)
-{
-    socket_context_t *ctx = bucket->data;
-
-    return serf_databuf_readline(&ctx->databuf, acceptable, found, data, len);
-}
-
-static apr_status_t serf_socket_peek(serf_bucket_t *bucket,
-                                     const char **data,
-                                     apr_size_t *len)
-{
-    socket_context_t *ctx = bucket->data;
-
-    return serf_databuf_peek(&ctx->databuf, data, len);
-}
-
-const serf_bucket_type_t serf_bucket_type_socket = {
-    "SOCKET",
-    serf_socket_read,
-    serf_socket_readline,
-    serf_default_read_iovec,
-    serf_default_read_for_sendfile,
-    serf_default_read_bucket,
-    serf_socket_peek,
-    serf_default_destroy_and_data,
-};

Copied: vendor/serf/1.3.9/buckets/socket_buckets.c (from rev 9259, vendor/serf/dist/buckets/socket_buckets.c)
===================================================================
--- vendor/serf/1.3.9/buckets/socket_buckets.c	                        (rev 0)
+++ vendor/serf/1.3.9/buckets/socket_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,130 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_pools.h>
+#include <apr_network_io.h>
+
+#include "serf.h"
+#include "serf_private.h"
+#include "serf_bucket_util.h"
+
+
+typedef struct {
+    apr_socket_t *skt;
+
+    serf_databuf_t databuf;
+
+    /* Progress callback */
+    serf_progress_t progress_func;
+    void *progress_baton;
+} socket_context_t;
+
+
+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;
+    status = apr_socket_recv(ctx->skt, buf, len);
+
+    if (status && !APR_STATUS_IS_EAGAIN(status))
+        serf__log_skt(SOCK_VERBOSE, __FILE__, ctx->skt,
+                      "socket_recv error %d\n", status);
+
+    if (*len)
+        serf__log_skt(SOCK_MSG_VERBOSE, __FILE__, ctx->skt,
+                      "--- socket_recv:\n%.*s\n-(%d)-\n",
+                      *len, buf, *len);
+
+    if (ctx->progress_func && *len)
+        ctx->progress_func(ctx->progress_baton, *len, 0);
+
+    return status;
+}
+
+serf_bucket_t *serf_bucket_socket_create(
+    apr_socket_t *skt,
+    serf_bucket_alloc_t *allocator)
+{
+    socket_context_t *ctx;
+
+    /* Oh, well. */
+    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
+    ctx->skt = skt;
+
+    serf_databuf_init(&ctx->databuf);
+    ctx->databuf.read = socket_reader;
+    ctx->databuf.read_baton = ctx;
+
+    ctx->progress_func = NULL;
+    ctx->progress_baton = NULL;
+    return serf_bucket_create(&serf_bucket_type_socket, allocator, ctx);
+}
+
+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)
+{
+    socket_context_t *ctx = bucket->data;
+
+    return serf_databuf_read(&ctx->databuf, requested, data, len);
+}
+
+static apr_status_t serf_socket_readline(serf_bucket_t *bucket,
+                                         int acceptable, int *found,
+                                         const char **data, apr_size_t *len)
+{
+    socket_context_t *ctx = bucket->data;
+
+    return serf_databuf_readline(&ctx->databuf, acceptable, found, data, len);
+}
+
+static apr_status_t serf_socket_peek(serf_bucket_t *bucket,
+                                     const char **data,
+                                     apr_size_t *len)
+{
+    socket_context_t *ctx = bucket->data;
+
+    return serf_databuf_peek(&ctx->databuf, data, len);
+}
+
+const serf_bucket_type_t serf_bucket_type_socket = {
+    "SOCKET",
+    serf_socket_read,
+    serf_socket_readline,
+    serf_default_read_iovec,
+    serf_default_read_for_sendfile,
+    serf_default_read_bucket,
+    serf_socket_peek,
+    serf_default_destroy_and_data,
+};

Deleted: vendor/serf/1.3.9/buckets/ssl_buckets.c
===================================================================
--- vendor/serf/dist/buckets/ssl_buckets.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/buckets/ssl_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,1900 +0,0 @@
-/* Copyright 2002-2004 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.
- *
- * ----
- *
- * For the OpenSSL thread-safety locking code:
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.
- *
- * Originally developed by Aaron Bannert and Justin Erenkrantz, eBuilt.
- */
-
-#include <apr_pools.h>
-#include <apr_network_io.h>
-#include <apr_portable.h>
-#include <apr_strings.h>
-#include <apr_base64.h>
-#include <apr_version.h>
-#include <apr_atomic.h>
-
-#include "serf.h"
-#include "serf_private.h"
-#include "serf_bucket_util.h"
-
-#include <openssl/bio.h>
-#include <openssl/ssl.h>
-#include <openssl/err.h>
-#include <openssl/pkcs12.h>
-#include <openssl/x509v3.h>
-
-#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 */
-
-#ifndef APR_ARRAY_PUSH
-#define APR_ARRAY_PUSH(ary,type) (*((type *)apr_array_push(ary)))
-#endif
-
-
-/*
- * Here's an overview of the SSL bucket's relationship to OpenSSL and serf.
- *
- * HTTP request:  SSLENCRYPT(REQUEST)
- *   [context.c reads from SSLENCRYPT and writes out to the socket]
- * HTTP response: RESPONSE(SSLDECRYPT(SOCKET))
- *   [handler function reads from RESPONSE which in turn reads from SSLDECRYPT]
- *
- * HTTP request read call path:
- *
- * write_to_connection
- *  |- serf_bucket_read on SSLENCRYPT
- *    |- serf_ssl_read
- *      |- serf_databuf_read
- *        |- common_databuf_prep
- *          |- ssl_encrypt
- *            |- 1. Try to read pending encrypted data; If available, return.
- *            |- 2. Try to read from ctx->stream [REQUEST bucket]
- *            |- 3. Call SSL_write with read data
- *              |- ...
- *                |- bio_bucket_read can be called
- *                |- bio_bucket_write with encrypted data
- *                  |- store in sink
- *            |- 4. If successful, read pending encrypted data and return.
- *            |- 5. If fails, place read data back in ctx->stream
- *
- * HTTP response read call path:
- *
- * read_from_connection
- *  |- acceptor
- *  |- handler
- *    |- ...
- *      |- serf_bucket_read(SSLDECRYPT)
- *        |- serf_ssl_read
- *          |- serf_databuf_read
- *            |- ssl_decrypt
- *              |- 1. SSL_read() for pending decrypted data; if any, return.
- *              |- 2. Try to read from ctx->stream [SOCKET bucket]
- *              |- 3. Append data to ssl_ctx->source
- *              |- 4. Call SSL_read()
- *                |- ...
- *                  |- bio_bucket_write can be called
- *                  |- bio_bucket_read
- *                    |- read data from ssl_ctx->source
- *              |- If data read, return it.
- *              |- If an error, set the STATUS value and return.
- *
- */
-
-typedef struct bucket_list {
-    serf_bucket_t *bucket;
-    struct bucket_list *next;
-} bucket_list_t;
-
-typedef struct {
-    /* Helper to read data. Wraps stream. */
-    serf_databuf_t databuf;
-
-    /* Our source for more data. */
-    serf_bucket_t *stream;
-
-    /* The next set of buckets */
-    bucket_list_t *stream_next;
-
-    /* The status of the last thing we read. */
-    apr_status_t status;
-    apr_status_t exhausted;
-    int exhausted_reset;
-
-    /* Data we've read but not processed. */
-    serf_bucket_t *pending;
-} serf_ssl_stream_t;
-
-struct serf_ssl_context_t {
-    /* How many open buckets refer to this context. */
-    int refcount;
-
-    /* The pool that this context uses. */
-    apr_pool_t *pool;
-
-    /* The allocator associated with the above pool. */
-    serf_bucket_alloc_t *allocator;
-
-    /* Internal OpenSSL parameters */
-    SSL_CTX *ctx;
-    SSL *ssl;
-    BIO *bio;
-
-    serf_ssl_stream_t encrypt;
-    serf_ssl_stream_t decrypt;
-
-    /* Client cert callbacks */
-    serf_ssl_need_client_cert_t cert_callback;
-    void *cert_userdata;
-    apr_pool_t *cert_cache_pool;
-    const char *cert_file_success;
-
-    /* Client cert PW callbacks */
-    serf_ssl_need_cert_password_t cert_pw_callback;
-    void *cert_pw_userdata;
-    apr_pool_t *cert_pw_cache_pool;
-    const char *cert_pw_success;
-
-    /* Server cert callbacks */
-    serf_ssl_need_server_cert_t server_cert_callback;
-    serf_ssl_server_cert_chain_cb_t server_cert_chain_callback;
-    void *server_cert_userdata;
-
-    const char *cert_path;
-
-    X509 *cached_cert;
-    EVP_PKEY *cached_cert_pw;
-
-    apr_status_t pending_err;
-
-    /* Status of a fatal error, returned on subsequent encrypt or decrypt
-       requests. */
-    apr_status_t fatal_err;
-};
-
-typedef struct {
-    /* The bucket-independent ssl context that this bucket is associated with */
-    serf_ssl_context_t *ssl_ctx;
-
-    /* Pointer to the 'right' databuf. */
-    serf_databuf_t *databuf;
-
-    /* Pointer to our stream, so we can find it later. */
-    serf_bucket_t **our_stream;
-} ssl_context_t;
-
-struct serf_ssl_certificate_t {
-    X509 *ssl_cert;
-    int depth;
-};
-
-static void disable_compression(serf_ssl_context_t *ssl_ctx);
-static char *
-    pstrdup_escape_nul_bytes(const char *buf, int len, apr_pool_t *pool);
-
-#if SSL_VERBOSE
-/* Log all ssl alerts that we receive from the server. */
-static void
-apps_ssl_info_callback(const SSL *s, int where, int ret)
-{
-    const char *str;
-    int w;
-    w = where & ~SSL_ST_MASK;
-
-    if (w & SSL_ST_CONNECT)
-        str = "SSL_connect";
-    else if (w & SSL_ST_ACCEPT)
-        str = "SSL_accept";
-    else
-        str = "undefined";
-
-    if (where & SSL_CB_LOOP) {
-        serf__log(SSL_VERBOSE, __FILE__, "%s:%s\n", str,
-                  SSL_state_string_long(s));
-    }
-    else if (where & SSL_CB_ALERT) {
-        str = (where & SSL_CB_READ) ? "read" : "write";
-        serf__log(SSL_VERBOSE, __FILE__, "SSL3 alert %s:%s:%s\n",
-               str,
-               SSL_alert_type_string_long(ret),
-               SSL_alert_desc_string_long(ret));
-    }
-    else if (where & SSL_CB_EXIT) {
-        if (ret == 0)
-            serf__log(SSL_VERBOSE, __FILE__, "%s:failed in %s\n", str,
-                      SSL_state_string_long(s));
-        else if (ret < 0) {
-            serf__log(SSL_VERBOSE, __FILE__, "%s:error in %s\n", str,
-                      SSL_state_string_long(s));
-        }
-    }
-}
-#endif
-
-/* Returns the amount read. */
-static int bio_bucket_read(BIO *bio, char *in, int inlen)
-{
-    serf_ssl_context_t *ctx = bio->ptr;
-    const char *data;
-    apr_status_t status;
-    apr_size_t len;
-
-    serf__log(SSL_VERBOSE, __FILE__, "bio_bucket_read called for %d bytes\n",
-              inlen);
-
-    if (ctx->encrypt.status == SERF_ERROR_WAIT_CONN
-        && BIO_should_read(ctx->bio)) {
-        serf__log(SSL_VERBOSE, __FILE__,
-                  "bio_bucket_read waiting: (%d %d %d)\n",
-           BIO_should_retry(ctx->bio), BIO_should_read(ctx->bio),
-           BIO_get_retry_flags(ctx->bio));
-        /* Falling back... */
-        ctx->encrypt.exhausted_reset = 1;
-        BIO_clear_retry_flags(bio);
-    }
-
-    status = serf_bucket_read(ctx->decrypt.pending, inlen, &data, &len);
-
-    ctx->decrypt.status = status;
-
-    serf__log(SSL_VERBOSE, __FILE__, "bio_bucket_read received %d bytes (%d)\n",
-              len, status);
-
-    if (!SERF_BUCKET_READ_ERROR(status)) {
-        /* Oh suck. */
-        if (len) {
-            memcpy(in, data, len);
-            return len;
-        }
-        if (APR_STATUS_IS_EOF(status)) {
-            BIO_set_retry_read(bio);
-            return -1;
-        }
-    }
-
-    return -1;
-}
-
-/* Returns the amount written. */
-static int bio_bucket_write(BIO *bio, const char *in, int inl)
-{
-    serf_ssl_context_t *ctx = bio->ptr;
-    serf_bucket_t *tmp;
-
-    serf__log(SSL_VERBOSE, __FILE__, "bio_bucket_write called for %d bytes\n",
-              inl);
-
-    if (ctx->encrypt.status == SERF_ERROR_WAIT_CONN
-        && !BIO_should_read(ctx->bio)) {
-        serf__log(SSL_VERBOSE, __FILE__,
-                  "bio_bucket_write waiting: (%d %d %d)\n",
-           BIO_should_retry(ctx->bio), BIO_should_read(ctx->bio),
-           BIO_get_retry_flags(ctx->bio));
-        /* Falling back... */
-        ctx->encrypt.exhausted_reset = 1;
-        BIO_clear_retry_flags(bio);
-    }
-
-    tmp = serf_bucket_simple_copy_create(in, inl,
-                                         ctx->encrypt.pending->allocator);
-
-    serf_bucket_aggregate_append(ctx->encrypt.pending, tmp);
-
-    return inl;
-}
-
-/* Returns the amount read. */
-static int bio_file_read(BIO *bio, char *in, int inlen)
-{
-    apr_file_t *file = bio->ptr;
-    apr_status_t status;
-    apr_size_t len;
-
-    BIO_clear_retry_flags(bio);
-
-    len = inlen;
-    status = apr_file_read(file, in, &len);
-
-    if (!SERF_BUCKET_READ_ERROR(status)) {
-        /* Oh suck. */
-        if (APR_STATUS_IS_EOF(status)) {
-            BIO_set_retry_read(bio);
-            return -1;
-        } else {
-            return len;
-        }
-    }
-
-    return -1;
-}
-
-/* Returns the amount written. */
-static int bio_file_write(BIO *bio, const char *in, int inl)
-{
-    apr_file_t *file = bio->ptr;
-    apr_size_t nbytes;
-
-    BIO_clear_retry_flags(bio);
-
-    nbytes = inl;
-    apr_file_write(file, in, &nbytes);
-
-    return nbytes;
-}
-
-static int bio_file_gets(BIO *bio, char *in, int inlen)
-{
-    return bio_file_read(bio, in, inlen);
-}
-
-static int bio_bucket_create(BIO *bio)
-{
-    bio->shutdown = 1;
-    bio->init = 1;
-    bio->num = -1;
-    bio->ptr = NULL;
-
-    return 1;
-}
-
-static int bio_bucket_destroy(BIO *bio)
-{
-    /* Did we already free this? */
-    if (bio == NULL) {
-        return 0;
-    }
-
-    return 1;
-}
-
-static long bio_bucket_ctrl(BIO *bio, int cmd, long num, void *ptr)
-{
-    long ret = 1;
-
-    switch (cmd) {
-    default:
-        /* abort(); */
-        break;
-    case BIO_CTRL_FLUSH:
-        /* At this point we can't force a flush. */
-        break;
-    case BIO_CTRL_PUSH:
-    case BIO_CTRL_POP:
-        ret = 0;
-        break;
-    }
-    return ret;
-}
-
-static BIO_METHOD bio_bucket_method = {
-    BIO_TYPE_MEM,
-    "Serf SSL encryption and decryption buckets",
-    bio_bucket_write,
-    bio_bucket_read,
-    NULL,                        /* Is this called? */
-    NULL,                        /* Is this called? */
-    bio_bucket_ctrl,
-    bio_bucket_create,
-    bio_bucket_destroy,
-#ifdef OPENSSL_VERSION_NUMBER
-    NULL /* sslc does not have the callback_ctrl field */
-#endif
-};
-
-static BIO_METHOD bio_file_method = {
-    BIO_TYPE_FILE,
-    "Wrapper around APR file structures",
-    bio_file_write,
-    bio_file_read,
-    NULL,                        /* Is this called? */
-    bio_file_gets,               /* Is this called? */
-    bio_bucket_ctrl,
-    bio_bucket_create,
-    bio_bucket_destroy,
-#ifdef OPENSSL_VERSION_NUMBER
-    NULL /* sslc does not have the callback_ctrl field */
-#endif
-};
-
-typedef enum san_copy_t {
-    EscapeNulAndCopy = 0,
-    ErrorOnNul = 1,
-} san_copy_t;
-
-
-static apr_status_t
-get_subject_alt_names(apr_array_header_t **san_arr, X509 *ssl_cert,
-                      san_copy_t copy_action, apr_pool_t *pool)
-{
-    STACK_OF(GENERAL_NAME) *names;
-
-    /* assert: copy_action == ErrorOnNul || (san_arr && pool) */
-
-    if (san_arr) {
-        *san_arr = NULL;
-    }
-
-    /* Get subjectAltNames */
-    names = X509_get_ext_d2i(ssl_cert, NID_subject_alt_name, NULL, NULL);
-    if (names) {
-        int names_count = sk_GENERAL_NAME_num(names);
-        int name_idx;
-
-        if (san_arr)
-            *san_arr = apr_array_make(pool, names_count, sizeof(char*));
-        for (name_idx = 0; name_idx < names_count; name_idx++) {
-            char *p = NULL;
-            GENERAL_NAME *nm = sk_GENERAL_NAME_value(names, name_idx);
-
-            switch (nm->type) {
-                case GEN_DNS:
-                    if (copy_action == ErrorOnNul &&
-                        strlen(nm->d.ia5->data) != nm->d.ia5->length)
-                        return SERF_ERROR_SSL_CERT_FAILED;
-                    if (san_arr && *san_arr)
-                        p = pstrdup_escape_nul_bytes((const char *)nm->d.ia5->data,
-                                                     nm->d.ia5->length,
-                                                     pool);
-                    break;
-                default:
-                    /* Don't know what to do - skip. */
-                    break;
-            }
-
-            if (p) {
-                APR_ARRAY_PUSH(*san_arr, char*) = p;
-            }
-        }
-        sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
-    }
-    
-    return APR_SUCCESS;
-}
-
-static apr_status_t validate_cert_hostname(X509 *server_cert, apr_pool_t *pool)
-{
-    char buf[1024];
-    int length;
-    apr_status_t ret;
-
-    ret = get_subject_alt_names(NULL, server_cert, ErrorOnNul, NULL);
-    if (ret) {
-      return ret;
-    } else {
-        /* Fail if the subject's CN field contains \0 characters. */
-        X509_NAME *subject = X509_get_subject_name(server_cert);
-        if (!subject)
-            return SERF_ERROR_SSL_CERT_FAILED;
-
-        length = X509_NAME_get_text_by_NID(subject, NID_commonName, buf, 1024);
-        if (length != -1)
-            if (strlen(buf) != length)
-                return SERF_ERROR_SSL_CERT_FAILED;
-    }
-
-    return APR_SUCCESS;
-}
-
-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;
-    apr_status_t status;
-
-    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:
-            case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
-            case X509_V_ERR_CERT_UNTRUSTED:
-            case X509_V_ERR_INVALID_CA:
-            case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
-                    failures |= SERF_SSL_CERT_UNKNOWNCA;
-                    break;
-            case X509_V_ERR_CERT_REVOKED:
-                    failures |= SERF_SSL_CERT_REVOKED;
-                    break;
-            default:
-                    failures |= SERF_SSL_CERT_UNKNOWN_FAILURE;
-                    break;
-        }
-    }
-
-    /* Validate hostname */
-    status = validate_cert_hostname(server_cert, ctx->pool);
-    if (status)
-        failures |= SERF_SSL_CERT_UNKNOWN_FAILURE;
-
-    /* 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)) {
-        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;
-        cert->depth = depth;
-
-        /* Callback for further verification. */
-        status = ctx->server_cert_callback(ctx->server_cert_userdata,
-                                           failures, cert);
-        if (status == APR_SUCCESS)
-            cert_valid = 1;
-        else {
-            /* Even if openssl found the certificate valid, the application
-               told us to reject it. */
-            cert_valid = 0;
-            /* Pass the error back to the caller through the context-run. */
-            ctx->pending_err = status;
-        }
-        apr_pool_destroy(subpool);
-    }
-
-    if (ctx->server_cert_chain_callback
-        && (depth == 0 || failures)) {
-        STACK_OF(X509) *chain;
-        const serf_ssl_certificate_t **certs;
-        int certs_len;
-        apr_pool_t *subpool;
-
-        apr_pool_create(&subpool, ctx->pool);
-
-        /* Borrow the chain to pass to the callback. */
-        chain = X509_STORE_CTX_get_chain(store_ctx);
-
-        /* If the chain can't be retrieved, just pass the current
-           certificate. */
-        /* ### can this actually happen with _get_chain() ?  */
-        if (!chain) {
-            serf_ssl_certificate_t *cert = apr_palloc(subpool, sizeof(*cert));
-
-            cert->ssl_cert = server_cert;
-            cert->depth = depth;
-
-            /* Room for the server_cert and a trailing NULL.  */
-            certs = apr_palloc(subpool, sizeof(*certs) * 2);
-            certs[0] = cert;
-
-            certs_len = 1;
-        } else {
-            int i;
-
-            certs_len = sk_X509_num(chain);
-
-            /* Room for all the certs and a trailing NULL.  */
-            certs = apr_palloc(subpool, sizeof(*certs) * (certs_len + 1));
-            for (i = 0; i < certs_len; ++i) {
-                serf_ssl_certificate_t *cert;
-
-                cert = apr_palloc(subpool, sizeof(*cert));
-                cert->ssl_cert = sk_X509_value(chain, i);
-                cert->depth = i;
-
-                certs[i] = cert;
-            }
-        }
-        certs[certs_len] = NULL;
-
-        /* Callback for further verification. */
-        status = ctx->server_cert_chain_callback(ctx->server_cert_userdata,
-                                                 failures, depth,
-                                                 certs, certs_len);
-        if (status == APR_SUCCESS) {
-            cert_valid = 1;
-        } else {
-            /* Even if openssl found the certificate valid, the application
-               told us to reject it. */
-            cert_valid = 0;
-            /* Pass the error back to the caller through the context-run. */
-            ctx->pending_err = status;
-        }
-
-        apr_pool_destroy(subpool);
-    }
-
-    /* Return a specific error if the server certificate is not accepted by
-       OpenSSL and the application has not set callbacks to override this. */
-    if (!cert_valid &&
-        !ctx->server_cert_chain_callback &&
-        !ctx->server_cert_callback)
-    {
-        ctx->pending_err = SERF_ERROR_SSL_CERT_FAILED;
-    }
-        
-    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)
-{
-    serf_ssl_context_t *ctx = baton;
-    apr_size_t priv_len;
-    apr_status_t status;
-    const char *data;
-    int ssl_len;
-
-    if (ctx->fatal_err)
-        return ctx->fatal_err;
-
-    serf__log(SSL_VERBOSE, __FILE__, "ssl_decrypt: begin %d\n", bufsize);
-
-    /* Is there some data waiting to be read? */
-    ssl_len = SSL_read(ctx->ssl, buf, bufsize);
-    if (ssl_len > 0) {
-        serf__log(SSL_VERBOSE, __FILE__,
-                  "ssl_decrypt: %d bytes (%d); status: %d; flags: %d\n",
-                  ssl_len, bufsize, ctx->decrypt.status,
-                  BIO_get_retry_flags(ctx->bio));
-        *len = ssl_len;
-        return APR_SUCCESS;
-    }
-
-    status = serf_bucket_read(ctx->decrypt.stream, bufsize, &data, &priv_len);
-
-    if (!SERF_BUCKET_READ_ERROR(status) && priv_len) {
-        serf_bucket_t *tmp;
-
-        serf__log(SSL_VERBOSE, __FILE__,
-                  "ssl_decrypt: read %d bytes (%d); status: %d\n",
-                  priv_len, bufsize, status);
-
-        tmp = serf_bucket_simple_copy_create(data, priv_len,
-                                             ctx->decrypt.pending->allocator);
-
-        serf_bucket_aggregate_append(ctx->decrypt.pending, tmp);
-
-        ssl_len = SSL_read(ctx->ssl, buf, bufsize);
-        if (ssl_len < 0) {
-            int ssl_err;
-
-            ssl_err = SSL_get_error(ctx->ssl, ssl_len);
-            switch (ssl_err) {
-            case SSL_ERROR_SYSCALL:
-                *len = 0;
-                /* Return the underlying network error that caused OpenSSL
-                   to fail. ### This can be a crypt error! */
-                status = ctx->decrypt.status;
-                break;
-            case SSL_ERROR_WANT_READ:
-            case SSL_ERROR_WANT_WRITE:
-                *len = 0;
-                status = APR_EAGAIN;
-                break;
-            case SSL_ERROR_SSL:
-                *len = 0;
-                if (ctx->pending_err) {
-                    status = ctx->pending_err;
-                    ctx->pending_err = 0;
-                } else {
-                    ctx->fatal_err = status = SERF_ERROR_SSL_COMM_FAILED;
-                }
-                break;
-            default:
-                *len = 0;
-                ctx->fatal_err = status = SERF_ERROR_SSL_COMM_FAILED;
-                break;
-            }
-        } else if (ssl_len == 0) {
-            /* The server shut down the connection. */
-            int ssl_err, shutdown;
-            *len = 0;
-
-            /* Check for SSL_RECEIVED_SHUTDOWN */
-            shutdown = SSL_get_shutdown(ctx->ssl);
-            /* Check for SSL_ERROR_ZERO_RETURN */
-            ssl_err = SSL_get_error(ctx->ssl, ssl_len);
-
-            if (shutdown == SSL_RECEIVED_SHUTDOWN &&
-                ssl_err == SSL_ERROR_ZERO_RETURN) {
-                /* The server closed the SSL session. While this doesn't
-                necessary mean the connection is closed, let's close
-                it here anyway.
-                We can optimize this later. */
-                serf__log(SSL_VERBOSE, __FILE__, 
-                          "ssl_decrypt: SSL read error: server"
-                          " shut down connection!\n");
-                status = APR_EOF;
-            } else {
-                /* A fatal error occurred. */
-                ctx->fatal_err = status = SERF_ERROR_SSL_COMM_FAILED;
-            }
-        } else {
-            *len = ssl_len;
-            serf__log(SSL_MSG_VERBOSE, __FILE__, 
-                      "---\n%.*s\n-(%d)-\n", *len, buf, *len);
-        }
-    }
-    else {
-        *len = 0;
-    }
-    serf__log(SSL_VERBOSE, __FILE__, 
-              "ssl_decrypt: %d %d %d\n", status, *len,
-              BIO_get_retry_flags(ctx->bio));
-
-    return status;
-}
-
-/* This function reads a decrypted stream and returns an encrypted stream. */
-static apr_status_t ssl_encrypt(void *baton, apr_size_t bufsize,
-                                char *buf, apr_size_t *len)
-{
-    const char *data;
-    apr_size_t interim_bufsize;
-    serf_ssl_context_t *ctx = baton;
-    apr_status_t status;
-
-    if (ctx->fatal_err)
-        return ctx->fatal_err;
-
-    serf__log(SSL_VERBOSE, __FILE__, "ssl_encrypt: begin %d\n", bufsize);
-
-    /* Try to read already encrypted but unread data first. */
-    status = serf_bucket_read(ctx->encrypt.pending, bufsize, &data, len);
-    if (SERF_BUCKET_READ_ERROR(status)) {
-        return status;
-    }
-
-    /* Aha, we read something.  Return that now. */
-    if (*len) {
-        memcpy(buf, data, *len);
-        if (APR_STATUS_IS_EOF(status)) {
-            status = APR_SUCCESS;
-        }
-
-        serf__log(SSL_VERBOSE, __FILE__, "ssl_encrypt: %d %d %d (quick read)\n",
-                  status, *len, BIO_get_retry_flags(ctx->bio));
-
-        return status;
-    }
-
-    if (BIO_should_retry(ctx->bio) && BIO_should_write(ctx->bio)) {
-        serf__log(SSL_VERBOSE, __FILE__,
-                  "ssl_encrypt: %d %d %d (should write exit)\n",
-                  status, *len, BIO_get_retry_flags(ctx->bio));
-
-        return APR_EAGAIN;
-    }
-
-    /* If we were previously blocked, unblock ourselves now. */
-    if (BIO_should_read(ctx->bio)) {
-        serf__log(SSL_VERBOSE, __FILE__, "ssl_encrypt: reset %d %d (%d %d %d)\n",
-                  status, ctx->encrypt.status,
-                  BIO_should_retry(ctx->bio), BIO_should_read(ctx->bio),
-                  BIO_get_retry_flags(ctx->bio));
-
-        ctx->encrypt.status = APR_SUCCESS;
-        ctx->encrypt.exhausted_reset = 0;
-    }
-
-    /* Oh well, read from our stream now. */
-    interim_bufsize = bufsize;
-    do {
-        apr_size_t interim_len;
-
-        if (!ctx->encrypt.status) {
-            struct iovec vecs[64];
-            int vecs_read;
-
-            status = serf_bucket_read_iovec(ctx->encrypt.stream,
-                                            interim_bufsize, 64, vecs,
-                                            &vecs_read);
-
-            if (!SERF_BUCKET_READ_ERROR(status) && vecs_read) {
-                char *vecs_data;
-                int i, cur, vecs_data_len;
-                int ssl_len;
-
-                /* Combine the buffers of the iovec into one buffer, as
-                   that is with SSL_write requires. */
-                vecs_data_len = 0;
-                for (i = 0; i < vecs_read; i++) {
-                    vecs_data_len += vecs[i].iov_len;
-                }
-
-                vecs_data = serf_bucket_mem_alloc(ctx->allocator,
-                                                  vecs_data_len);
-
-                cur = 0;
-                for (i = 0; i < vecs_read; i++) {
-                    memcpy(vecs_data + cur, vecs[i].iov_base, vecs[i].iov_len);
-                    cur += vecs[i].iov_len;
-                }
-
-                interim_bufsize -= vecs_data_len;
-                interim_len = vecs_data_len;
-
-                serf__log(SSL_VERBOSE, __FILE__,
-                          "ssl_encrypt: bucket read %d bytes; "\
-                          "status %d\n", interim_len, status);
-                serf__log(SSL_MSG_VERBOSE, __FILE__, "---\n%.*s\n-(%d)-\n",
-                          interim_len, vecs_data, interim_len);
-
-                /* Stash our status away. */
-                ctx->encrypt.status = status;
-
-                ssl_len = SSL_write(ctx->ssl, vecs_data, interim_len);
-
-                serf__log(SSL_VERBOSE, __FILE__, 
-                          "ssl_encrypt: SSL write: %d\n", ssl_len);
-
-                /* If we failed to write... */
-                if (ssl_len < 0) {
-                    int ssl_err;
-
-                    /* Ah, bugger. We need to put that data back.
-                       Note: use the copy here, we do not own the original iovec
-                       data buffer so it will be freed on next read. */
-                    serf_bucket_t *vecs_copy =
-                        serf_bucket_simple_own_create(vecs_data,
-                                                      vecs_data_len,
-                                                      ctx->allocator);
-                    serf_bucket_aggregate_prepend(ctx->encrypt.stream,
-                                                  vecs_copy);
-
-                    ssl_err = SSL_get_error(ctx->ssl, ssl_len);
-
-                    serf__log(SSL_VERBOSE, __FILE__, 
-                              "ssl_encrypt: SSL write error: %d\n", ssl_err);
-
-                    if (ssl_err == SSL_ERROR_SYSCALL) {
-                        /* Return the underlying network error that caused OpenSSL
-                           to fail. ### This can be a decrypt error! */
-                        status = ctx->encrypt.status;
-                        if (SERF_BUCKET_READ_ERROR(status)) {
-                            return status;
-                        }
-                    }
-                    else {
-                        /* Oh, no. */
-                        if (ssl_err == SSL_ERROR_WANT_READ) {
-                            status = SERF_ERROR_WAIT_CONN;
-                        }
-                        else {
-                            ctx->fatal_err = status =
-                                SERF_ERROR_SSL_COMM_FAILED;
-                        }
-                    }
-
-                    serf__log(SSL_VERBOSE, __FILE__, 
-                              "ssl_encrypt: SSL write error: %d %d\n",
-                              status, *len);
-                } else {
-                    /* We're done with this data. */
-                    serf_bucket_mem_free(ctx->allocator, vecs_data);
-                }
-            }
-        }
-        else {
-            interim_len = 0;
-            *len = 0;
-            status = ctx->encrypt.status;
-        }
-
-    } while (!status && interim_bufsize);
-
-    /* Okay, we exhausted our underlying stream. */
-    if (!SERF_BUCKET_READ_ERROR(status)) {
-        apr_status_t agg_status;
-        struct iovec vecs[64];
-        int vecs_read, i;
-
-        /* We read something! */
-        agg_status = serf_bucket_read_iovec(ctx->encrypt.pending, bufsize,
-                                            64, vecs, &vecs_read);
-        *len = 0;
-        for (i = 0; i < vecs_read; i++) {
-            memcpy(buf + *len, vecs[i].iov_base, vecs[i].iov_len);
-            *len += vecs[i].iov_len;
-        }
-
-        serf__log(SSL_VERBOSE, __FILE__,
-                  "ssl_encrypt read agg: %d %d %d %d\n", status, agg_status,
-            ctx->encrypt.status, *len);
-
-        if (!agg_status) {
-            status = agg_status;
-        }
-    }
-
-    if (status == SERF_ERROR_WAIT_CONN
-        && BIO_should_retry(ctx->bio) && BIO_should_read(ctx->bio)) {
-        ctx->encrypt.exhausted = ctx->encrypt.status;
-        ctx->encrypt.status = SERF_ERROR_WAIT_CONN;
-    }
-
-    serf__log(SSL_VERBOSE, __FILE__,
-              "ssl_encrypt finished: %d %d (%d %d %d)\n", status, *len,
-              BIO_should_retry(ctx->bio), BIO_should_read(ctx->bio),
-              BIO_get_retry_flags(ctx->bio));
-
-    return status;
-}
-
-#if APR_HAS_THREADS
-static apr_pool_t *ssl_pool;
-static apr_thread_mutex_t **ssl_locks;
-
-typedef struct CRYPTO_dynlock_value {
-    apr_thread_mutex_t *lock;
-} CRYPTO_dynlock_value;
-
-static CRYPTO_dynlock_value *ssl_dyn_create(const char* file, int line)
-{
-    CRYPTO_dynlock_value *l;
-    apr_status_t rv;
-
-    l = apr_palloc(ssl_pool, sizeof(CRYPTO_dynlock_value));
-    rv = apr_thread_mutex_create(&l->lock, APR_THREAD_MUTEX_DEFAULT, ssl_pool);
-    if (rv != APR_SUCCESS) {
-        /* FIXME: return error here */
-    }
-    return l;
-}
-
-static void ssl_dyn_lock(int mode, CRYPTO_dynlock_value *l, const char *file,
-                         int line)
-{
-    if (mode & CRYPTO_LOCK) {
-        apr_thread_mutex_lock(l->lock);
-    }
-    else if (mode & CRYPTO_UNLOCK) {
-        apr_thread_mutex_unlock(l->lock);
-    }
-}
-
-static void ssl_dyn_destroy(CRYPTO_dynlock_value *l, const char *file,
-                            int line)
-{
-    apr_thread_mutex_destroy(l->lock);
-}
-
-static void ssl_lock(int mode, int n, const char *file, int line)
-{
-    if (mode & CRYPTO_LOCK) {
-        apr_thread_mutex_lock(ssl_locks[n]);
-    }
-    else if (mode & CRYPTO_UNLOCK) {
-        apr_thread_mutex_unlock(ssl_locks[n]);
-    }
-}
-
-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
-
-#if !APR_VERSION_AT_LEAST(1,0,0)
-#define apr_atomic_cas32(mem, with, cmp) apr_atomic_cas(mem, with, cmp)
-#endif
-
-enum ssl_init_e
-{
-   INIT_UNINITIALIZED = 0,
-   INIT_BUSY = 1,
-   INIT_DONE = 2
-};
-
-static volatile apr_uint32_t have_init_ssl = INIT_UNINITIALIZED;
-
-static void init_ssl_libraries(void)
-{
-    apr_uint32_t val;
-
-    val = apr_atomic_cas32(&have_init_ssl, INIT_BUSY, INIT_UNINITIALIZED);
-
-    if (!val) {
-#if APR_HAS_THREADS
-        int i, numlocks;
-#endif
-
-#ifdef SSL_VERBOSE
-        /* Warn when compile-time and run-time version of OpenSSL differ in
-           major/minor version number. */
-        long libver = SSLeay();
-
-        if ((libver ^ OPENSSL_VERSION_NUMBER) & 0xFFF00000) {
-            serf__log(SSL_VERBOSE, __FILE__,
-                      "Warning: OpenSSL library version mismatch, compile-time "
-                      "was %lx, runtime is %lx.\n",
-                      OPENSSL_VERSION_NUMBER, libver);
-        }
-#endif
-
-        CRYPTO_malloc_init();
-        ERR_load_crypto_strings();
-        SSL_load_error_strings();
-        SSL_library_init();
-        OpenSSL_add_all_algorithms();
-
-#if APR_HAS_THREADS
-        numlocks = CRYPTO_num_locks();
-        apr_pool_create(&ssl_pool, NULL);
-        ssl_locks = apr_palloc(ssl_pool, sizeof(apr_thread_mutex_t*)*numlocks);
-        for (i = 0; i < numlocks; i++) {
-            apr_status_t rv;
-
-            /* Intraprocess locks don't /need/ a filename... */
-            rv = apr_thread_mutex_create(&ssl_locks[i],
-                                         APR_THREAD_MUTEX_DEFAULT, ssl_pool);
-            if (rv != APR_SUCCESS) {
-                /* FIXME: error out here */
-            }
-        }
-        CRYPTO_set_locking_callback(ssl_lock);
-        CRYPTO_set_id_callback(ssl_id);
-        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
-        apr_atomic_cas32(&have_init_ssl, INIT_DONE, INIT_BUSY);
-    }
-  else
-    {
-        /* Make sure we don't continue before the initialization in another
-           thread has completed */
-        while (val != INIT_DONE) {
-            apr_sleep(APR_USEC_PER_SEC / 1000);
-      
-            val = apr_atomic_cas32(&have_init_ssl,
-                                   INIT_UNINITIALIZED,
-                                   INIT_UNINITIALIZED);            
-        }
-    }
-}
-
-static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey)
-{
-    serf_ssl_context_t *ctx = SSL_get_app_data(ssl);
-    apr_status_t status;
-
-    if (ctx->cached_cert) {
-        *cert = ctx->cached_cert;
-        *pkey = ctx->cached_cert_pw;
-        return 1;
-    }
-
-    while (ctx->cert_callback) {
-        const char *cert_path;
-        apr_file_t *cert_file;
-        BIO *bio;
-        PKCS12 *p12;
-        int i;
-        int retrying_success = 0;
-
-        if (ctx->cert_file_success) {
-            status = APR_SUCCESS;
-            cert_path = ctx->cert_file_success;
-            ctx->cert_file_success = NULL;
-            retrying_success = 1;
-        } else {
-            status = ctx->cert_callback(ctx->cert_userdata, &cert_path);
-        }
-
-        if (status || !cert_path) {
-            break;
-        }
-
-        /* Load the x.509 cert file stored in PKCS12 */
-        status = apr_file_open(&cert_file, cert_path, APR_READ, APR_OS_DEFAULT,
-                               ctx->pool);
-
-        if (status) {
-            continue;
-        }
-
-        bio = BIO_new(&bio_file_method);
-        bio->ptr = cert_file;
-
-        ctx->cert_path = cert_path;
-        p12 = d2i_PKCS12_bio(bio, NULL);
-        apr_file_close(cert_file);
-
-        i = PKCS12_parse(p12, NULL, pkey, cert, NULL);
-
-        if (i == 1) {
-            PKCS12_free(p12);
-            ctx->cached_cert = *cert;
-            ctx->cached_cert_pw = *pkey;
-            if (!retrying_success && ctx->cert_cache_pool) {
-                const char *c;
-
-                c = apr_pstrdup(ctx->cert_cache_pool, ctx->cert_path);
-
-                apr_pool_userdata_setn(c, "serf:ssl:cert",
-                                       apr_pool_cleanup_null,
-                                       ctx->cert_cache_pool);
-            }
-            return 1;
-        }
-        else {
-            int err = ERR_get_error();
-            ERR_clear_error();
-            if (ERR_GET_LIB(err) == ERR_LIB_PKCS12 &&
-                ERR_GET_REASON(err) == PKCS12_R_MAC_VERIFY_FAILURE) {
-                if (ctx->cert_pw_callback) {
-                    const char *password;
-
-                    if (ctx->cert_pw_success) {
-                        status = APR_SUCCESS;
-                        password = ctx->cert_pw_success;
-                        ctx->cert_pw_success = NULL;
-                    } else {
-                        status = ctx->cert_pw_callback(ctx->cert_pw_userdata,
-                                                       ctx->cert_path,
-                                                       &password);
-                    }
-
-                    if (!status && password) {
-                        i = PKCS12_parse(p12, password, pkey, cert, NULL);
-                        if (i == 1) {
-                            PKCS12_free(p12);
-                            ctx->cached_cert = *cert;
-                            ctx->cached_cert_pw = *pkey;
-                            if (!retrying_success && ctx->cert_cache_pool) {
-                                const char *c;
-
-                                c = apr_pstrdup(ctx->cert_cache_pool,
-                                                ctx->cert_path);
-
-                                apr_pool_userdata_setn(c, "serf:ssl:cert",
-                                                       apr_pool_cleanup_null,
-                                                       ctx->cert_cache_pool);
-                            }
-                            if (!retrying_success && ctx->cert_pw_cache_pool) {
-                                const char *c;
-
-                                c = apr_pstrdup(ctx->cert_pw_cache_pool,
-                                                password);
-
-                                apr_pool_userdata_setn(c, "serf:ssl:certpw",
-                                                       apr_pool_cleanup_null,
-                                                       ctx->cert_pw_cache_pool);
-                            }
-                            return 1;
-                        }
-                    }
-                }
-                PKCS12_free(p12);
-                return 0;
-            }
-            else {
-                printf("OpenSSL cert error: %d %d %d\n", ERR_GET_LIB(err),
-                       ERR_GET_FUNC(err),
-                       ERR_GET_REASON(err));
-                PKCS12_free(p12);
-            }
-        }
-    }
-
-    return 0;
-}
-
-
-void serf_ssl_client_cert_provider_set(
-    serf_ssl_context_t *context,
-    serf_ssl_need_client_cert_t callback,
-    void *data,
-    void *cache_pool)
-{
-    context->cert_callback = callback;
-    context->cert_userdata = data;
-    context->cert_cache_pool = cache_pool;
-    if (context->cert_cache_pool) {
-        apr_pool_userdata_get((void**)&context->cert_file_success,
-                              "serf:ssl:cert", cache_pool);
-    }
-}
-
-
-void serf_ssl_client_cert_password_set(
-    serf_ssl_context_t *context,
-    serf_ssl_need_cert_password_t callback,
-    void *data,
-    void *cache_pool)
-{
-    context->cert_pw_callback = callback;
-    context->cert_pw_userdata = data;
-    context->cert_pw_cache_pool = cache_pool;
-    if (context->cert_pw_cache_pool) {
-        apr_pool_userdata_get((void**)&context->cert_pw_success,
-                              "serf:ssl:certpw", cache_pool);
-    }
-}
-
-
-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;
-}
-
-void serf_ssl_server_cert_chain_callback_set(
-    serf_ssl_context_t *context,
-    serf_ssl_need_server_cert_t cert_callback,
-    serf_ssl_server_cert_chain_cb_t cert_chain_callback,
-    void *data)
-{
-    context->server_cert_callback = cert_callback;
-    context->server_cert_chain_callback = cert_chain_callback;
-    context->server_cert_userdata = data;
-}
-
-static serf_ssl_context_t *ssl_init_context(serf_bucket_alloc_t *allocator)
-{
-    serf_ssl_context_t *ssl_ctx;
-
-    init_ssl_libraries();
-
-    ssl_ctx = serf_bucket_mem_alloc(allocator, sizeof(*ssl_ctx));
-
-    ssl_ctx->refcount = 0;
-    ssl_ctx->pool = serf_bucket_allocator_get_pool(allocator);
-    ssl_ctx->allocator = allocator;
-
-    /* Use the best possible protocol version, but disable the broken SSLv2/3 */
-    ssl_ctx->ctx = SSL_CTX_new(SSLv23_client_method());
-    SSL_CTX_set_options(ssl_ctx->ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
-
-    SSL_CTX_set_client_cert_cb(ssl_ctx->ctx, ssl_need_client_cert);
-    ssl_ctx->cached_cert = 0;
-    ssl_ctx->cached_cert_pw = 0;
-    ssl_ctx->pending_err = APR_SUCCESS;
-    ssl_ctx->fatal_err = APR_SUCCESS;
-
-    ssl_ctx->cert_callback = NULL;
-    ssl_ctx->cert_pw_callback = NULL;
-    ssl_ctx->server_cert_callback = NULL;
-    ssl_ctx->server_cert_chain_callback = NULL;
-
-    SSL_CTX_set_verify(ssl_ctx->ctx, SSL_VERIFY_PEER,
-                       validate_server_certificate);
-    SSL_CTX_set_options(ssl_ctx->ctx, SSL_OP_ALL);
-    /* Disable SSL compression by default. */
-    disable_compression(ssl_ctx);
-
-    ssl_ctx->ssl = SSL_new(ssl_ctx->ctx);
-    ssl_ctx->bio = BIO_new(&bio_bucket_method);
-    ssl_ctx->bio->ptr = ssl_ctx;
-
-    SSL_set_bio(ssl_ctx->ssl, ssl_ctx->bio, ssl_ctx->bio);
-
-    SSL_set_connect_state(ssl_ctx->ssl);
-
-    SSL_set_app_data(ssl_ctx->ssl, ssl_ctx);
-
-#if SSL_VERBOSE
-    SSL_CTX_set_info_callback(ssl_ctx->ctx, apps_ssl_info_callback);
-#endif
-
-    ssl_ctx->encrypt.stream = NULL;
-    ssl_ctx->encrypt.stream_next = NULL;
-    ssl_ctx->encrypt.pending = serf_bucket_aggregate_create(allocator);
-    ssl_ctx->encrypt.status = APR_SUCCESS;
-    serf_databuf_init(&ssl_ctx->encrypt.databuf);
-    ssl_ctx->encrypt.databuf.read = ssl_encrypt;
-    ssl_ctx->encrypt.databuf.read_baton = ssl_ctx;
-
-    ssl_ctx->decrypt.stream = NULL;
-    ssl_ctx->decrypt.pending = serf_bucket_aggregate_create(allocator);
-    ssl_ctx->decrypt.status = APR_SUCCESS;
-    serf_databuf_init(&ssl_ctx->decrypt.databuf);
-    ssl_ctx->decrypt.databuf.read = ssl_decrypt;
-    ssl_ctx->decrypt.databuf.read_baton = ssl_ctx;
-
-    return ssl_ctx;
-}
-
-static apr_status_t ssl_free_context(
-    serf_ssl_context_t *ssl_ctx)
-{
-    /* If never had the pending buckets, don't try to free them. */
-    if (ssl_ctx->decrypt.pending != NULL) {
-        serf_bucket_destroy(ssl_ctx->decrypt.pending);
-    }
-    if (ssl_ctx->encrypt.pending != NULL) {
-        serf_bucket_destroy(ssl_ctx->encrypt.pending);
-    }
-
-    /* SSL_free implicitly frees the underlying BIO. */
-    SSL_free(ssl_ctx->ssl);
-    SSL_CTX_free(ssl_ctx->ctx);
-
-    serf_bucket_mem_free(ssl_ctx->allocator, ssl_ctx);
-
-    return APR_SUCCESS;
-}
-
-static serf_bucket_t * serf_bucket_ssl_create(
-    serf_ssl_context_t *ssl_ctx,
-    serf_bucket_alloc_t *allocator,
-    const serf_bucket_type_t *type)
-{
-    ssl_context_t *ctx;
-
-    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
-    if (!ssl_ctx) {
-        ctx->ssl_ctx = ssl_init_context(allocator);
-    }
-    else {
-        ctx->ssl_ctx = ssl_ctx;
-    }
-    ctx->ssl_ctx->refcount++;
-
-    return serf_bucket_create(type, allocator, ctx);
-}
-
-apr_status_t serf_ssl_set_hostname(serf_ssl_context_t *context,
-                                   const char * hostname)
-{
-#ifdef SSL_set_tlsext_host_name
-    if (SSL_set_tlsext_host_name(context->ssl, hostname) != 1) {
-        ERR_clear_error();
-    }
-#endif
-    return APR_SUCCESS;
-}
-
-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 : SERF_ERROR_SSL_CERT_FAILED;
-}
-
-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 SERF_ERROR_SSL_CERT_FAILED;
-}
-
-
-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 : SERF_ERROR_SSL_CERT_FAILED;
-}
-
-
-serf_bucket_t *serf_bucket_ssl_decrypt_create(
-    serf_bucket_t *stream,
-    serf_ssl_context_t *ssl_ctx,
-    serf_bucket_alloc_t *allocator)
-{
-    serf_bucket_t *bkt;
-    ssl_context_t *ctx;
-
-    bkt = serf_bucket_ssl_create(ssl_ctx, allocator,
-                                 &serf_bucket_type_ssl_decrypt);
-
-    ctx = bkt->data;
-
-    ctx->databuf = &ctx->ssl_ctx->decrypt.databuf;
-    if (ctx->ssl_ctx->decrypt.stream != NULL) {
-        return NULL;
-    }
-    ctx->ssl_ctx->decrypt.stream = stream;
-    ctx->our_stream = &ctx->ssl_ctx->decrypt.stream;
-
-    return bkt;
-}
-
-
-serf_ssl_context_t *serf_bucket_ssl_decrypt_context_get(
-     serf_bucket_t *bucket)
-{
-    ssl_context_t *ctx = bucket->data;
-    return ctx->ssl_ctx;
-}
-
-
-serf_bucket_t *serf_bucket_ssl_encrypt_create(
-    serf_bucket_t *stream,
-    serf_ssl_context_t *ssl_ctx,
-    serf_bucket_alloc_t *allocator)
-{
-    serf_bucket_t *bkt;
-    ssl_context_t *ctx;
-
-    bkt = serf_bucket_ssl_create(ssl_ctx, allocator,
-                                 &serf_bucket_type_ssl_encrypt);
-
-    ctx = bkt->data;
-
-    ctx->databuf = &ctx->ssl_ctx->encrypt.databuf;
-    ctx->our_stream = &ctx->ssl_ctx->encrypt.stream;
-    if (ctx->ssl_ctx->encrypt.stream == NULL) {
-        serf_bucket_t *tmp = serf_bucket_aggregate_create(stream->allocator);
-        serf_bucket_aggregate_append(tmp, stream);
-        ctx->ssl_ctx->encrypt.stream = tmp;
-    }
-    else {
-        bucket_list_t *new_list;
-
-        new_list = serf_bucket_mem_alloc(ctx->ssl_ctx->allocator,
-                                         sizeof(*new_list));
-        new_list->bucket = stream;
-        new_list->next = NULL;
-        if (ctx->ssl_ctx->encrypt.stream_next == NULL) {
-            ctx->ssl_ctx->encrypt.stream_next = new_list;
-        }
-        else {
-            bucket_list_t *scan = ctx->ssl_ctx->encrypt.stream_next;
-
-            while (scan->next != NULL)
-                scan = scan->next;
-            scan->next = new_list;
-        }
-    }
-
-    return bkt;
-}
-
-
-serf_ssl_context_t *serf_bucket_ssl_encrypt_context_get(
-     serf_bucket_t *bucket)
-{
-    ssl_context_t *ctx = bucket->data;
-    return ctx->ssl_ctx;
-}
-
-/* Functions to read a serf_ssl_certificate structure. */
-
-/* Takes a counted length string and escapes any NUL bytes so that
- * it can be used as a C string.  NUL bytes are escaped as 3 characters
- * "\00" (that's a literal backslash).
- * The returned string is allocated in POOL.
- */
-static char *
-pstrdup_escape_nul_bytes(const char *buf, int len, apr_pool_t *pool)
-{
-    int i, nul_count = 0;
-    char *ret;
-
-    /* First determine if there are any nul bytes in the string. */
-    for (i = 0; i < len; i++) {
-        if (buf[i] == '\0')
-            nul_count++;
-    }
-
-    if (nul_count == 0) {
-        /* There aren't so easy case to just copy the string */
-        ret = apr_pstrdup(pool, buf);
-    } else {
-        /* There are so we have to replace nul bytes with escape codes
-         * Proper length is the length of the original string, plus
-         * 2 times the number of nulls (for two digit hex code for
-         * the value) + the trailing null. */
-        char *pos;
-        ret = pos = apr_palloc(pool, len + 2 * nul_count + 1);
-        for (i = 0; i < len; i++) {
-            if (buf[i] != '\0') {
-                *(pos++) = buf[i];
-            } else {
-                *(pos++) = '\\';
-                *(pos++) = '0';
-                *(pos++) = '0';
-            }
-        }
-        *pos = '\0';
-    }
-
-    return ret;
-}
-
-/* Creates a hash_table with keys (E, CN, OU, O, L, ST and C). Any NUL bytes in
-   these fields in the certificate will be escaped as \00. */
-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,
-                     pstrdup_escape_nul_bytes(buf, ret, pool));
-    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,
-                     pstrdup_escape_nul_bytes(buf, ret, pool));
-    ret = X509_NAME_get_text_by_NID(org,
-                                    NID_organizationalUnitName,
-                                    buf, 1024);
-    if (ret != -1)
-        apr_hash_set(tgt, "OU", APR_HASH_KEY_STRING,
-                     pstrdup_escape_nul_bytes(buf, ret, pool));
-    ret = X509_NAME_get_text_by_NID(org,
-                                    NID_organizationName,
-                                    buf, 1024);
-    if (ret != -1)
-        apr_hash_set(tgt, "O", APR_HASH_KEY_STRING,
-                     pstrdup_escape_nul_bytes(buf, ret, pool));
-    ret = X509_NAME_get_text_by_NID(org,
-                                    NID_localityName,
-                                    buf, 1024);
-    if (ret != -1)
-        apr_hash_set(tgt, "L", APR_HASH_KEY_STRING,
-                     pstrdup_escape_nul_bytes(buf, ret, pool));
-    ret = X509_NAME_get_text_by_NID(org,
-                                    NID_stateOrProvinceName,
-                                    buf, 1024);
-    if (ret != -1)
-        apr_hash_set(tgt, "ST", APR_HASH_KEY_STRING,
-                     pstrdup_escape_nul_bytes(buf, ret, pool));
-    ret = X509_NAME_get_text_by_NID(org,
-                                    NID_countryName,
-                                    buf, 1024);
-    if (ret != -1)
-        apr_hash_set(tgt, "C", APR_HASH_KEY_STRING,
-                     pstrdup_escape_nul_bytes(buf, ret, pool));
-
-    return tgt;
-}
-
-
-int serf_ssl_cert_depth(const serf_ssl_certificate_t *cert)
-{
-    return cert->depth;
-}
-
-
-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);
-}
-
-
-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);
-}
-
-
-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;
-    apr_array_header_t *san_arr;
-
-    /* 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);
-
-    /* Get subjectAltNames */
-    if (!get_subject_alt_names(&san_arr, cert->ssl_cert, EscapeNulAndCopy, pool))
-        apr_hash_set(tgt, "subjectAltName", APR_HASH_KEY_STRING, san_arr);
-
-    return tgt;
-}
-
-
-const char *serf_ssl_cert_export(
-    const serf_ssl_certificate_t *cert,
-    apr_pool_t *pool)
-{
-    char *binary_cert;
-    char *encoded_cert;
-    int len;
-    unsigned char *unused;
-
-    /* find the length of the DER encoding. */
-    len = i2d_X509(cert->ssl_cert, NULL);
-    if (len < 0) {
-        return NULL;
-    }
-
-    binary_cert = apr_palloc(pool, len);
-    unused = (unsigned char *)binary_cert;
-    len = i2d_X509(cert->ssl_cert, &unused);  /* unused is incremented  */
-    if (len < 0) {
-        return NULL;
-    }
-
-    encoded_cert = apr_palloc(pool, apr_base64_encode_len(len));
-    apr_base64_encode(encoded_cert, binary_cert, len);
-    
-    return encoded_cert;
-}
-
-/* Disables compression for all SSL sessions. */
-static void disable_compression(serf_ssl_context_t *ssl_ctx)
-{
-#ifdef SSL_OP_NO_COMPRESSION
-    SSL_CTX_set_options(ssl_ctx->ctx, SSL_OP_NO_COMPRESSION);
-#endif
-}
-
-apr_status_t serf_ssl_use_compression(serf_ssl_context_t *ssl_ctx, int enabled)
-{
-    if (enabled) {
-#ifdef SSL_OP_NO_COMPRESSION
-        SSL_clear_options(ssl_ctx->ssl, SSL_OP_NO_COMPRESSION);
-        return APR_SUCCESS;
-#endif
-    } else {
-#ifdef SSL_OP_NO_COMPRESSION
-        SSL_set_options(ssl_ctx->ssl, SSL_OP_NO_COMPRESSION);
-        return APR_SUCCESS;
-#endif
-    }
-
-    return APR_EGENERAL;
-}
-
-static void serf_ssl_destroy_and_data(serf_bucket_t *bucket)
-{
-    ssl_context_t *ctx = bucket->data;
-
-    if (!--ctx->ssl_ctx->refcount) {
-        ssl_free_context(ctx->ssl_ctx);
-    }
-
-    serf_default_destroy_and_data(bucket);
-}
-
-static void serf_ssl_decrypt_destroy_and_data(serf_bucket_t *bucket)
-{
-    ssl_context_t *ctx = bucket->data;
-
-    serf_bucket_destroy(*ctx->our_stream);
-
-    serf_ssl_destroy_and_data(bucket);
-}
-
-static void serf_ssl_encrypt_destroy_and_data(serf_bucket_t *bucket)
-{
-    ssl_context_t *ctx = bucket->data;
-    serf_ssl_context_t *ssl_ctx = ctx->ssl_ctx;
-
-    if (ssl_ctx->encrypt.stream == *ctx->our_stream) {
-        serf_bucket_destroy(*ctx->our_stream);
-        serf_bucket_destroy(ssl_ctx->encrypt.pending);
-
-        /* Reset our encrypted status and databuf. */
-        ssl_ctx->encrypt.status = APR_SUCCESS;
-        ssl_ctx->encrypt.databuf.status = APR_SUCCESS;
-
-        /* Advance to the next stream - if we have one. */
-        if (ssl_ctx->encrypt.stream_next == NULL) {
-            ssl_ctx->encrypt.stream = NULL;
-            ssl_ctx->encrypt.pending = NULL;
-        }
-        else {
-            bucket_list_t *cur;
-
-            cur = ssl_ctx->encrypt.stream_next;
-            ssl_ctx->encrypt.stream = cur->bucket;
-            ssl_ctx->encrypt.pending =
-                serf_bucket_aggregate_create(cur->bucket->allocator);
-            ssl_ctx->encrypt.stream_next = cur->next;
-            serf_bucket_mem_free(ssl_ctx->allocator, cur);
-        }
-    }
-    else {
-        /* Ah, darn.  We haven't sent this one along yet. */
-        return;
-    }
-    serf_ssl_destroy_and_data(bucket);
-}
-
-static apr_status_t serf_ssl_read(serf_bucket_t *bucket,
-                                  apr_size_t requested,
-                                  const char **data, apr_size_t *len)
-{
-    ssl_context_t *ctx = bucket->data;
-
-    return serf_databuf_read(ctx->databuf, requested, data, len);
-}
-
-static apr_status_t serf_ssl_readline(serf_bucket_t *bucket,
-                                      int acceptable, int *found,
-                                      const char **data,
-                                      apr_size_t *len)
-{
-    ssl_context_t *ctx = bucket->data;
-
-    return serf_databuf_readline(ctx->databuf, acceptable, found, data, len);
-}
-
-static apr_status_t serf_ssl_peek(serf_bucket_t *bucket,
-                                  const char **data,
-                                  apr_size_t *len)
-{
-    ssl_context_t *ctx = bucket->data;
-
-    return serf_databuf_peek(ctx->databuf, data, len);
-}
-
-
-const serf_bucket_type_t serf_bucket_type_ssl_encrypt = {
-    "SSLENCRYPT",
-    serf_ssl_read,
-    serf_ssl_readline,
-    serf_default_read_iovec,
-    serf_default_read_for_sendfile,
-    serf_default_read_bucket,
-    serf_ssl_peek,
-    serf_ssl_encrypt_destroy_and_data,
-};
-
-const serf_bucket_type_t serf_bucket_type_ssl_decrypt = {
-    "SSLDECRYPT",
-    serf_ssl_read,
-    serf_ssl_readline,
-    serf_default_read_iovec,
-    serf_default_read_for_sendfile,
-    serf_default_read_bucket,
-    serf_ssl_peek,
-    serf_ssl_decrypt_destroy_and_data,
-};

Copied: vendor/serf/1.3.9/buckets/ssl_buckets.c (from rev 9259, vendor/serf/dist/buckets/ssl_buckets.c)
===================================================================
--- vendor/serf/1.3.9/buckets/ssl_buckets.c	                        (rev 0)
+++ vendor/serf/1.3.9/buckets/ssl_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,1987 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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.
+ * ====================================================================
+ *
+ * ----
+ *
+ * Originally developed by Aaron Bannert and Justin Erenkrantz, eBuilt.
+ */
+
+#include <apr_pools.h>
+#include <apr_network_io.h>
+#include <apr_portable.h>
+#include <apr_strings.h>
+#include <apr_base64.h>
+#include <apr_version.h>
+#include <apr_atomic.h>
+
+#include "serf.h"
+#include "serf_private.h"
+#include "serf_bucket_util.h"
+
+#include <openssl/bio.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/pkcs12.h>
+#include <openssl/x509v3.h>
+
+#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 */
+
+#ifndef APR_ARRAY_PUSH
+#define APR_ARRAY_PUSH(ary,type) (*((type *)apr_array_push(ary)))
+#endif
+
+#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L
+#define USE_OPENSSL_1_1_API
+#endif
+
+
+/*
+ * Here's an overview of the SSL bucket's relationship to OpenSSL and serf.
+ *
+ * HTTP request:  SSLENCRYPT(REQUEST)
+ *   [context.c reads from SSLENCRYPT and writes out to the socket]
+ * HTTP response: RESPONSE(SSLDECRYPT(SOCKET))
+ *   [handler function reads from RESPONSE which in turn reads from SSLDECRYPT]
+ *
+ * HTTP request read call path:
+ *
+ * write_to_connection
+ *  |- serf_bucket_read on SSLENCRYPT
+ *    |- serf_ssl_read
+ *      |- serf_databuf_read
+ *        |- common_databuf_prep
+ *          |- ssl_encrypt
+ *            |- 1. Try to read pending encrypted data; If available, return.
+ *            |- 2. Try to read from ctx->stream [REQUEST bucket]
+ *            |- 3. Call SSL_write with read data
+ *              |- ...
+ *                |- bio_bucket_read can be called
+ *                |- bio_bucket_write with encrypted data
+ *                  |- store in sink
+ *            |- 4. If successful, read pending encrypted data and return.
+ *            |- 5. If fails, place read data back in ctx->stream
+ *
+ * HTTP response read call path:
+ *
+ * read_from_connection
+ *  |- acceptor
+ *  |- handler
+ *    |- ...
+ *      |- serf_bucket_read(SSLDECRYPT)
+ *        |- serf_ssl_read
+ *          |- serf_databuf_read
+ *            |- ssl_decrypt
+ *              |- 1. SSL_read() for pending decrypted data; if any, return.
+ *              |- 2. Try to read from ctx->stream [SOCKET bucket]
+ *              |- 3. Append data to ssl_ctx->source
+ *              |- 4. Call SSL_read()
+ *                |- ...
+ *                  |- bio_bucket_write can be called
+ *                  |- bio_bucket_read
+ *                    |- read data from ssl_ctx->source
+ *              |- If data read, return it.
+ *              |- If an error, set the STATUS value and return.
+ *
+ */
+
+typedef struct bucket_list {
+    serf_bucket_t *bucket;
+    struct bucket_list *next;
+} bucket_list_t;
+
+typedef struct {
+    /* Helper to read data. Wraps stream. */
+    serf_databuf_t databuf;
+
+    /* Our source for more data. */
+    serf_bucket_t *stream;
+
+    /* The next set of buckets */
+    bucket_list_t *stream_next;
+
+    /* The status of the last thing we read. */
+    apr_status_t status;
+    apr_status_t exhausted;
+    int exhausted_reset;
+
+    /* Data we've read but not processed. */
+    serf_bucket_t *pending;
+} serf_ssl_stream_t;
+
+struct serf_ssl_context_t {
+    /* How many open buckets refer to this context. */
+    int refcount;
+
+    /* The pool that this context uses. */
+    apr_pool_t *pool;
+
+    /* The allocator associated with the above pool. */
+    serf_bucket_alloc_t *allocator;
+
+    /* Internal OpenSSL parameters */
+    SSL_CTX *ctx;
+    SSL *ssl;
+    BIO *bio;
+    BIO_METHOD *biom;
+
+    serf_ssl_stream_t encrypt;
+    serf_ssl_stream_t decrypt;
+
+    /* Client cert callbacks */
+    serf_ssl_need_client_cert_t cert_callback;
+    void *cert_userdata;
+    apr_pool_t *cert_cache_pool;
+    const char *cert_file_success;
+
+    /* Client cert PW callbacks */
+    serf_ssl_need_cert_password_t cert_pw_callback;
+    void *cert_pw_userdata;
+    apr_pool_t *cert_pw_cache_pool;
+    const char *cert_pw_success;
+
+    /* Server cert callbacks */
+    serf_ssl_need_server_cert_t server_cert_callback;
+    serf_ssl_server_cert_chain_cb_t server_cert_chain_callback;
+    void *server_cert_userdata;
+
+    const char *cert_path;
+
+    X509 *cached_cert;
+    EVP_PKEY *cached_cert_pw;
+
+    apr_status_t pending_err;
+
+    /* Status of a fatal error, returned on subsequent encrypt or decrypt
+       requests. */
+    apr_status_t fatal_err;
+};
+
+typedef struct {
+    /* The bucket-independent ssl context that this bucket is associated with */
+    serf_ssl_context_t *ssl_ctx;
+
+    /* Pointer to the 'right' databuf. */
+    serf_databuf_t *databuf;
+
+    /* Pointer to our stream, so we can find it later. */
+    serf_bucket_t **our_stream;
+} ssl_context_t;
+
+struct serf_ssl_certificate_t {
+    X509 *ssl_cert;
+    int depth;
+};
+
+static void disable_compression(serf_ssl_context_t *ssl_ctx);
+static char *
+    pstrdup_escape_nul_bytes(const char *buf, int len, apr_pool_t *pool);
+
+#if SSL_VERBOSE
+/* Log all ssl alerts that we receive from the server. */
+static void
+apps_ssl_info_callback(const SSL *s, int where, int ret)
+{
+    const char *str;
+    int w;
+    w = where & ~SSL_ST_MASK;
+
+    if (w & SSL_ST_CONNECT)
+        str = "SSL_connect";
+    else if (w & SSL_ST_ACCEPT)
+        str = "SSL_accept";
+    else
+        str = "undefined";
+
+    if (where & SSL_CB_LOOP) {
+        serf__log(SSL_VERBOSE, __FILE__, "%s:%s\n", str,
+                  SSL_state_string_long(s));
+    }
+    else if (where & SSL_CB_ALERT) {
+        str = (where & SSL_CB_READ) ? "read" : "write";
+        serf__log(SSL_VERBOSE, __FILE__, "SSL3 alert %s:%s:%s\n",
+               str,
+               SSL_alert_type_string_long(ret),
+               SSL_alert_desc_string_long(ret));
+    }
+    else if (where & SSL_CB_EXIT) {
+        if (ret == 0)
+            serf__log(SSL_VERBOSE, __FILE__, "%s:failed in %s\n", str,
+                      SSL_state_string_long(s));
+        else if (ret < 0) {
+            serf__log(SSL_VERBOSE, __FILE__, "%s:error in %s\n", str,
+                      SSL_state_string_long(s));
+        }
+    }
+}
+#endif
+
+static void bio_set_data(BIO *bio, void *data)
+{
+#ifdef USE_OPENSSL_1_1_API
+    BIO_set_data(bio, data);
+#else
+    bio->ptr = data;
+#endif
+}
+
+static void *bio_get_data(BIO *bio)
+{
+#ifdef USE_OPENSSL_1_1_API
+    return BIO_get_data(bio);
+#else
+    return bio->ptr;
+#endif
+}
+
+/* Returns the amount read. */
+static int bio_bucket_read(BIO *bio, char *in, int inlen)
+{
+    serf_ssl_context_t *ctx = bio_get_data(bio);
+    const char *data;
+    apr_status_t status;
+    apr_size_t len;
+
+    serf__log(SSL_VERBOSE, __FILE__, "bio_bucket_read called for %d bytes\n",
+              inlen);
+
+    if (ctx->encrypt.status == SERF_ERROR_WAIT_CONN
+        && BIO_should_read(ctx->bio)) {
+        serf__log(SSL_VERBOSE, __FILE__,
+                  "bio_bucket_read waiting: (%d %d %d)\n",
+           BIO_should_retry(ctx->bio), BIO_should_read(ctx->bio),
+           BIO_get_retry_flags(ctx->bio));
+        /* Falling back... */
+        ctx->encrypt.exhausted_reset = 1;
+        BIO_clear_retry_flags(bio);
+    }
+
+    status = serf_bucket_read(ctx->decrypt.pending, inlen, &data, &len);
+
+    ctx->decrypt.status = status;
+
+    serf__log(SSL_VERBOSE, __FILE__, "bio_bucket_read received %d bytes (%d)\n",
+              len, status);
+
+    if (!SERF_BUCKET_READ_ERROR(status)) {
+        /* Oh suck. */
+        if (len) {
+            memcpy(in, data, len);
+            return len;
+        }
+        if (APR_STATUS_IS_EOF(status)) {
+            BIO_set_retry_read(bio);
+            return -1;
+        }
+    }
+
+    return -1;
+}
+
+/* Returns the amount written. */
+static int bio_bucket_write(BIO *bio, const char *in, int inl)
+{
+    serf_ssl_context_t *ctx = bio_get_data(bio);
+    serf_bucket_t *tmp;
+
+    serf__log(SSL_VERBOSE, __FILE__, "bio_bucket_write called for %d bytes\n",
+              inl);
+
+    if (ctx->encrypt.status == SERF_ERROR_WAIT_CONN
+        && !BIO_should_read(ctx->bio)) {
+        serf__log(SSL_VERBOSE, __FILE__,
+                  "bio_bucket_write waiting: (%d %d %d)\n",
+           BIO_should_retry(ctx->bio), BIO_should_read(ctx->bio),
+           BIO_get_retry_flags(ctx->bio));
+        /* Falling back... */
+        ctx->encrypt.exhausted_reset = 1;
+        BIO_clear_retry_flags(bio);
+    }
+
+    tmp = serf_bucket_simple_copy_create(in, inl,
+                                         ctx->encrypt.pending->allocator);
+
+    serf_bucket_aggregate_append(ctx->encrypt.pending, tmp);
+
+    return inl;
+}
+
+/* Returns the amount read. */
+static int bio_file_read(BIO *bio, char *in, int inlen)
+{
+    apr_file_t *file = bio_get_data(bio);
+    apr_status_t status;
+    apr_size_t len;
+
+    len = inlen;
+    status = apr_file_read(file, in, &len);
+
+    if (!SERF_BUCKET_READ_ERROR(status)) {
+        /* Oh suck. */
+        if (APR_STATUS_IS_EOF(status)) {
+            return -1;
+        } else {
+            return len;
+        }
+    }
+
+    return -1;
+}
+
+/* Returns the amount written. */
+static int bio_file_write(BIO *bio, const char *in, int inl)
+{
+    apr_file_t *file = bio_get_data(bio);
+    apr_size_t nbytes;
+
+    BIO_clear_retry_flags(bio);
+
+    nbytes = inl;
+    apr_file_write(file, in, &nbytes);
+
+    return nbytes;
+}
+
+static int bio_file_gets(BIO *bio, char *in, int inlen)
+{
+    apr_file_t *file = bio_get_data(bio);
+    apr_status_t status;
+
+    status = apr_file_gets(in, inlen, file);
+
+    if (! status) {
+        return (int)strlen(in);
+    } else if (APR_STATUS_IS_EOF(status)) {
+        return 0;
+    } else {
+        return -1; /* Signal generic error */
+    }
+}
+
+static int bio_bucket_create(BIO *bio)
+{
+#ifdef USE_OPENSSL_1_1_API
+    BIO_set_shutdown(bio, 1);
+    BIO_set_init(bio, 1);
+    BIO_set_data(bio, NULL);
+#else
+    bio->shutdown = 1;
+    bio->init = 1;
+    bio->num = -1;
+    bio->ptr = NULL;
+#endif
+
+    return 1;
+}
+
+static int bio_bucket_destroy(BIO *bio)
+{
+    /* Did we already free this? */
+    if (bio == NULL) {
+        return 0;
+    }
+
+    return 1;
+}
+
+static long bio_bucket_ctrl(BIO *bio, int cmd, long num, void *ptr)
+{
+    long ret = 1;
+
+    switch (cmd) {
+    default:
+        /* abort(); */
+        break;
+    case BIO_CTRL_FLUSH:
+        /* At this point we can't force a flush. */
+        break;
+    case BIO_CTRL_PUSH:
+    case BIO_CTRL_POP:
+        ret = 0;
+        break;
+    }
+    return ret;
+}
+
+#ifndef USE_OPENSSL_1_1_API
+static BIO_METHOD bio_bucket_method = {
+    BIO_TYPE_MEM,
+    "Serf SSL encryption and decryption buckets",
+    bio_bucket_write,
+    bio_bucket_read,
+    NULL,                        /* Is this called? */
+    NULL,                        /* Is this called? */
+    bio_bucket_ctrl,
+    bio_bucket_create,
+    bio_bucket_destroy,
+#ifdef OPENSSL_VERSION_NUMBER
+    NULL /* sslc does not have the callback_ctrl field */
+#endif
+};
+
+static BIO_METHOD bio_file_method = {
+    BIO_TYPE_FILE,
+    "Wrapper around APR file structures",
+    bio_file_write,
+    bio_file_read,
+    NULL,                        /* Is this called? */
+    bio_file_gets,               /* Is this called? */
+    bio_bucket_ctrl,
+    bio_bucket_create,
+    bio_bucket_destroy,
+#ifdef OPENSSL_VERSION_NUMBER
+    NULL /* sslc does not have the callback_ctrl field */
+#endif
+};
+#endif
+
+static BIO_METHOD *bio_meth_bucket_new(void)
+{
+    BIO_METHOD *biom = NULL;
+
+#ifdef USE_OPENSSL_1_1_API
+    biom = BIO_meth_new(BIO_TYPE_MEM,
+                        "Serf SSL encryption and decryption buckets");
+    if (biom) {
+        BIO_meth_set_write(biom, bio_bucket_write);
+        BIO_meth_set_read(biom, bio_bucket_read);
+        BIO_meth_set_ctrl(biom, bio_bucket_ctrl);
+        BIO_meth_set_create(biom, bio_bucket_create);
+        BIO_meth_set_destroy(biom, bio_bucket_destroy);
+    }
+#else
+    biom = &bio_bucket_method;
+#endif
+
+    return biom;
+}
+
+static BIO_METHOD *bio_meth_file_new(void)
+{
+    BIO_METHOD *biom = NULL;
+
+#ifdef USE_OPENSSL_1_1_API
+    biom = BIO_meth_new(BIO_TYPE_FILE,
+                        "Wrapper around APR file structures");
+    BIO_meth_set_write(biom, bio_file_write);
+    BIO_meth_set_read(biom, bio_file_read);
+    BIO_meth_set_gets(biom, bio_file_gets);
+    BIO_meth_set_ctrl(biom, bio_bucket_ctrl);
+    BIO_meth_set_create(biom, bio_bucket_create);
+    BIO_meth_set_destroy(biom, bio_bucket_destroy);
+#else
+    biom = &bio_file_method;
+#endif
+
+    return biom;
+}
+
+static void bio_meth_free(BIO_METHOD *biom)
+{
+#ifdef USE_OPENSSL_1_1_API
+    BIO_meth_free(biom);
+#endif
+}
+
+typedef enum san_copy_t {
+    EscapeNulAndCopy = 0,
+    ErrorOnNul = 1,
+} san_copy_t;
+
+
+static apr_status_t
+get_subject_alt_names(apr_array_header_t **san_arr, X509 *ssl_cert,
+                      san_copy_t copy_action, apr_pool_t *pool)
+{
+    STACK_OF(GENERAL_NAME) *names;
+
+    /* assert: copy_action == ErrorOnNul || (san_arr && pool) */
+
+    if (san_arr) {
+        *san_arr = NULL;
+    }
+
+    /* Get subjectAltNames */
+    names = X509_get_ext_d2i(ssl_cert, NID_subject_alt_name, NULL, NULL);
+    if (names) {
+        int names_count = sk_GENERAL_NAME_num(names);
+        int name_idx;
+
+        if (san_arr)
+            *san_arr = apr_array_make(pool, names_count, sizeof(char*));
+        for (name_idx = 0; name_idx < names_count; name_idx++) {
+            char *p = NULL;
+            GENERAL_NAME *nm = sk_GENERAL_NAME_value(names, name_idx);
+
+            switch (nm->type) {
+                case GEN_DNS:
+                    if (copy_action == ErrorOnNul &&
+                        strlen(nm->d.ia5->data) != nm->d.ia5->length)
+                        return SERF_ERROR_SSL_CERT_FAILED;
+                    if (san_arr && *san_arr)
+                        p = pstrdup_escape_nul_bytes((const char *)nm->d.ia5->data,
+                                                     nm->d.ia5->length,
+                                                     pool);
+                    break;
+                default:
+                    /* Don't know what to do - skip. */
+                    break;
+            }
+
+            if (p) {
+                APR_ARRAY_PUSH(*san_arr, char*) = p;
+            }
+        }
+        sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
+    }
+    
+    return APR_SUCCESS;
+}
+
+static apr_status_t validate_cert_hostname(X509 *server_cert, apr_pool_t *pool)
+{
+    char buf[1024];
+    int length;
+    apr_status_t ret;
+
+    ret = get_subject_alt_names(NULL, server_cert, ErrorOnNul, NULL);
+    if (ret) {
+      return ret;
+    } else {
+        /* Fail if the subject's CN field contains \0 characters. */
+        X509_NAME *subject = X509_get_subject_name(server_cert);
+        if (!subject)
+            return SERF_ERROR_SSL_CERT_FAILED;
+
+        length = X509_NAME_get_text_by_NID(subject, NID_commonName, buf, 1024);
+        if (length != -1)
+            if (strlen(buf) != length)
+                return SERF_ERROR_SSL_CERT_FAILED;
+    }
+
+    return APR_SUCCESS;
+}
+
+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;
+    apr_status_t status;
+
+    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:
+            case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+            case X509_V_ERR_CERT_UNTRUSTED:
+            case X509_V_ERR_INVALID_CA:
+            case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+                    failures |= SERF_SSL_CERT_UNKNOWNCA;
+                    break;
+            case X509_V_ERR_CERT_REVOKED:
+                    failures |= SERF_SSL_CERT_REVOKED;
+                    break;
+            default:
+                    failures |= SERF_SSL_CERT_UNKNOWN_FAILURE;
+                    break;
+        }
+    }
+
+    /* Validate hostname */
+    status = validate_cert_hostname(server_cert, ctx->pool);
+    if (status)
+        failures |= SERF_SSL_CERT_UNKNOWN_FAILURE;
+
+    /* 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)) {
+        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;
+        cert->depth = depth;
+
+        /* Callback for further verification. */
+        status = ctx->server_cert_callback(ctx->server_cert_userdata,
+                                           failures, cert);
+        if (status == APR_SUCCESS)
+            cert_valid = 1;
+        else {
+            /* Even if openssl found the certificate valid, the application
+               told us to reject it. */
+            cert_valid = 0;
+            /* Pass the error back to the caller through the context-run. */
+            ctx->pending_err = status;
+        }
+        apr_pool_destroy(subpool);
+    }
+
+    if (ctx->server_cert_chain_callback
+        && (depth == 0 || failures)) {
+        STACK_OF(X509) *chain;
+        const serf_ssl_certificate_t **certs;
+        int certs_len;
+        apr_pool_t *subpool;
+
+        apr_pool_create(&subpool, ctx->pool);
+
+        /* Borrow the chain to pass to the callback. */
+        chain = X509_STORE_CTX_get_chain(store_ctx);
+
+        /* If the chain can't be retrieved, just pass the current
+           certificate. */
+        /* ### can this actually happen with _get_chain() ?  */
+        if (!chain) {
+            serf_ssl_certificate_t *cert = apr_palloc(subpool, sizeof(*cert));
+
+            cert->ssl_cert = server_cert;
+            cert->depth = depth;
+
+            /* Room for the server_cert and a trailing NULL.  */
+            certs = apr_palloc(subpool, sizeof(*certs) * 2);
+            certs[0] = cert;
+
+            certs_len = 1;
+        } else {
+            int i;
+
+            certs_len = sk_X509_num(chain);
+
+            /* Room for all the certs and a trailing NULL.  */
+            certs = apr_palloc(subpool, sizeof(*certs) * (certs_len + 1));
+            for (i = 0; i < certs_len; ++i) {
+                serf_ssl_certificate_t *cert;
+
+                cert = apr_palloc(subpool, sizeof(*cert));
+                cert->ssl_cert = sk_X509_value(chain, i);
+                cert->depth = i;
+
+                certs[i] = cert;
+            }
+        }
+        certs[certs_len] = NULL;
+
+        /* Callback for further verification. */
+        status = ctx->server_cert_chain_callback(ctx->server_cert_userdata,
+                                                 failures, depth,
+                                                 certs, certs_len);
+        if (status == APR_SUCCESS) {
+            cert_valid = 1;
+        } else {
+            /* Even if openssl found the certificate valid, the application
+               told us to reject it. */
+            cert_valid = 0;
+            /* Pass the error back to the caller through the context-run. */
+            ctx->pending_err = status;
+        }
+
+        apr_pool_destroy(subpool);
+    }
+
+    /* Return a specific error if the server certificate is not accepted by
+       OpenSSL and the application has not set callbacks to override this. */
+    if (!cert_valid &&
+        !ctx->server_cert_chain_callback &&
+        !ctx->server_cert_callback)
+    {
+        ctx->pending_err = SERF_ERROR_SSL_CERT_FAILED;
+    }
+        
+    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)
+{
+    serf_ssl_context_t *ctx = baton;
+    apr_size_t priv_len;
+    apr_status_t status;
+    const char *data;
+    int ssl_len;
+
+    if (ctx->fatal_err)
+        return ctx->fatal_err;
+
+    serf__log(SSL_VERBOSE, __FILE__, "ssl_decrypt: begin %d\n", bufsize);
+
+    /* Is there some data waiting to be read? */
+    ssl_len = SSL_read(ctx->ssl, buf, bufsize);
+    if (ssl_len > 0) {
+        serf__log(SSL_VERBOSE, __FILE__,
+                  "ssl_decrypt: %d bytes (%d); status: %d; flags: %d\n",
+                  ssl_len, bufsize, ctx->decrypt.status,
+                  BIO_get_retry_flags(ctx->bio));
+        *len = ssl_len;
+        return APR_SUCCESS;
+    }
+
+    status = serf_bucket_read(ctx->decrypt.stream, bufsize, &data, &priv_len);
+
+    if (!SERF_BUCKET_READ_ERROR(status) && priv_len) {
+        serf_bucket_t *tmp;
+
+        serf__log(SSL_VERBOSE, __FILE__,
+                  "ssl_decrypt: read %d bytes (%d); status: %d\n",
+                  priv_len, bufsize, status);
+
+        tmp = serf_bucket_simple_copy_create(data, priv_len,
+                                             ctx->decrypt.pending->allocator);
+
+        serf_bucket_aggregate_append(ctx->decrypt.pending, tmp);
+
+        ssl_len = SSL_read(ctx->ssl, buf, bufsize);
+        if (ssl_len < 0) {
+            int ssl_err;
+
+            ssl_err = SSL_get_error(ctx->ssl, ssl_len);
+            switch (ssl_err) {
+            case SSL_ERROR_SYSCALL:
+                *len = 0;
+                /* Return the underlying network error that caused OpenSSL
+                   to fail. ### This can be a crypt error! */
+                status = ctx->decrypt.status;
+                break;
+            case SSL_ERROR_WANT_READ:
+            case SSL_ERROR_WANT_WRITE:
+                *len = 0;
+                status = APR_EAGAIN;
+                break;
+            case SSL_ERROR_SSL:
+                *len = 0;
+                if (ctx->pending_err) {
+                    status = ctx->pending_err;
+                    ctx->pending_err = 0;
+                } else {
+                    ctx->fatal_err = status = SERF_ERROR_SSL_COMM_FAILED;
+                }
+                break;
+            default:
+                *len = 0;
+                ctx->fatal_err = status = SERF_ERROR_SSL_COMM_FAILED;
+                break;
+            }
+        } else if (ssl_len == 0) {
+            /* The server shut down the connection. */
+            int ssl_err, shutdown;
+            *len = 0;
+
+            /* Check for SSL_RECEIVED_SHUTDOWN */
+            shutdown = SSL_get_shutdown(ctx->ssl);
+            /* Check for SSL_ERROR_ZERO_RETURN */
+            ssl_err = SSL_get_error(ctx->ssl, ssl_len);
+
+            if (shutdown == SSL_RECEIVED_SHUTDOWN &&
+                ssl_err == SSL_ERROR_ZERO_RETURN) {
+                /* The server closed the SSL session. While this doesn't
+                necessary mean the connection is closed, let's close
+                it here anyway.
+                We can optimize this later. */
+                serf__log(SSL_VERBOSE, __FILE__, 
+                          "ssl_decrypt: SSL read error: server"
+                          " shut down connection!\n");
+                status = APR_EOF;
+            } else {
+                /* A fatal error occurred. */
+                ctx->fatal_err = status = SERF_ERROR_SSL_COMM_FAILED;
+            }
+        } else {
+            *len = ssl_len;
+            serf__log(SSL_MSG_VERBOSE, __FILE__, 
+                      "---\n%.*s\n-(%d)-\n", *len, buf, *len);
+        }
+    }
+    else {
+        *len = 0;
+    }
+    serf__log(SSL_VERBOSE, __FILE__, 
+              "ssl_decrypt: %d %d %d\n", status, *len,
+              BIO_get_retry_flags(ctx->bio));
+
+    return status;
+}
+
+/* This function reads a decrypted stream and returns an encrypted stream. */
+static apr_status_t ssl_encrypt(void *baton, apr_size_t bufsize,
+                                char *buf, apr_size_t *len)
+{
+    const char *data;
+    apr_size_t interim_bufsize;
+    serf_ssl_context_t *ctx = baton;
+    apr_status_t status;
+
+    if (ctx->fatal_err)
+        return ctx->fatal_err;
+
+    serf__log(SSL_VERBOSE, __FILE__, "ssl_encrypt: begin %d\n", bufsize);
+
+    /* Try to read already encrypted but unread data first. */
+    status = serf_bucket_read(ctx->encrypt.pending, bufsize, &data, len);
+    if (SERF_BUCKET_READ_ERROR(status)) {
+        return status;
+    }
+
+    /* Aha, we read something.  Return that now. */
+    if (*len) {
+        memcpy(buf, data, *len);
+        if (APR_STATUS_IS_EOF(status)) {
+            status = APR_SUCCESS;
+        }
+
+        serf__log(SSL_VERBOSE, __FILE__, "ssl_encrypt: %d %d %d (quick read)\n",
+                  status, *len, BIO_get_retry_flags(ctx->bio));
+
+        return status;
+    }
+
+    if (BIO_should_retry(ctx->bio) && BIO_should_write(ctx->bio)) {
+        serf__log(SSL_VERBOSE, __FILE__,
+                  "ssl_encrypt: %d %d %d (should write exit)\n",
+                  status, *len, BIO_get_retry_flags(ctx->bio));
+
+        return APR_EAGAIN;
+    }
+
+    /* If we were previously blocked, unblock ourselves now. */
+    if (BIO_should_read(ctx->bio)) {
+        serf__log(SSL_VERBOSE, __FILE__, "ssl_encrypt: reset %d %d (%d %d %d)\n",
+                  status, ctx->encrypt.status,
+                  BIO_should_retry(ctx->bio), BIO_should_read(ctx->bio),
+                  BIO_get_retry_flags(ctx->bio));
+
+        ctx->encrypt.status = APR_SUCCESS;
+        ctx->encrypt.exhausted_reset = 0;
+    }
+
+    /* Oh well, read from our stream now. */
+    interim_bufsize = bufsize;
+    do {
+        apr_size_t interim_len;
+
+        if (!ctx->encrypt.status) {
+            struct iovec vecs[64];
+            int vecs_read;
+
+            status = serf_bucket_read_iovec(ctx->encrypt.stream,
+                                            interim_bufsize, 64, vecs,
+                                            &vecs_read);
+
+            if (!SERF_BUCKET_READ_ERROR(status) && vecs_read) {
+                char *vecs_data;
+                int i, cur, vecs_data_len;
+                int ssl_len;
+
+                /* Combine the buffers of the iovec into one buffer, as
+                   that is with SSL_write requires. */
+                vecs_data_len = 0;
+                for (i = 0; i < vecs_read; i++) {
+                    vecs_data_len += vecs[i].iov_len;
+                }
+
+                vecs_data = serf_bucket_mem_alloc(ctx->allocator,
+                                                  vecs_data_len);
+
+                cur = 0;
+                for (i = 0; i < vecs_read; i++) {
+                    memcpy(vecs_data + cur, vecs[i].iov_base, vecs[i].iov_len);
+                    cur += vecs[i].iov_len;
+                }
+
+                interim_bufsize -= vecs_data_len;
+                interim_len = vecs_data_len;
+
+                serf__log(SSL_VERBOSE, __FILE__,
+                          "ssl_encrypt: bucket read %d bytes; "\
+                          "status %d\n", interim_len, status);
+                serf__log(SSL_MSG_VERBOSE, __FILE__, "---\n%.*s\n-(%d)-\n",
+                          interim_len, vecs_data, interim_len);
+
+                /* Stash our status away. */
+                ctx->encrypt.status = status;
+
+                ssl_len = SSL_write(ctx->ssl, vecs_data, interim_len);
+
+                serf__log(SSL_VERBOSE, __FILE__, 
+                          "ssl_encrypt: SSL write: %d\n", ssl_len);
+
+                /* If we failed to write... */
+                if (ssl_len < 0) {
+                    int ssl_err;
+
+                    /* Ah, bugger. We need to put that data back.
+                       Note: use the copy here, we do not own the original iovec
+                       data buffer so it will be freed on next read. */
+                    serf_bucket_t *vecs_copy =
+                        serf_bucket_simple_own_create(vecs_data,
+                                                      vecs_data_len,
+                                                      ctx->allocator);
+                    serf_bucket_aggregate_prepend(ctx->encrypt.stream,
+                                                  vecs_copy);
+
+                    ssl_err = SSL_get_error(ctx->ssl, ssl_len);
+
+                    serf__log(SSL_VERBOSE, __FILE__, 
+                              "ssl_encrypt: SSL write error: %d\n", ssl_err);
+
+                    if (ssl_err == SSL_ERROR_SYSCALL) {
+                        /* Return the underlying network error that caused OpenSSL
+                           to fail. ### This can be a decrypt error! */
+                        status = ctx->encrypt.status;
+                        if (SERF_BUCKET_READ_ERROR(status)) {
+                            return status;
+                        }
+                    }
+                    else {
+                        /* Oh, no. */
+                        if (ssl_err == SSL_ERROR_WANT_READ) {
+                            status = SERF_ERROR_WAIT_CONN;
+                        }
+                        else {
+                            ctx->fatal_err = status =
+                                SERF_ERROR_SSL_COMM_FAILED;
+                        }
+                    }
+
+                    serf__log(SSL_VERBOSE, __FILE__, 
+                              "ssl_encrypt: SSL write error: %d %d\n",
+                              status, *len);
+                } else {
+                    /* We're done with this data. */
+                    serf_bucket_mem_free(ctx->allocator, vecs_data);
+                }
+            }
+        }
+        else {
+            interim_len = 0;
+            *len = 0;
+            status = ctx->encrypt.status;
+        }
+
+    } while (!status && interim_bufsize);
+
+    /* Okay, we exhausted our underlying stream. */
+    if (!SERF_BUCKET_READ_ERROR(status)) {
+        apr_status_t agg_status;
+        struct iovec vecs[64];
+        int vecs_read, i;
+
+        /* We read something! */
+        agg_status = serf_bucket_read_iovec(ctx->encrypt.pending, bufsize,
+                                            64, vecs, &vecs_read);
+        *len = 0;
+        for (i = 0; i < vecs_read; i++) {
+            memcpy(buf + *len, vecs[i].iov_base, vecs[i].iov_len);
+            *len += vecs[i].iov_len;
+        }
+
+        serf__log(SSL_VERBOSE, __FILE__,
+                  "ssl_encrypt read agg: %d %d %d %d\n", status, agg_status,
+            ctx->encrypt.status, *len);
+
+        if (!agg_status) {
+            status = agg_status;
+        }
+    }
+
+    if (status == SERF_ERROR_WAIT_CONN
+        && BIO_should_retry(ctx->bio) && BIO_should_read(ctx->bio)) {
+        ctx->encrypt.exhausted = ctx->encrypt.status;
+        ctx->encrypt.status = SERF_ERROR_WAIT_CONN;
+    }
+
+    serf__log(SSL_VERBOSE, __FILE__,
+              "ssl_encrypt finished: %d %d (%d %d %d)\n", status, *len,
+              BIO_should_retry(ctx->bio), BIO_should_read(ctx->bio),
+              BIO_get_retry_flags(ctx->bio));
+
+    return status;
+}
+
+#if APR_HAS_THREADS && !defined(USE_OPENSSL_1_1_API)
+static apr_pool_t *ssl_pool;
+static apr_thread_mutex_t **ssl_locks;
+
+typedef struct CRYPTO_dynlock_value {
+    apr_thread_mutex_t *lock;
+} CRYPTO_dynlock_value;
+
+static CRYPTO_dynlock_value *ssl_dyn_create(const char* file, int line)
+{
+    CRYPTO_dynlock_value *l;
+    apr_status_t rv;
+
+    l = apr_palloc(ssl_pool, sizeof(CRYPTO_dynlock_value));
+    rv = apr_thread_mutex_create(&l->lock, APR_THREAD_MUTEX_DEFAULT, ssl_pool);
+    if (rv != APR_SUCCESS) {
+        /* FIXME: return error here */
+    }
+    return l;
+}
+
+static void ssl_dyn_lock(int mode, CRYPTO_dynlock_value *l, const char *file,
+                         int line)
+{
+    if (mode & CRYPTO_LOCK) {
+        apr_thread_mutex_lock(l->lock);
+    }
+    else if (mode & CRYPTO_UNLOCK) {
+        apr_thread_mutex_unlock(l->lock);
+    }
+}
+
+static void ssl_dyn_destroy(CRYPTO_dynlock_value *l, const char *file,
+                            int line)
+{
+    apr_thread_mutex_destroy(l->lock);
+}
+
+static void ssl_lock(int mode, int n, const char *file, int line)
+{
+    if (mode & CRYPTO_LOCK) {
+        apr_thread_mutex_lock(ssl_locks[n]);
+    }
+    else if (mode & CRYPTO_UNLOCK) {
+        apr_thread_mutex_unlock(ssl_locks[n]);
+    }
+}
+
+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
+
+#if !APR_VERSION_AT_LEAST(1,0,0)
+#define apr_atomic_cas32(mem, with, cmp) apr_atomic_cas(mem, with, cmp)
+#endif
+
+enum ssl_init_e
+{
+   INIT_UNINITIALIZED = 0,
+   INIT_BUSY = 1,
+   INIT_DONE = 2
+};
+
+static volatile apr_uint32_t have_init_ssl = INIT_UNINITIALIZED;
+
+static void init_ssl_libraries(void)
+{
+    apr_uint32_t val;
+
+    val = apr_atomic_cas32(&have_init_ssl, INIT_BUSY, INIT_UNINITIALIZED);
+
+    if (!val) {
+#if APR_HAS_THREADS && !defined(USE_OPENSSL_1_1_API)
+        int i, numlocks;
+#endif
+
+#ifdef SSL_VERBOSE
+        /* Warn when compile-time and run-time version of OpenSSL differ in
+           major/minor version number. */
+        long libver = SSLeay();
+
+        if ((libver ^ OPENSSL_VERSION_NUMBER) & 0xFFF00000) {
+            serf__log(SSL_VERBOSE, __FILE__,
+                      "Warning: OpenSSL library version mismatch, compile-time "
+                      "was %lx, runtime is %lx.\n",
+                      OPENSSL_VERSION_NUMBER, libver);
+        }
+#endif
+
+#ifdef USE_OPENSSL_1_1_API
+        OPENSSL_malloc_init();
+#else
+        CRYPTO_malloc_init();
+#endif
+        ERR_load_crypto_strings();
+        SSL_load_error_strings();
+        SSL_library_init();
+        OpenSSL_add_all_algorithms();
+
+#if APR_HAS_THREADS && !defined(USE_OPENSSL_1_1_API)
+        numlocks = CRYPTO_num_locks();
+        apr_pool_create(&ssl_pool, NULL);
+        ssl_locks = apr_palloc(ssl_pool, sizeof(apr_thread_mutex_t*)*numlocks);
+        for (i = 0; i < numlocks; i++) {
+            apr_status_t rv;
+
+            /* Intraprocess locks don't /need/ a filename... */
+            rv = apr_thread_mutex_create(&ssl_locks[i],
+                                         APR_THREAD_MUTEX_DEFAULT, ssl_pool);
+            if (rv != APR_SUCCESS) {
+                /* FIXME: error out here */
+            }
+        }
+        CRYPTO_set_locking_callback(ssl_lock);
+        CRYPTO_set_id_callback(ssl_id);
+        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
+        apr_atomic_cas32(&have_init_ssl, INIT_DONE, INIT_BUSY);
+    }
+  else
+    {
+        /* Make sure we don't continue before the initialization in another
+           thread has completed */
+        while (val != INIT_DONE) {
+            apr_sleep(APR_USEC_PER_SEC / 1000);
+      
+            val = apr_atomic_cas32(&have_init_ssl,
+                                   INIT_UNINITIALIZED,
+                                   INIT_UNINITIALIZED);            
+        }
+    }
+}
+
+static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey)
+{
+    serf_ssl_context_t *ctx = SSL_get_app_data(ssl);
+    apr_status_t status;
+
+    if (ctx->cached_cert) {
+        *cert = ctx->cached_cert;
+        *pkey = ctx->cached_cert_pw;
+        return 1;
+    }
+
+    while (ctx->cert_callback) {
+        const char *cert_path;
+        apr_file_t *cert_file;
+        BIO *bio;
+        BIO_METHOD *biom;
+        PKCS12 *p12;
+        int i;
+        int retrying_success = 0;
+
+        if (ctx->cert_file_success) {
+            status = APR_SUCCESS;
+            cert_path = ctx->cert_file_success;
+            ctx->cert_file_success = NULL;
+            retrying_success = 1;
+        } else {
+            status = ctx->cert_callback(ctx->cert_userdata, &cert_path);
+        }
+
+        if (status || !cert_path) {
+            break;
+        }
+
+        /* Load the x.509 cert file stored in PKCS12 */
+        status = apr_file_open(&cert_file, cert_path, APR_READ, APR_OS_DEFAULT,
+                               ctx->pool);
+
+        if (status) {
+            continue;
+        }
+
+        biom = bio_meth_file_new();
+        bio = BIO_new(biom);
+        bio_set_data(bio, cert_file);
+
+        ctx->cert_path = cert_path;
+        p12 = d2i_PKCS12_bio(bio, NULL);
+        apr_file_close(cert_file);
+
+        i = PKCS12_parse(p12, NULL, pkey, cert, NULL);
+
+        if (i == 1) {
+            PKCS12_free(p12);
+            bio_meth_free(biom);
+            ctx->cached_cert = *cert;
+            ctx->cached_cert_pw = *pkey;
+            if (!retrying_success && ctx->cert_cache_pool) {
+                const char *c;
+
+                c = apr_pstrdup(ctx->cert_cache_pool, ctx->cert_path);
+
+                apr_pool_userdata_setn(c, "serf:ssl:cert",
+                                       apr_pool_cleanup_null,
+                                       ctx->cert_cache_pool);
+            }
+            return 1;
+        }
+        else {
+            int err = ERR_get_error();
+            ERR_clear_error();
+            if (ERR_GET_LIB(err) == ERR_LIB_PKCS12 &&
+                ERR_GET_REASON(err) == PKCS12_R_MAC_VERIFY_FAILURE) {
+                if (ctx->cert_pw_callback) {
+                    const char *password;
+
+                    if (ctx->cert_pw_success) {
+                        status = APR_SUCCESS;
+                        password = ctx->cert_pw_success;
+                        ctx->cert_pw_success = NULL;
+                    } else {
+                        status = ctx->cert_pw_callback(ctx->cert_pw_userdata,
+                                                       ctx->cert_path,
+                                                       &password);
+                    }
+
+                    if (!status && password) {
+                        i = PKCS12_parse(p12, password, pkey, cert, NULL);
+                        if (i == 1) {
+                            PKCS12_free(p12);
+                            bio_meth_free(biom);
+                            ctx->cached_cert = *cert;
+                            ctx->cached_cert_pw = *pkey;
+                            if (!retrying_success && ctx->cert_cache_pool) {
+                                const char *c;
+
+                                c = apr_pstrdup(ctx->cert_cache_pool,
+                                                ctx->cert_path);
+
+                                apr_pool_userdata_setn(c, "serf:ssl:cert",
+                                                       apr_pool_cleanup_null,
+                                                       ctx->cert_cache_pool);
+                            }
+                            if (!retrying_success && ctx->cert_pw_cache_pool) {
+                                const char *c;
+
+                                c = apr_pstrdup(ctx->cert_pw_cache_pool,
+                                                password);
+
+                                apr_pool_userdata_setn(c, "serf:ssl:certpw",
+                                                       apr_pool_cleanup_null,
+                                                       ctx->cert_pw_cache_pool);
+                            }
+                            return 1;
+                        }
+                    }
+                }
+                PKCS12_free(p12);
+                bio_meth_free(biom);
+                return 0;
+            }
+            else {
+                printf("OpenSSL cert error: %d %d %d\n", ERR_GET_LIB(err),
+                       ERR_GET_FUNC(err),
+                       ERR_GET_REASON(err));
+                PKCS12_free(p12);
+                bio_meth_free(biom);
+            }
+        }
+    }
+
+    return 0;
+}
+
+
+void serf_ssl_client_cert_provider_set(
+    serf_ssl_context_t *context,
+    serf_ssl_need_client_cert_t callback,
+    void *data,
+    void *cache_pool)
+{
+    context->cert_callback = callback;
+    context->cert_userdata = data;
+    context->cert_cache_pool = cache_pool;
+    if (context->cert_cache_pool) {
+        apr_pool_userdata_get((void**)&context->cert_file_success,
+                              "serf:ssl:cert", cache_pool);
+    }
+}
+
+
+void serf_ssl_client_cert_password_set(
+    serf_ssl_context_t *context,
+    serf_ssl_need_cert_password_t callback,
+    void *data,
+    void *cache_pool)
+{
+    context->cert_pw_callback = callback;
+    context->cert_pw_userdata = data;
+    context->cert_pw_cache_pool = cache_pool;
+    if (context->cert_pw_cache_pool) {
+        apr_pool_userdata_get((void**)&context->cert_pw_success,
+                              "serf:ssl:certpw", cache_pool);
+    }
+}
+
+
+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;
+}
+
+void serf_ssl_server_cert_chain_callback_set(
+    serf_ssl_context_t *context,
+    serf_ssl_need_server_cert_t cert_callback,
+    serf_ssl_server_cert_chain_cb_t cert_chain_callback,
+    void *data)
+{
+    context->server_cert_callback = cert_callback;
+    context->server_cert_chain_callback = cert_chain_callback;
+    context->server_cert_userdata = data;
+}
+
+static serf_ssl_context_t *ssl_init_context(serf_bucket_alloc_t *allocator)
+{
+    serf_ssl_context_t *ssl_ctx;
+
+    init_ssl_libraries();
+
+    ssl_ctx = serf_bucket_mem_alloc(allocator, sizeof(*ssl_ctx));
+
+    ssl_ctx->refcount = 0;
+    ssl_ctx->pool = serf_bucket_allocator_get_pool(allocator);
+    ssl_ctx->allocator = allocator;
+
+    /* Use the best possible protocol version, but disable the broken SSLv2/3 */
+    ssl_ctx->ctx = SSL_CTX_new(SSLv23_client_method());
+    SSL_CTX_set_options(ssl_ctx->ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
+
+    SSL_CTX_set_client_cert_cb(ssl_ctx->ctx, ssl_need_client_cert);
+    ssl_ctx->cached_cert = 0;
+    ssl_ctx->cached_cert_pw = 0;
+    ssl_ctx->pending_err = APR_SUCCESS;
+    ssl_ctx->fatal_err = APR_SUCCESS;
+
+    ssl_ctx->cert_callback = NULL;
+    ssl_ctx->cert_pw_callback = NULL;
+    ssl_ctx->server_cert_callback = NULL;
+    ssl_ctx->server_cert_chain_callback = NULL;
+
+    SSL_CTX_set_verify(ssl_ctx->ctx, SSL_VERIFY_PEER,
+                       validate_server_certificate);
+    SSL_CTX_set_options(ssl_ctx->ctx, SSL_OP_ALL);
+    /* Disable SSL compression by default. */
+    disable_compression(ssl_ctx);
+
+    ssl_ctx->ssl = SSL_new(ssl_ctx->ctx);
+    ssl_ctx->biom = bio_meth_bucket_new();
+    ssl_ctx->bio = BIO_new(ssl_ctx->biom);
+    bio_set_data(ssl_ctx->bio, ssl_ctx);
+
+    SSL_set_bio(ssl_ctx->ssl, ssl_ctx->bio, ssl_ctx->bio);
+
+    SSL_set_connect_state(ssl_ctx->ssl);
+
+    SSL_set_app_data(ssl_ctx->ssl, ssl_ctx);
+
+#if SSL_VERBOSE
+    SSL_CTX_set_info_callback(ssl_ctx->ctx, apps_ssl_info_callback);
+#endif
+
+    ssl_ctx->encrypt.stream = NULL;
+    ssl_ctx->encrypt.stream_next = NULL;
+    ssl_ctx->encrypt.pending = serf_bucket_aggregate_create(allocator);
+    ssl_ctx->encrypt.status = APR_SUCCESS;
+    serf_databuf_init(&ssl_ctx->encrypt.databuf);
+    ssl_ctx->encrypt.databuf.read = ssl_encrypt;
+    ssl_ctx->encrypt.databuf.read_baton = ssl_ctx;
+
+    ssl_ctx->decrypt.stream = NULL;
+    ssl_ctx->decrypt.pending = serf_bucket_aggregate_create(allocator);
+    ssl_ctx->decrypt.status = APR_SUCCESS;
+    serf_databuf_init(&ssl_ctx->decrypt.databuf);
+    ssl_ctx->decrypt.databuf.read = ssl_decrypt;
+    ssl_ctx->decrypt.databuf.read_baton = ssl_ctx;
+
+    return ssl_ctx;
+}
+
+static apr_status_t ssl_free_context(
+    serf_ssl_context_t *ssl_ctx)
+{
+    /* If never had the pending buckets, don't try to free them. */
+    if (ssl_ctx->decrypt.pending != NULL) {
+        serf_bucket_destroy(ssl_ctx->decrypt.pending);
+    }
+    if (ssl_ctx->encrypt.pending != NULL) {
+        serf_bucket_destroy(ssl_ctx->encrypt.pending);
+    }
+
+    /* SSL_free implicitly frees the underlying BIO. */
+    SSL_free(ssl_ctx->ssl);
+    bio_meth_free(ssl_ctx->biom);
+    SSL_CTX_free(ssl_ctx->ctx);
+
+    serf_bucket_mem_free(ssl_ctx->allocator, ssl_ctx);
+
+    return APR_SUCCESS;
+}
+
+static serf_bucket_t * serf_bucket_ssl_create(
+    serf_ssl_context_t *ssl_ctx,
+    serf_bucket_alloc_t *allocator,
+    const serf_bucket_type_t *type)
+{
+    ssl_context_t *ctx;
+
+    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
+    if (!ssl_ctx) {
+        ctx->ssl_ctx = ssl_init_context(allocator);
+    }
+    else {
+        ctx->ssl_ctx = ssl_ctx;
+    }
+    ctx->ssl_ctx->refcount++;
+
+    return serf_bucket_create(type, allocator, ctx);
+}
+
+apr_status_t serf_ssl_set_hostname(serf_ssl_context_t *context,
+                                   const char * hostname)
+{
+#ifdef SSL_set_tlsext_host_name
+    if (SSL_set_tlsext_host_name(context->ssl, hostname) != 1) {
+        ERR_clear_error();
+    }
+#endif
+    return APR_SUCCESS;
+}
+
+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 : SERF_ERROR_SSL_CERT_FAILED;
+}
+
+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 SERF_ERROR_SSL_CERT_FAILED;
+}
+
+
+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 : SERF_ERROR_SSL_CERT_FAILED;
+}
+
+
+serf_bucket_t *serf_bucket_ssl_decrypt_create(
+    serf_bucket_t *stream,
+    serf_ssl_context_t *ssl_ctx,
+    serf_bucket_alloc_t *allocator)
+{
+    serf_bucket_t *bkt;
+    ssl_context_t *ctx;
+
+    bkt = serf_bucket_ssl_create(ssl_ctx, allocator,
+                                 &serf_bucket_type_ssl_decrypt);
+
+    ctx = bkt->data;
+
+    ctx->databuf = &ctx->ssl_ctx->decrypt.databuf;
+    if (ctx->ssl_ctx->decrypt.stream != NULL) {
+        return NULL;
+    }
+    ctx->ssl_ctx->decrypt.stream = stream;
+    ctx->our_stream = &ctx->ssl_ctx->decrypt.stream;
+
+    return bkt;
+}
+
+
+serf_ssl_context_t *serf_bucket_ssl_decrypt_context_get(
+     serf_bucket_t *bucket)
+{
+    ssl_context_t *ctx = bucket->data;
+    return ctx->ssl_ctx;
+}
+
+
+serf_bucket_t *serf_bucket_ssl_encrypt_create(
+    serf_bucket_t *stream,
+    serf_ssl_context_t *ssl_ctx,
+    serf_bucket_alloc_t *allocator)
+{
+    serf_bucket_t *bkt;
+    ssl_context_t *ctx;
+
+    bkt = serf_bucket_ssl_create(ssl_ctx, allocator,
+                                 &serf_bucket_type_ssl_encrypt);
+
+    ctx = bkt->data;
+
+    ctx->databuf = &ctx->ssl_ctx->encrypt.databuf;
+    ctx->our_stream = &ctx->ssl_ctx->encrypt.stream;
+    if (ctx->ssl_ctx->encrypt.stream == NULL) {
+        serf_bucket_t *tmp = serf_bucket_aggregate_create(stream->allocator);
+        serf_bucket_aggregate_append(tmp, stream);
+        ctx->ssl_ctx->encrypt.stream = tmp;
+    }
+    else {
+        bucket_list_t *new_list;
+
+        new_list = serf_bucket_mem_alloc(ctx->ssl_ctx->allocator,
+                                         sizeof(*new_list));
+        new_list->bucket = stream;
+        new_list->next = NULL;
+        if (ctx->ssl_ctx->encrypt.stream_next == NULL) {
+            ctx->ssl_ctx->encrypt.stream_next = new_list;
+        }
+        else {
+            bucket_list_t *scan = ctx->ssl_ctx->encrypt.stream_next;
+
+            while (scan->next != NULL)
+                scan = scan->next;
+            scan->next = new_list;
+        }
+    }
+
+    return bkt;
+}
+
+
+serf_ssl_context_t *serf_bucket_ssl_encrypt_context_get(
+     serf_bucket_t *bucket)
+{
+    ssl_context_t *ctx = bucket->data;
+    return ctx->ssl_ctx;
+}
+
+/* Functions to read a serf_ssl_certificate structure. */
+
+/* Takes a counted length string and escapes any NUL bytes so that
+ * it can be used as a C string.  NUL bytes are escaped as 3 characters
+ * "\00" (that's a literal backslash).
+ * The returned string is allocated in POOL.
+ */
+static char *
+pstrdup_escape_nul_bytes(const char *buf, int len, apr_pool_t *pool)
+{
+    int i, nul_count = 0;
+    char *ret;
+
+    /* First determine if there are any nul bytes in the string. */
+    for (i = 0; i < len; i++) {
+        if (buf[i] == '\0')
+            nul_count++;
+    }
+
+    if (nul_count == 0) {
+        /* There aren't so easy case to just copy the string */
+        ret = apr_pstrdup(pool, buf);
+    } else {
+        /* There are so we have to replace nul bytes with escape codes
+         * Proper length is the length of the original string, plus
+         * 2 times the number of nulls (for two digit hex code for
+         * the value) + the trailing null. */
+        char *pos;
+        ret = pos = apr_palloc(pool, len + 2 * nul_count + 1);
+        for (i = 0; i < len; i++) {
+            if (buf[i] != '\0') {
+                *(pos++) = buf[i];
+            } else {
+                *(pos++) = '\\';
+                *(pos++) = '0';
+                *(pos++) = '0';
+            }
+        }
+        *pos = '\0';
+    }
+
+    return ret;
+}
+
+/* Creates a hash_table with keys (E, CN, OU, O, L, ST and C). Any NUL bytes in
+   these fields in the certificate will be escaped as \00. */
+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,
+                     pstrdup_escape_nul_bytes(buf, ret, pool));
+    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,
+                     pstrdup_escape_nul_bytes(buf, ret, pool));
+    ret = X509_NAME_get_text_by_NID(org,
+                                    NID_organizationalUnitName,
+                                    buf, 1024);
+    if (ret != -1)
+        apr_hash_set(tgt, "OU", APR_HASH_KEY_STRING,
+                     pstrdup_escape_nul_bytes(buf, ret, pool));
+    ret = X509_NAME_get_text_by_NID(org,
+                                    NID_organizationName,
+                                    buf, 1024);
+    if (ret != -1)
+        apr_hash_set(tgt, "O", APR_HASH_KEY_STRING,
+                     pstrdup_escape_nul_bytes(buf, ret, pool));
+    ret = X509_NAME_get_text_by_NID(org,
+                                    NID_localityName,
+                                    buf, 1024);
+    if (ret != -1)
+        apr_hash_set(tgt, "L", APR_HASH_KEY_STRING,
+                     pstrdup_escape_nul_bytes(buf, ret, pool));
+    ret = X509_NAME_get_text_by_NID(org,
+                                    NID_stateOrProvinceName,
+                                    buf, 1024);
+    if (ret != -1)
+        apr_hash_set(tgt, "ST", APR_HASH_KEY_STRING,
+                     pstrdup_escape_nul_bytes(buf, ret, pool));
+    ret = X509_NAME_get_text_by_NID(org,
+                                    NID_countryName,
+                                    buf, 1024);
+    if (ret != -1)
+        apr_hash_set(tgt, "C", APR_HASH_KEY_STRING,
+                     pstrdup_escape_nul_bytes(buf, ret, pool));
+
+    return tgt;
+}
+
+
+int serf_ssl_cert_depth(const serf_ssl_certificate_t *cert)
+{
+    return cert->depth;
+}
+
+
+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);
+}
+
+
+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);
+}
+
+
+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;
+    apr_array_header_t *san_arr;
+
+    /* 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);
+
+    /* Get subjectAltNames */
+    if (!get_subject_alt_names(&san_arr, cert->ssl_cert, EscapeNulAndCopy, pool))
+        apr_hash_set(tgt, "subjectAltName", APR_HASH_KEY_STRING, san_arr);
+
+    return tgt;
+}
+
+
+const char *serf_ssl_cert_export(
+    const serf_ssl_certificate_t *cert,
+    apr_pool_t *pool)
+{
+    char *binary_cert;
+    char *encoded_cert;
+    int len;
+    unsigned char *unused;
+
+    /* find the length of the DER encoding. */
+    len = i2d_X509(cert->ssl_cert, NULL);
+    if (len < 0) {
+        return NULL;
+    }
+
+    binary_cert = apr_palloc(pool, len);
+    unused = (unsigned char *)binary_cert;
+    len = i2d_X509(cert->ssl_cert, &unused);  /* unused is incremented  */
+    if (len < 0) {
+        return NULL;
+    }
+
+    encoded_cert = apr_palloc(pool, apr_base64_encode_len(len));
+    apr_base64_encode(encoded_cert, binary_cert, len);
+    
+    return encoded_cert;
+}
+
+/* Disables compression for all SSL sessions. */
+static void disable_compression(serf_ssl_context_t *ssl_ctx)
+{
+#ifdef SSL_OP_NO_COMPRESSION
+    SSL_CTX_set_options(ssl_ctx->ctx, SSL_OP_NO_COMPRESSION);
+#endif
+}
+
+apr_status_t serf_ssl_use_compression(serf_ssl_context_t *ssl_ctx, int enabled)
+{
+    if (enabled) {
+#ifdef SSL_OP_NO_COMPRESSION
+        SSL_clear_options(ssl_ctx->ssl, SSL_OP_NO_COMPRESSION);
+        return APR_SUCCESS;
+#endif
+    } else {
+#ifdef SSL_OP_NO_COMPRESSION
+        SSL_set_options(ssl_ctx->ssl, SSL_OP_NO_COMPRESSION);
+        return APR_SUCCESS;
+#endif
+    }
+
+    return APR_EGENERAL;
+}
+
+static void serf_ssl_destroy_and_data(serf_bucket_t *bucket)
+{
+    ssl_context_t *ctx = bucket->data;
+
+    if (!--ctx->ssl_ctx->refcount) {
+        ssl_free_context(ctx->ssl_ctx);
+    }
+
+    serf_default_destroy_and_data(bucket);
+}
+
+static void serf_ssl_decrypt_destroy_and_data(serf_bucket_t *bucket)
+{
+    ssl_context_t *ctx = bucket->data;
+
+    serf_bucket_destroy(*ctx->our_stream);
+
+    serf_ssl_destroy_and_data(bucket);
+}
+
+static void serf_ssl_encrypt_destroy_and_data(serf_bucket_t *bucket)
+{
+    ssl_context_t *ctx = bucket->data;
+    serf_ssl_context_t *ssl_ctx = ctx->ssl_ctx;
+
+    if (ssl_ctx->encrypt.stream == *ctx->our_stream) {
+        serf_bucket_destroy(*ctx->our_stream);
+        serf_bucket_destroy(ssl_ctx->encrypt.pending);
+
+        /* Reset our encrypted status and databuf. */
+        ssl_ctx->encrypt.status = APR_SUCCESS;
+        ssl_ctx->encrypt.databuf.status = APR_SUCCESS;
+
+        /* Advance to the next stream - if we have one. */
+        if (ssl_ctx->encrypt.stream_next == NULL) {
+            ssl_ctx->encrypt.stream = NULL;
+            ssl_ctx->encrypt.pending = NULL;
+        }
+        else {
+            bucket_list_t *cur;
+
+            cur = ssl_ctx->encrypt.stream_next;
+            ssl_ctx->encrypt.stream = cur->bucket;
+            ssl_ctx->encrypt.pending =
+                serf_bucket_aggregate_create(cur->bucket->allocator);
+            ssl_ctx->encrypt.stream_next = cur->next;
+            serf_bucket_mem_free(ssl_ctx->allocator, cur);
+        }
+    }
+    else {
+        /* Ah, darn.  We haven't sent this one along yet. */
+        return;
+    }
+    serf_ssl_destroy_and_data(bucket);
+}
+
+static apr_status_t serf_ssl_read(serf_bucket_t *bucket,
+                                  apr_size_t requested,
+                                  const char **data, apr_size_t *len)
+{
+    ssl_context_t *ctx = bucket->data;
+
+    return serf_databuf_read(ctx->databuf, requested, data, len);
+}
+
+static apr_status_t serf_ssl_readline(serf_bucket_t *bucket,
+                                      int acceptable, int *found,
+                                      const char **data,
+                                      apr_size_t *len)
+{
+    ssl_context_t *ctx = bucket->data;
+
+    return serf_databuf_readline(ctx->databuf, acceptable, found, data, len);
+}
+
+static apr_status_t serf_ssl_peek(serf_bucket_t *bucket,
+                                  const char **data,
+                                  apr_size_t *len)
+{
+    ssl_context_t *ctx = bucket->data;
+
+    return serf_databuf_peek(ctx->databuf, data, len);
+}
+
+
+const serf_bucket_type_t serf_bucket_type_ssl_encrypt = {
+    "SSLENCRYPT",
+    serf_ssl_read,
+    serf_ssl_readline,
+    serf_default_read_iovec,
+    serf_default_read_for_sendfile,
+    serf_default_read_bucket,
+    serf_ssl_peek,
+    serf_ssl_encrypt_destroy_and_data,
+};
+
+const serf_bucket_type_t serf_bucket_type_ssl_decrypt = {
+    "SSLDECRYPT",
+    serf_ssl_read,
+    serf_ssl_readline,
+    serf_default_read_iovec,
+    serf_default_read_for_sendfile,
+    serf_default_read_bucket,
+    serf_ssl_peek,
+    serf_ssl_decrypt_destroy_and_data,
+};

Deleted: vendor/serf/1.3.9/build/check.py
===================================================================
--- vendor/serf/dist/build/check.py	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/build/check.py	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,58 +0,0 @@
-#!/usr/bin/env python
-#
-# check.py :  Run all the test cases.
-#
-# ====================================================================
-#   Copyright 2013 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.
-# ====================================================================
-
-import sys
-import glob
-import subprocess
-import os
-
-
-if __name__ == '__main__':
-  # get the test directory from the commandline, if set.
-  if len(sys.argv) > 1:
-    testdir = sys.argv[1]
-  else:
-    testdir = 'test'
-
-  # define test executable paths
-  if sys.platform == 'win32':
-    SERF_RESPONSE_EXE = 'serf_response.exe'
-    TEST_ALL_EXE = 'test_all.exe'
-  else:
-    SERF_RESPONSE_EXE = 'serf_response'
-    TEST_ALL_EXE = 'test_all'
-  SERF_RESPONSE_EXE = os.path.join(testdir, SERF_RESPONSE_EXE)
-  TEST_ALL_EXE = os.path.join(testdir, TEST_ALL_EXE)
-
-  # Find test responses and run them one by one
-  for case in glob.glob(testdir + "/testcases/*.response"):
-    print "== Testing %s ==" % (case)
-    try:
-      subprocess.check_call([SERF_RESPONSE_EXE, case])
-    except subprocess.CalledProcessError:
-      print "ERROR: test case %s failed" % (case)
-      sys.exit(1)
-
-  print "== Running the unit tests =="
-  try:
-    subprocess.check_call(TEST_ALL_EXE)
-  except subprocess.CalledProcessError:
-    print "ERROR: test(s) failed in test_all"
-    sys.exit(1)

Copied: vendor/serf/1.3.9/build/check.py (from rev 9259, vendor/serf/dist/build/check.py)
===================================================================
--- vendor/serf/1.3.9/build/check.py	                        (rev 0)
+++ vendor/serf/1.3.9/build/check.py	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+#
+# check.py :  Run all the test cases.
+#
+# ===================================================================
+#   Licensed to the Apache Software Foundation (ASF) under one
+#   or more contributor license agreements.  See the NOTICE file
+#   distributed with this work for additional information
+#   regarding copyright ownership.  The ASF licenses this file
+#   to you 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.
+# ===================================================================
+#
+
+import sys
+import glob
+import subprocess
+import os
+
+
+if __name__ == '__main__':
+  # get the test directory from the commandline, if set.
+  if len(sys.argv) > 1:
+    testdir = sys.argv[1]
+  else:
+    testdir = 'test'
+
+  if len(sys.argv) > 2:
+    test_builddir = sys.argv[2]
+  else:
+    test_builddir = 'test'
+
+  # define test executable paths
+  if sys.platform == 'win32':
+    SERF_RESPONSE_EXE = 'serf_response.exe'
+    TEST_ALL_EXE = 'test_all.exe'
+  else:
+    SERF_RESPONSE_EXE = 'serf_response'
+    TEST_ALL_EXE = 'test_all'
+  SERF_RESPONSE_EXE = os.path.join(test_builddir, SERF_RESPONSE_EXE)
+  TEST_ALL_EXE = os.path.join(test_builddir, TEST_ALL_EXE)
+
+  # Find test responses and run them one by one
+  for case in glob.glob(testdir + "/testcases/*.response"):
+    print "== Testing %s ==" % (case)
+    try:
+      subprocess.check_call([SERF_RESPONSE_EXE, case])
+    except subprocess.CalledProcessError:
+      print "ERROR: test case %s failed" % (case)
+      sys.exit(1)
+
+  print "== Running the unit tests =="
+  try:
+    subprocess.check_call(TEST_ALL_EXE)
+  except subprocess.CalledProcessError:
+    print "ERROR: test(s) failed in test_all"
+    sys.exit(1)

Deleted: vendor/serf/1.3.9/build/gen_def.py
===================================================================
--- vendor/serf/dist/build/gen_def.py	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/build/gen_def.py	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,76 +0,0 @@
-#!/usr/bin/env python
-#
-# gen_def.py :  Generate the .DEF file for Windows builds
-#
-# ====================================================================
-#   Copyright 2002-2010 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.
-# ====================================================================
-#
-#
-# Typically, this script is used like:
-#
-#    C:\PATH> python build/gen_def.py serf.h serf_bucket_types.h serf_bucket_util.h > build/serf.def
-#
-
-import re
-import sys
-
-# This regex parses function declarations that look like:
-#
-#    return_type serf_func1(...
-#    return_type *serf_func2(...
-#
-# Where return_type is a combination of words and "*" each separated by a
-# SINGLE space. If the function returns a pointer type (like serf_func2),
-# then a space may exist between the "*" and the function name. Thus,
-# a more complicated example might be:
-#    const type * const * serf_func3(...
-#
-_funcs = re.compile(r'^(?:(?:\w+|\*) )+\*?(serf_[a-z][a-zA-Z_0-9]*)\(',
-                    re.MULTILINE)
-
-# This regex parses the bucket type definitions which look like:
-#
-#    extern const serf_bucket_type_t serf_bucket_type_FOO;
-#
-_types = re.compile(r'^extern const serf_bucket_type_t (serf_[a-z_]*);',
-                    re.MULTILINE)
-
-
-def extract_exports(fname):
-  content = open(fname).read()
-  exports = [ ]
-  for name in _funcs.findall(content):
-    exports.append(name)
-  for name in _types.findall(content):
-    exports.append(name)
-  return exports
-
-# Blacklist the serf v2 API for now
-blacklist = ['serf_connection_switch_protocol',
-             'serf_http_protocol_create',
-             'serf_http_request_create',
-             'serf_https_protocol_create']
-
-if __name__ == '__main__':
-  # run the extraction over each file mentioned
-  import sys
-  print("EXPORTS")
-
-  for fname in sys.argv[1:]:
-    funclist = extract_exports(fname)
-    funclist = set(funclist) - set(blacklist)
-    for func in funclist:
-      print(func)

Copied: vendor/serf/1.3.9/build/gen_def.py (from rev 9259, vendor/serf/dist/build/gen_def.py)
===================================================================
--- vendor/serf/1.3.9/build/gen_def.py	                        (rev 0)
+++ vendor/serf/1.3.9/build/gen_def.py	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+#
+# gen_def.py :  Generate the .DEF file for Windows builds
+#
+# ===================================================================
+#   Licensed to the Apache Software Foundation (ASF) under one
+#   or more contributor license agreements.  See the NOTICE file
+#   distributed with this work for additional information
+#   regarding copyright ownership.  The ASF licenses this file
+#   to you 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.
+# ===================================================================
+#
+# Typically, this script is used like:
+#
+#    C:\PATH> python build/gen_def.py serf.h serf_bucket_types.h serf_bucket_util.h > build/serf.def
+#
+
+import re
+import sys
+
+# This regex parses function declarations that look like:
+#
+#    return_type serf_func1(...
+#    return_type *serf_func2(...
+#
+# Where return_type is a combination of words and "*" each separated by a
+# SINGLE space. If the function returns a pointer type (like serf_func2),
+# then a space may exist between the "*" and the function name. Thus,
+# a more complicated example might be:
+#    const type * const * serf_func3(...
+#
+_funcs = re.compile(r'^(?:(?:\w+|\*) )+\*?(serf_[a-z][a-zA-Z_0-9]*)\(',
+                    re.MULTILINE)
+
+# This regex parses the bucket type definitions which look like:
+#
+#    extern const serf_bucket_type_t serf_bucket_type_FOO;
+#
+_types = re.compile(r'^extern const serf_bucket_type_t (serf_[a-z_]*);',
+                    re.MULTILINE)
+
+
+def extract_exports(fname):
+  content = open(fname).read()
+  exports = [ ]
+  for name in _funcs.findall(content):
+    exports.append(name)
+  for name in _types.findall(content):
+    exports.append(name)
+  return exports
+
+# Blacklist the serf v2 API for now
+blacklist = ['serf_connection_switch_protocol',
+             'serf_http_protocol_create',
+             'serf_http_request_create',
+             'serf_https_protocol_create']
+
+if __name__ == '__main__':
+  # run the extraction over each file mentioned
+  import sys
+  print("EXPORTS")
+
+  for fname in sys.argv[1:]:
+    funclist = extract_exports(fname)
+    funclist = set(funclist) - set(blacklist)
+    for func in funclist:
+      print(func)

Deleted: vendor/serf/1.3.9/context.c
===================================================================
--- vendor/serf/dist/context.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/context.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,385 +0,0 @@
-/* Copyright 2002-2004 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_pools.h>
-#include <apr_poll.h>
-#include <apr_version.h>
-
-#include "serf.h"
-#include "serf_bucket_util.h"
-
-#include "serf_private.h"
-
-/**
- * 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).
- */
-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);
-}
-
-
-/* Check for dirty connections and update their pollsets accordingly. */
-static apr_status_t check_dirty_pollsets(serf_context_t *ctx)
-{
-    int i;
-
-    /* if we're not dirty, return now. */
-    if (!ctx->dirty_pollset) {
-        return APR_SUCCESS;
-    }
-
-    for (i = ctx->conns->nelts; i--; ) {
-        serf_connection_t *conn = GET_CONN(ctx, i);
-        apr_status_t status;
-
-        /* if this connection isn't dirty, skip it. */
-        if (!conn->dirty_conn) {
-            continue;
-        }
-
-        /* reset this connection's flag before we update. */
-        conn->dirty_conn = 0;
-
-        if ((status = serf__conn_update_pollset(conn)) != APR_SUCCESS)
-            return status;
-    }
-
-    /* reset our context flag now */
-    ctx->dirty_pollset = 0;
-
-    return APR_SUCCESS;
-}
-
-
-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);
-}
-
-
-void serf_config_proxy(serf_context_t *ctx,
-                       apr_sockaddr_t *address)
-{
-    ctx->proxy_address = address;
-}
-
-
-void serf_config_credentials_callback(serf_context_t *ctx,
-                                      serf_credentials_callback_t cred_cb)
-{
-    ctx->cred_cb = cred_cb;
-}
-
-
-void serf_config_authn_types(serf_context_t *ctx,
-                             int authn_types)
-{
-    ctx->authn_types = authn_types;
-}
-
-
-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;
-
-    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));
-
-        /* ### TODO: As of APR 1.4.x apr_pollset_create_ex can return a status
-           ### other than APR_SUCCESS, so we should handle it.
-           ### Probably move creation of the pollset to later when we have
-           ### the possibility of returning status to the caller.
-         */
-#ifdef BROKEN_WSAPOLL
-        /* APR 1.4.x switched to using WSAPoll() on Win32, but it does not
-         * properly handle errors on a non-blocking sockets (such as
-         * connecting to a server where no listener is active).
-         *
-         * So, sadly, we must force using select() on Win32.
-         *
-         * http://mail-archives.apache.org/mod_mbox/apr-dev/201105.mbox/%3CBANLkTin3rBCecCBRvzUA5B-14u-NWxR_Kg@mail.gmail.com%3E
-         */
-        (void) apr_pollset_create_ex(&ps->pollset, MAX_CONN, pool, 0,
-                                     APR_POLLSET_SELECT);
-#else
-        (void) apr_pollset_create(&ps->pollset, MAX_CONN, pool, 0);
-#endif
-        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;
-
-    ctx->authn_types = SERF_AUTHN_ALL;
-    ctx->server_authn_info = apr_hash_make(pool);
-
-    return ctx;
-}
-
-
-serf_context_t *serf_context_create(apr_pool_t *pool)
-{
-    return serf_context_create_ex(NULL, NULL, NULL, pool);
-}
-
-apr_status_t serf_context_prerun(serf_context_t *ctx)
-{
-    apr_status_t status = APR_SUCCESS;
-    if ((status = serf__open_connections(ctx)) != APR_SUCCESS)
-        return status;
-
-    if ((status = check_dirty_pollsets(ctx)) != APR_SUCCESS)
-        return status;
-    return status;
-}
-
-
-apr_status_t serf_event_trigger(
-    serf_context_t *s,
-    void *serf_baton,
-    const apr_pollfd_t *desc)
-{
-    apr_pollfd_t tdesc = { 0 };
-    apr_status_t status = APR_SUCCESS;
-    serf_io_baton_t *io = serf_baton;
-
-    if (io->type == SERF_IO_CONN) {
-        serf_connection_t *conn = io->u.conn;
-        serf_context_t *ctx = conn->ctx;
-
-        /* If this connection has already failed, return the error again, and try
-         * to remove it from the pollset again
-         */
-        if (conn->status) {
-            tdesc.desc_type = APR_POLL_SOCKET;
-            tdesc.desc.s = conn->skt;
-            tdesc.reqevents = conn->reqevents;
-            ctx->pollset_rm(ctx->pollset_baton,
-                            &tdesc, conn);
-            return conn->status;
-        }
-        /* 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 ((conn->status = serf__process_connection(conn,
-                                         desc->rtnevents)) != APR_SUCCESS) {
-
-            /* it's possible that the connection was already reset and thus the
-               socket cleaned up. */
-            if (conn->skt) {
-                tdesc.desc_type = APR_POLL_SOCKET;
-                tdesc.desc.s = conn->skt;
-                tdesc.reqevents = conn->reqevents;
-                ctx->pollset_rm(ctx->pollset_baton,
-                                &tdesc, conn);
-            }
-            return conn->status;
-        }
-    }
-    else if (io->type == SERF_IO_LISTENER) {
-        serf_listener_t *l = io->u.listener;
-
-        status = serf__process_listener(l);
-
-        if (status) {
-            return status;
-        }
-    }
-    else if (io->type == SERF_IO_CLIENT) {
-        serf_incoming_t *c = io->u.client;
-
-        status = serf__process_client(c, desc->rtnevents);
-
-        if (status) {
-            return status;
-        }
-    }
-    return status;
-}
-
-
-apr_status_t serf_context_run(
-    serf_context_t *ctx,
-    apr_short_interval_time_t duration,
-    apr_pool_t *pool)
-{
-    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 = serf_context_prerun(ctx)) != APR_SUCCESS) {
-        return status;
-    }
-
-    if ((status = apr_pollset_poll(ps->pollset, duration, &num,
-                                   &desc)) != APR_SUCCESS) {
-        /* EINTR indicates a handled signal happened during the poll call,
-           ignore, the application can safely retry. */
-        if (APR_STATUS_IS_EINTR(status))
-            return APR_SUCCESS;
-
-        /* ### do we still need to dispatch stuff here?
-           ### look at the potential return codes. map to our defined
-           ### return values? ...
-        */
-
-        /* Use the strict documented error for poll timeouts, to allow proper
-           handling of the other timeout types when returned from
-           serf_event_trigger */
-        if (APR_STATUS_IS_TIMEUP(status))
-            return APR_TIMEUP; /* Return the documented error */
-        return status;
-    }
-
-    while (num--) {
-        serf_connection_t *conn = desc->client_data;
-
-        status = serf_event_trigger(ctx, conn, desc);
-        if (status) {
-            return status;
-        }
-
-        desc++;
-    }
-
-    return APR_SUCCESS;
-}
-
-
-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_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;
-}
-
-
-/* ### this really ought to go somewhere else, but... meh.  */
-void serf_lib_version(int *major, int *minor, int *patch)
-{
-    *major = SERF_MAJOR_VERSION;
-    *minor = SERF_MINOR_VERSION;
-    *patch = SERF_PATCH_VERSION;
-}
-
-
-const char *serf_error_string(apr_status_t errcode)
-{
-    switch (errcode)
-    {
-    case SERF_ERROR_CLOSING:
-        return "The connection is closing";
-    case SERF_ERROR_REQUEST_LOST:
-        return "A request has been lost";
-    case SERF_ERROR_WAIT_CONN:
-        return "The connection is blocked, pending further action";
-    case SERF_ERROR_DECOMPRESSION_FAILED:
-        return "An error occurred during decompression";
-    case SERF_ERROR_BAD_HTTP_RESPONSE:
-        return "The server sent an improper HTTP response";
-    case SERF_ERROR_TRUNCATED_HTTP_RESPONSE:
-        return "The server sent a truncated HTTP response body.";
-    case SERF_ERROR_ABORTED_CONNECTION:
-        return "The server unexpectedly closed the connection.";
-    case SERF_ERROR_SSL_COMM_FAILED:
-        return "An error occurred during SSL communication";
-    case SERF_ERROR_SSL_CERT_FAILED:
-        return "An SSL certificate related error occurred ";
-    case SERF_ERROR_AUTHN_FAILED:
-        return "An error occurred during authentication";
-    case SERF_ERROR_AUTHN_NOT_SUPPORTED:
-        return "The requested authentication type(s) are not supported";
-    case SERF_ERROR_AUTHN_MISSING_ATTRIBUTE:
-        return "An authentication attribute is missing";
-    case SERF_ERROR_AUTHN_INITALIZATION_FAILED:
-        return "Initialization of an authentication type failed";
-    case SERF_ERROR_SSLTUNNEL_SETUP_FAILED:
-        return "The proxy server returned an error while setting up the "
-               "SSL tunnel.";
-    default:
-        return NULL;
-    }
-
-    /* NOTREACHED  */
-}

Copied: vendor/serf/1.3.9/context.c (from rev 9259, vendor/serf/dist/context.c)
===================================================================
--- vendor/serf/1.3.9/context.c	                        (rev 0)
+++ vendor/serf/1.3.9/context.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,390 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_pools.h>
+#include <apr_poll.h>
+#include <apr_version.h>
+
+#include "serf.h"
+#include "serf_bucket_util.h"
+
+#include "serf_private.h"
+
+/**
+ * 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).
+ */
+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);
+}
+
+
+/* Check for dirty connections and update their pollsets accordingly. */
+static apr_status_t check_dirty_pollsets(serf_context_t *ctx)
+{
+    int i;
+
+    /* if we're not dirty, return now. */
+    if (!ctx->dirty_pollset) {
+        return APR_SUCCESS;
+    }
+
+    for (i = ctx->conns->nelts; i--; ) {
+        serf_connection_t *conn = GET_CONN(ctx, i);
+        apr_status_t status;
+
+        /* if this connection isn't dirty, skip it. */
+        if (!conn->dirty_conn) {
+            continue;
+        }
+
+        /* reset this connection's flag before we update. */
+        conn->dirty_conn = 0;
+
+        if ((status = serf__conn_update_pollset(conn)) != APR_SUCCESS)
+            return status;
+    }
+
+    /* reset our context flag now */
+    ctx->dirty_pollset = 0;
+
+    return APR_SUCCESS;
+}
+
+
+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);
+}
+
+
+void serf_config_proxy(serf_context_t *ctx,
+                       apr_sockaddr_t *address)
+{
+    ctx->proxy_address = address;
+}
+
+
+void serf_config_credentials_callback(serf_context_t *ctx,
+                                      serf_credentials_callback_t cred_cb)
+{
+    ctx->cred_cb = cred_cb;
+}
+
+
+void serf_config_authn_types(serf_context_t *ctx,
+                             int authn_types)
+{
+    ctx->authn_types = authn_types;
+}
+
+
+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;
+
+    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));
+
+        /* ### TODO: As of APR 1.4.x apr_pollset_create_ex can return a status
+           ### other than APR_SUCCESS, so we should handle it.
+           ### Probably move creation of the pollset to later when we have
+           ### the possibility of returning status to the caller.
+         */
+#ifdef BROKEN_WSAPOLL
+        /* APR 1.4.x switched to using WSAPoll() on Win32, but it does not
+         * properly handle errors on a non-blocking sockets (such as
+         * connecting to a server where no listener is active).
+         *
+         * So, sadly, we must force using select() on Win32.
+         *
+         * http://mail-archives.apache.org/mod_mbox/apr-dev/201105.mbox/%3CBANLkTin3rBCecCBRvzUA5B-14u-NWxR_Kg@mail.gmail.com%3E
+         */
+        (void) apr_pollset_create_ex(&ps->pollset, MAX_CONN, pool, 0,
+                                     APR_POLLSET_SELECT);
+#else
+        (void) apr_pollset_create(&ps->pollset, MAX_CONN, pool, 0);
+#endif
+        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;
+
+    ctx->authn_types = SERF_AUTHN_ALL;
+    ctx->server_authn_info = apr_hash_make(pool);
+
+    return ctx;
+}
+
+
+serf_context_t *serf_context_create(apr_pool_t *pool)
+{
+    return serf_context_create_ex(NULL, NULL, NULL, pool);
+}
+
+apr_status_t serf_context_prerun(serf_context_t *ctx)
+{
+    apr_status_t status = APR_SUCCESS;
+    if ((status = serf__open_connections(ctx)) != APR_SUCCESS)
+        return status;
+
+    if ((status = check_dirty_pollsets(ctx)) != APR_SUCCESS)
+        return status;
+    return status;
+}
+
+
+apr_status_t serf_event_trigger(
+    serf_context_t *s,
+    void *serf_baton,
+    const apr_pollfd_t *desc)
+{
+    apr_pollfd_t tdesc = { 0 };
+    apr_status_t status = APR_SUCCESS;
+    serf_io_baton_t *io = serf_baton;
+
+    if (io->type == SERF_IO_CONN) {
+        serf_connection_t *conn = io->u.conn;
+        serf_context_t *ctx = conn->ctx;
+
+        /* If this connection has already failed, return the error again, and try
+         * to remove it from the pollset again
+         */
+        if (conn->status) {
+            tdesc.desc_type = APR_POLL_SOCKET;
+            tdesc.desc.s = conn->skt;
+            tdesc.reqevents = conn->reqevents;
+            ctx->pollset_rm(ctx->pollset_baton,
+                            &tdesc, &conn->baton);
+            return conn->status;
+        }
+        /* 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 ((conn->status = serf__process_connection(conn,
+                                         desc->rtnevents)) != APR_SUCCESS) {
+
+            /* it's possible that the connection was already reset and thus the
+               socket cleaned up. */
+            if (conn->skt) {
+                tdesc.desc_type = APR_POLL_SOCKET;
+                tdesc.desc.s = conn->skt;
+                tdesc.reqevents = conn->reqevents;
+                ctx->pollset_rm(ctx->pollset_baton,
+                                &tdesc, &conn->baton);
+            }
+            return conn->status;
+        }
+    }
+    else if (io->type == SERF_IO_LISTENER) {
+        serf_listener_t *l = io->u.listener;
+
+        status = serf__process_listener(l);
+
+        if (status) {
+            return status;
+        }
+    }
+    else if (io->type == SERF_IO_CLIENT) {
+        serf_incoming_t *c = io->u.client;
+
+        status = serf__process_client(c, desc->rtnevents);
+
+        if (status) {
+            return status;
+        }
+    }
+    return status;
+}
+
+
+apr_status_t serf_context_run(
+    serf_context_t *ctx,
+    apr_short_interval_time_t duration,
+    apr_pool_t *pool)
+{
+    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 = serf_context_prerun(ctx)) != APR_SUCCESS) {
+        return status;
+    }
+
+    if ((status = apr_pollset_poll(ps->pollset, duration, &num,
+                                   &desc)) != APR_SUCCESS) {
+        /* EINTR indicates a handled signal happened during the poll call,
+           ignore, the application can safely retry. */
+        if (APR_STATUS_IS_EINTR(status))
+            return APR_SUCCESS;
+
+        /* ### do we still need to dispatch stuff here?
+           ### look at the potential return codes. map to our defined
+           ### return values? ...
+        */
+
+        /* Use the strict documented error for poll timeouts, to allow proper
+           handling of the other timeout types when returned from
+           serf_event_trigger */
+        if (APR_STATUS_IS_TIMEUP(status))
+            return APR_TIMEUP; /* Return the documented error */
+        return status;
+    }
+
+    while (num--) {
+        serf_io_baton_t *io  = desc->client_data;
+
+        status = serf_event_trigger(ctx, io, desc);
+        if (status) {
+            return status;
+        }
+
+        desc++;
+    }
+
+    return APR_SUCCESS;
+}
+
+
+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_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;
+}
+
+
+/* ### this really ought to go somewhere else, but... meh.  */
+void serf_lib_version(int *major, int *minor, int *patch)
+{
+    *major = SERF_MAJOR_VERSION;
+    *minor = SERF_MINOR_VERSION;
+    *patch = SERF_PATCH_VERSION;
+}
+
+
+const char *serf_error_string(apr_status_t errcode)
+{
+    switch (errcode)
+    {
+    case SERF_ERROR_CLOSING:
+        return "The connection is closing";
+    case SERF_ERROR_REQUEST_LOST:
+        return "A request has been lost";
+    case SERF_ERROR_WAIT_CONN:
+        return "The connection is blocked, pending further action";
+    case SERF_ERROR_DECOMPRESSION_FAILED:
+        return "An error occurred during decompression";
+    case SERF_ERROR_BAD_HTTP_RESPONSE:
+        return "The server sent an improper HTTP response";
+    case SERF_ERROR_TRUNCATED_HTTP_RESPONSE:
+        return "The server sent a truncated HTTP response body.";
+    case SERF_ERROR_ABORTED_CONNECTION:
+        return "The server unexpectedly closed the connection.";
+    case SERF_ERROR_SSL_COMM_FAILED:
+        return "An error occurred during SSL communication";
+    case SERF_ERROR_SSL_CERT_FAILED:
+        return "An SSL certificate related error occurred ";
+    case SERF_ERROR_AUTHN_FAILED:
+        return "An error occurred during authentication";
+    case SERF_ERROR_AUTHN_NOT_SUPPORTED:
+        return "The requested authentication type(s) are not supported";
+    case SERF_ERROR_AUTHN_MISSING_ATTRIBUTE:
+        return "An authentication attribute is missing";
+    case SERF_ERROR_AUTHN_INITALIZATION_FAILED:
+        return "Initialization of an authentication type failed";
+    case SERF_ERROR_SSLTUNNEL_SETUP_FAILED:
+        return "The proxy server returned an error while setting up the "
+               "SSL tunnel.";
+    default:
+        return NULL;
+    }
+
+    /* NOTREACHED  */
+}

Deleted: vendor/serf/1.3.9/incoming.c
===================================================================
--- vendor/serf/dist/incoming.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/incoming.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,176 +0,0 @@
-/* Copyright 2002-2004 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_pools.h>
-#include <apr_poll.h>
-#include <apr_version.h>
-
-#include "serf.h"
-#include "serf_bucket_util.h"
-
-#include "serf_private.h"
-
-static apr_status_t read_from_client(serf_incoming_t *client)
-{
-    return APR_ENOTIMPL;
-}
-
-static apr_status_t write_to_client(serf_incoming_t *client)
-{
-    return APR_ENOTIMPL;
-}
-
-apr_status_t serf__process_client(serf_incoming_t *client, apr_int16_t events)
-{
-    apr_status_t rv;
-    if ((events & APR_POLLIN) != 0) {
-        rv = read_from_client(client);
-        if (rv) {
-            return rv;
-        }
-    }
-
-    if ((events & APR_POLLHUP) != 0) {
-        return APR_ECONNRESET;
-    }
-
-    if ((events & APR_POLLERR) != 0) {
-        return APR_EGENERAL;
-    }
-
-    if ((events & APR_POLLOUT) != 0) {
-        rv = write_to_client(client);
-        if (rv) {
-            return rv;
-        }
-    }
-
-    return APR_SUCCESS;
-}
-
-apr_status_t serf__process_listener(serf_listener_t *l)
-{
-    apr_status_t rv;
-    apr_socket_t *in;
-    apr_pool_t *p;
-    /* THIS IS NOT OPTIMAL */
-    apr_pool_create(&p, l->pool);
-
-    rv = apr_socket_accept(&in, l->skt, p);
-
-    if (rv) {
-        apr_pool_destroy(p);
-        return rv;
-    }
-
-    rv = l->accept_func(l->ctx, l, l->accept_baton, in, p);
-
-    if (rv) {
-        apr_pool_destroy(p);
-        return rv;
-    }
-
-    return rv;
-}
-
-
-apr_status_t serf_incoming_create(
-    serf_incoming_t **client,
-    serf_context_t *ctx,
-    apr_socket_t *insock,
-    void *request_baton,
-    serf_incoming_request_cb_t request,
-    apr_pool_t *pool)
-{
-    apr_status_t rv;
-    serf_incoming_t *ic = apr_palloc(pool, sizeof(*ic));
-
-    ic->ctx = ctx;
-    ic->baton.type = SERF_IO_CLIENT;
-    ic->baton.u.client = ic;
-    ic->request_baton =  request_baton;
-    ic->request = request;
-    ic->skt = insock;
-    ic->desc.desc_type = APR_POLL_SOCKET;
-    ic->desc.desc.s = ic->skt;
-    ic->desc.reqevents = APR_POLLIN;
-
-    rv = ctx->pollset_add(ctx->pollset_baton,
-                         &ic->desc, &ic->baton);
-    *client = ic;
-
-    return rv;
-}
-
-
-apr_status_t serf_listener_create(
-    serf_listener_t **listener,
-    serf_context_t *ctx,
-    const char *host,
-    apr_uint16_t port,
-    void *accept_baton,
-    serf_accept_client_t accept,
-    apr_pool_t *pool)
-{
-    apr_sockaddr_t *sa;
-    apr_status_t rv;
-    serf_listener_t *l = apr_palloc(pool, sizeof(*l));
-
-    l->ctx = ctx;
-    l->baton.type = SERF_IO_LISTENER;
-    l->baton.u.listener = l;
-    l->accept_func = accept;
-    l->accept_baton = accept_baton;
-
-    apr_pool_create(&l->pool, pool);
-
-    rv = apr_sockaddr_info_get(&sa, host, APR_UNSPEC, port, 0, l->pool);
-    if (rv)
-        return rv;
-
-    rv = apr_socket_create(&l->skt, sa->family,
-                           SOCK_STREAM,
-#if APR_MAJOR_VERSION > 0
-                           APR_PROTO_TCP,
-#endif
-                           l->pool);
-    if (rv)
-        return rv;
-
-    rv = apr_socket_opt_set(l->skt, APR_SO_REUSEADDR, 1);
-    if (rv)
-        return rv;
-
-    rv = apr_socket_bind(l->skt, sa);
-    if (rv)
-        return rv;
-
-    rv = apr_socket_listen(l->skt, 5);
-    if (rv)
-        return rv;
-
-    l->desc.desc_type = APR_POLL_SOCKET;
-    l->desc.desc.s = l->skt;
-    l->desc.reqevents = APR_POLLIN;
-
-    rv = ctx->pollset_add(ctx->pollset_baton,
-                            &l->desc, &l->baton);
-    if (rv)
-        return rv;
-
-    *listener = l;
-
-    return APR_SUCCESS;
-}

Copied: vendor/serf/1.3.9/incoming.c (from rev 9259, vendor/serf/dist/incoming.c)
===================================================================
--- vendor/serf/1.3.9/incoming.c	                        (rev 0)
+++ vendor/serf/1.3.9/incoming.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,181 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_pools.h>
+#include <apr_poll.h>
+#include <apr_version.h>
+
+#include "serf.h"
+#include "serf_bucket_util.h"
+
+#include "serf_private.h"
+
+static apr_status_t read_from_client(serf_incoming_t *client)
+{
+    return APR_ENOTIMPL;
+}
+
+static apr_status_t write_to_client(serf_incoming_t *client)
+{
+    return APR_ENOTIMPL;
+}
+
+apr_status_t serf__process_client(serf_incoming_t *client, apr_int16_t events)
+{
+    apr_status_t rv;
+    if ((events & APR_POLLIN) != 0) {
+        rv = read_from_client(client);
+        if (rv) {
+            return rv;
+        }
+    }
+
+    if ((events & APR_POLLHUP) != 0) {
+        return APR_ECONNRESET;
+    }
+
+    if ((events & APR_POLLERR) != 0) {
+        return APR_EGENERAL;
+    }
+
+    if ((events & APR_POLLOUT) != 0) {
+        rv = write_to_client(client);
+        if (rv) {
+            return rv;
+        }
+    }
+
+    return APR_SUCCESS;
+}
+
+apr_status_t serf__process_listener(serf_listener_t *l)
+{
+    apr_status_t rv;
+    apr_socket_t *in;
+    apr_pool_t *p;
+    /* THIS IS NOT OPTIMAL */
+    apr_pool_create(&p, l->pool);
+
+    rv = apr_socket_accept(&in, l->skt, p);
+
+    if (rv) {
+        apr_pool_destroy(p);
+        return rv;
+    }
+
+    rv = l->accept_func(l->ctx, l, l->accept_baton, in, p);
+
+    if (rv) {
+        apr_pool_destroy(p);
+        return rv;
+    }
+
+    return rv;
+}
+
+
+apr_status_t serf_incoming_create(
+    serf_incoming_t **client,
+    serf_context_t *ctx,
+    apr_socket_t *insock,
+    void *request_baton,
+    serf_incoming_request_cb_t request,
+    apr_pool_t *pool)
+{
+    apr_status_t rv;
+    serf_incoming_t *ic = apr_palloc(pool, sizeof(*ic));
+
+    ic->ctx = ctx;
+    ic->baton.type = SERF_IO_CLIENT;
+    ic->baton.u.client = ic;
+    ic->request_baton =  request_baton;
+    ic->request = request;
+    ic->skt = insock;
+    ic->desc.desc_type = APR_POLL_SOCKET;
+    ic->desc.desc.s = ic->skt;
+    ic->desc.reqevents = APR_POLLIN;
+
+    rv = ctx->pollset_add(ctx->pollset_baton,
+                         &ic->desc, &ic->baton);
+    *client = ic;
+
+    return rv;
+}
+
+
+apr_status_t serf_listener_create(
+    serf_listener_t **listener,
+    serf_context_t *ctx,
+    const char *host,
+    apr_uint16_t port,
+    void *accept_baton,
+    serf_accept_client_t accept,
+    apr_pool_t *pool)
+{
+    apr_sockaddr_t *sa;
+    apr_status_t rv;
+    serf_listener_t *l = apr_palloc(pool, sizeof(*l));
+
+    l->ctx = ctx;
+    l->baton.type = SERF_IO_LISTENER;
+    l->baton.u.listener = l;
+    l->accept_func = accept;
+    l->accept_baton = accept_baton;
+
+    apr_pool_create(&l->pool, pool);
+
+    rv = apr_sockaddr_info_get(&sa, host, APR_UNSPEC, port, 0, l->pool);
+    if (rv)
+        return rv;
+
+    rv = apr_socket_create(&l->skt, sa->family,
+                           SOCK_STREAM,
+#if APR_MAJOR_VERSION > 0
+                           APR_PROTO_TCP,
+#endif
+                           l->pool);
+    if (rv)
+        return rv;
+
+    rv = apr_socket_opt_set(l->skt, APR_SO_REUSEADDR, 1);
+    if (rv)
+        return rv;
+
+    rv = apr_socket_bind(l->skt, sa);
+    if (rv)
+        return rv;
+
+    rv = apr_socket_listen(l->skt, 5);
+    if (rv)
+        return rv;
+
+    l->desc.desc_type = APR_POLL_SOCKET;
+    l->desc.desc.s = l->skt;
+    l->desc.reqevents = APR_POLLIN;
+
+    rv = ctx->pollset_add(ctx->pollset_baton,
+                            &l->desc, &l->baton);
+    if (rv)
+        return rv;
+
+    *listener = l;
+
+    return APR_SUCCESS;
+}

Deleted: vendor/serf/1.3.9/outgoing.c
===================================================================
--- vendor/serf/dist/outgoing.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/outgoing.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,1744 +0,0 @@
-/* Copyright 2002-2004 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_pools.h>
-#include <apr_poll.h>
-#include <apr_version.h>
-#include <apr_portable.h>
-
-#include "serf.h"
-#include "serf_bucket_util.h"
-
-#include "serf_private.h"
-
-/* cleanup for sockets */
-static apr_status_t clean_skt(void *data)
-{
-    serf_connection_t *conn = data;
-    apr_status_t status = APR_SUCCESS;
-
-    if (conn->skt) {
-        serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt, "cleanup - ");
-        status = apr_socket_close(conn->skt);
-        conn->skt = NULL;
-        serf__log_nopref(SOCK_VERBOSE, "closed socket, status %d\n", status);
-    }
-
-    return status;
-}
-
-static apr_status_t clean_resp(void *data)
-{
-    serf_request_t *request = data;
-
-    /* The request's RESPOOL is being cleared.  */
-
-    /* If the response has allocated some buckets, then destroy them (since
-       the bucket may hold resources other than memory in RESPOOL). Also
-       make sure to set their fields to NULL so connection closure does
-       not attempt to free them again.  */
-    if (request->resp_bkt) {
-        serf_bucket_destroy(request->resp_bkt);
-        request->resp_bkt = NULL;
-    }
-    if (request->req_bkt) {
-        serf_bucket_destroy(request->req_bkt);
-        request->req_bkt = NULL;
-    }
-
-    /* ### should we worry about debug stuff, like that performed in
-       ### destroy_request()? should we worry about calling req->handler
-       ### to notify this "cancellation" due to pool clearing?  */
-
-    /* This pool just got cleared/destroyed. Don't try to destroy the pool
-       (again) when the request is canceled.  */
-    request->respool = NULL;
-
-    return APR_SUCCESS;
-}
-
-/* cleanup for conns */
-static apr_status_t clean_conn(void *data)
-{
-    serf_connection_t *conn = data;
-
-    serf__log(CONN_VERBOSE, __FILE__, "cleaning up connection 0x%x\n",
-              conn);
-    serf_connection_close(conn);
-
-    return APR_SUCCESS;
-}
-
-/* Check if there is data waiting to be sent over the socket. This can happen
-   in two situations:
-   - The connection queue has atleast one request with unwritten data.
-   - All requests are written and the ssl layer wrote some data while reading
-     the response. This can happen when the server triggers a renegotiation,
-     e.g. after the first and only request on that connection was received.
-   Returns 1 if data is pending on CONN, NULL if not.
-   If NEXT_REQ is not NULL, it will be filled in with the next available request
-   with unwritten data. */
-static int
-request_or_data_pending(serf_request_t **next_req, serf_connection_t *conn)
-{
-    serf_request_t *request = conn->requests;
-
-    while (request != NULL && request->req_bkt == NULL &&
-           request->writing_started)
-        request = request->next;
-
-    if (next_req)
-        *next_req = request;
-
-    if (request != NULL) {
-        return 1;
-    } else if (conn->ostream_head) {
-        const char *dummy;
-        apr_size_t len;
-        apr_status_t status;
-
-        status = serf_bucket_peek(conn->ostream_head, &dummy,
-                                  &len);
-        if (!SERF_BUCKET_READ_ERROR(status) && len) {
-            serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt,
-                          "All requests written but still data pending.\n");
-            return 1;
-        }
-    }
-
-    return 0;
-}
-
-/* Update the pollset for this connection. We tweak the pollset based on
- * whether we want to read and/or write, given conditions within the
- * connection. If the connection is not (yet) in the pollset, then it
- * will be added.
- */
-apr_status_t serf__conn_update_pollset(serf_connection_t *conn)
-{
-    serf_context_t *ctx = conn->ctx;
-    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 = ctx->pollset_rm(ctx->pollset_baton,
-                             &desc, conn);
-    if (status && !APR_STATUS_IS_NOTFOUND(status))
-        return status;
-
-    /* Now put it back in with the correct read/write values. */
-    desc.reqevents = APR_POLLHUP | APR_POLLERR;
-    if (conn->requests &&
-        conn->state != SERF_CONN_INIT) {
-        /* If there are any outstanding events, then we want to read. */
-        /* ### not true. we only want to read IF we have sent some data */
-        desc.reqevents |= APR_POLLIN;
-
-        /* Don't write if OpenSSL told us that it needs to read data first. */
-        if (conn->stop_writing != 1) {
-
-            /* If the connection is not closing down and
-             *   has unwritten data or
-             *   there are any requests that still have buckets to write out,
-             *     then we want to write.
-             */
-            if (conn->vec_len &&
-                conn->state != SERF_CONN_CLOSING)
-                desc.reqevents |= APR_POLLOUT;
-            else {
-
-                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 if (request_or_data_pending(NULL, conn)) {
-                    desc.reqevents |= APR_POLLOUT;
-                }
-            }
-        }
-    }
-
-    /* If we can have async responses, always look for something to read. */
-    if (conn->async_responses) {
-        desc.reqevents |= APR_POLLIN;
-    }
-
-    /* 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 ctx->pollset_add(ctx->pollset_baton,
-                            &desc, &conn->baton);
-}
-
-#ifdef SERF_DEBUG_BUCKET_USE
-
-/* Make sure all response buckets were drained. */
-static void check_buckets_drained(serf_connection_t *conn)
-{
-    serf_request_t *request = conn->requests;
-
-    for ( ; request ; request = request->next ) {
-        if (request->resp_bkt != NULL) {
-            /* ### crap. can't do this. this allocator may have un-drained
-             * ### REQUEST buckets.
-             */
-            /* serf_debug__entered_loop(request->resp_bkt->allocator); */
-            /* ### for now, pretend we closed the conn (resets the tracking) */
-            serf_debug__closed_conn(request->resp_bkt->allocator);
-        }
-    }
-}
-
-#endif
-
-static void destroy_ostream(serf_connection_t *conn)
-{
-    if (conn->ostream_head != NULL) {
-        serf_bucket_destroy(conn->ostream_head);
-        conn->ostream_head = NULL;
-        conn->ostream_tail = NULL;
-    }
-}
-
-static apr_status_t detect_eof(void *baton, serf_bucket_t *aggregate_bucket)
-{
-    serf_connection_t *conn = baton;
-    conn->hit_eof = 1;
-    return APR_EAGAIN;
-}
-
-static apr_status_t do_conn_setup(serf_connection_t *conn)
-{
-    apr_status_t status;
-    serf_bucket_t *ostream;
-
-    if (conn->ostream_head == NULL) {
-        conn->ostream_head = serf_bucket_aggregate_create(conn->allocator);
-    }
-
-    if (conn->ostream_tail == NULL) {
-        conn->ostream_tail = serf__bucket_stream_create(conn->allocator,
-                                                        detect_eof,
-                                                        conn);
-    }
-
-    ostream = conn->ostream_tail;
-
-    status = (*conn->setup)(conn->skt,
-                            &conn->stream,
-                            &ostream,
-                            conn->setup_baton,
-                            conn->pool);
-    if (status) {
-        /* extra destroy here since it wasn't added to the head bucket yet. */
-        serf_bucket_destroy(conn->ostream_tail);
-        destroy_ostream(conn);
-        return status;
-    }
-
-    serf_bucket_aggregate_append(conn->ostream_head,
-                                 ostream);
-
-    return status;
-}
-
-/* Set up the input and output stream buckets.
- When a tunnel over an http proxy is needed, create a socket bucket and
- empty aggregate bucket for sending and receiving unencrypted requests
- over the socket.
-
- After the tunnel is there, or no tunnel was needed, ask the application
- to create the input and output buckets, which should take care of the
- [en/de]cryption.
- */
-
-static apr_status_t prepare_conn_streams(serf_connection_t *conn,
-                                         serf_bucket_t **istream,
-                                         serf_bucket_t **ostreamt,
-                                         serf_bucket_t **ostreamh)
-{
-    apr_status_t status;
-
-    if (conn->stream == NULL) {
-        conn->latency = apr_time_now() - conn->connect_time;
-    }
-
-    /* Do we need a SSL tunnel first? */
-    if (conn->state == SERF_CONN_CONNECTED) {
-        /* If the connection does not have an associated bucket, then
-         * call the setup callback to get one.
-         */
-        if (conn->stream == NULL) {
-            status = do_conn_setup(conn);
-            if (status) {
-                return status;
-            }
-        }
-        *ostreamt = conn->ostream_tail;
-        *ostreamh = conn->ostream_head;
-        *istream = conn->stream;
-    } else {
-        /* SSL tunnel needed and not set up yet, get a direct unencrypted
-         stream for this socket */
-        if (conn->stream == NULL) {
-            *istream = serf_bucket_socket_create(conn->skt,
-                                                 conn->allocator);
-        }
-        /* Don't create the ostream bucket chain including the ssl_encrypt
-         bucket yet. This ensure the CONNECT request is sent unencrypted
-         to the proxy. */
-        *ostreamt = *ostreamh = conn->ssltunnel_ostream;
-    }
-
-    return APR_SUCCESS;
-}
-
-/* Create and connect sockets for any connections which don't have them
- * yet. This is the core of our lazy-connect behavior.
- */
-apr_status_t serf__open_connections(serf_context_t *ctx)
-{
-    int i;
-
-    for (i = ctx->conns->nelts; i--; ) {
-        serf_connection_t *conn = GET_CONN(ctx, i);
-        serf__authn_info_t *authn_info;
-        apr_status_t status;
-        apr_socket_t *skt;
-
-        conn->seen_in_pollset = 0;
-
-        if (conn->skt != NULL) {
-#ifdef SERF_DEBUG_BUCKET_USE
-            check_buckets_drained(conn);
-#endif
-            continue;
-        }
-
-        /* Delay opening until we have something to deliver! */
-        if (conn->requests == NULL) {
-            continue;
-        }
-
-        apr_pool_clear(conn->skt_pool);
-        apr_pool_cleanup_register(conn->skt_pool, conn, clean_skt, clean_skt);
-
-        status = apr_socket_create(&skt, conn->address->family,
-                                   SOCK_STREAM,
-#if APR_MAJOR_VERSION > 0
-                                   APR_PROTO_TCP,
-#endif
-                                   conn->skt_pool);
-        serf__log(SOCK_VERBOSE, __FILE__,
-                  "created socket for conn 0x%x, status %d\n", conn, status);
-        if (status != APR_SUCCESS)
-            return status;
-
-        /* Set the socket to be non-blocking */
-        if ((status = apr_socket_timeout_set(skt, 0)) != APR_SUCCESS)
-            return status;
-
-        /* Disable Nagle's algorithm */
-        if ((status = apr_socket_opt_set(skt,
-                                         APR_TCP_NODELAY, 1)) != APR_SUCCESS)
-            return status;
-
-        /* Configured. Store it into the connection now. */
-        conn->skt = skt;
-
-        /* Remember time when we started connecting to server to calculate
-           network latency. */
-        conn->connect_time = apr_time_now();
-
-        /* Now that the socket is set up, let's connect it. This should
-         * return immediately.
-         */
-        status = apr_socket_connect(skt, conn->address);
-        serf__log_skt(SOCK_VERBOSE, __FILE__, skt,
-                      "connected socket for conn 0x%x, status %d\n",
-                      conn, status);
-        if (status != APR_SUCCESS) {
-            if (!APR_STATUS_IS_EINPROGRESS(status))
-                return status;
-        }
-
-        /* Flag our pollset as dirty now that we have a new socket. */
-        conn->dirty_conn = 1;
-        ctx->dirty_pollset = 1;
-
-        /* If the authentication was already started on another connection,
-           prepare this connection (it might be possible to skip some
-           part of the handshaking). */
-        if (ctx->proxy_address) {
-            authn_info = &ctx->proxy_authn_info;
-            if (authn_info->scheme) {
-                authn_info->scheme->init_conn_func(authn_info->scheme, 407,
-                                                   conn, conn->pool);
-            }
-        }
-
-        authn_info = serf__get_authn_info_for_server(conn);
-        if (authn_info->scheme) {
-            authn_info->scheme->init_conn_func(authn_info->scheme, 401,
-                                               conn, conn->pool);
-        }
-
-        /* Does this connection require a SSL tunnel over the proxy? */
-        if (ctx->proxy_address && strcmp(conn->host_info.scheme, "https") == 0)
-            serf__ssltunnel_connect(conn);
-        else {
-            serf_bucket_t *dummy1, *dummy2;
-
-            conn->state = SERF_CONN_CONNECTED;
-
-            status = prepare_conn_streams(conn, &conn->stream,
-                                          &dummy1, &dummy2);
-            if (status) {
-                return status;
-            }
-        }
-    }
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t no_more_writes(serf_connection_t *conn)
-{
-    /* Note that we should hold new requests until we open our new socket. */
-    conn->state = SERF_CONN_CLOSING;
-    serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt,
-                  "stop writing on conn 0x%x\n", conn);
-
-    /* Clear our iovec. */
-    conn->vec_len = 0;
-
-    /* Update the pollset to know we don't want to write on this socket any
-     * more.
-     */
-    conn->dirty_conn = 1;
-    conn->ctx->dirty_pollset = 1;
-    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)
-{
-    if (*list == NULL) {
-        *list = request;
-        *tail = request;
-    }
-    else {
-        (*tail)->next = request;
-        *tail = request;
-    }
-}
-
-static apr_status_t destroy_request(serf_request_t *request)
-{
-    serf_connection_t *conn = request->conn;
-
-    /* The request and response buckets are no longer needed,
-       nor is the request's pool.  */
-    if (request->resp_bkt) {
-        serf_debug__closed_conn(request->resp_bkt->allocator);
-        serf_bucket_destroy(request->resp_bkt);
-        request->resp_bkt = NULL;
-    }
-    if (request->req_bkt) {
-        serf_debug__closed_conn(request->req_bkt->allocator);
-        serf_bucket_destroy(request->req_bkt);
-        request->req_bkt = NULL;
-    }
-
-    serf_debug__bucket_alloc_check(request->allocator);
-    if (request->respool) {
-        /* ### unregister the pool cleanup for self?  */
-        apr_pool_destroy(request->respool);
-    }
-
-    serf_bucket_mem_free(conn->allocator, request);
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t cancel_request(serf_request_t *request,
-                                   serf_request_t **list,
-                                   int notify_request)
-{
-    /* If we haven't run setup, then we won't have a handler to call. */
-    if (request->handler && notify_request) {
-        /* We actually don't care what the handler returns.
-         * We have bigger matters at hand.
-         */
-        (*request->handler)(request, NULL, request->handler_baton,
-                            request->respool);
-    }
-
-    if (*list == request) {
-        *list = request->next;
-    }
-    else {
-        serf_request_t *scan = *list;
-
-        while (scan->next && scan->next != request)
-            scan = scan->next;
-
-        if (scan->next) {
-            scan->next = scan->next->next;
-        }
-    }
-
-    return destroy_request(request);
-}
-
-static apr_status_t remove_connection(serf_context_t *ctx,
-                                      serf_connection_t *conn)
-{
-    apr_pollfd_t desc = { 0 };
-
-    desc.desc_type = APR_POLL_SOCKET;
-    desc.desc.s = conn->skt;
-    desc.reqevents = conn->reqevents;
-
-    return ctx->pollset_rm(ctx->pollset_baton,
-                           &desc, conn);
-}
-
-/* A socket was closed, inform the application. */
-static void handle_conn_closed(serf_connection_t *conn, apr_status_t status)
-{
-    (*conn->closed)(conn, conn->closed_baton, status,
-                    conn->pool);
-}
-
-static apr_status_t reset_connection(serf_connection_t *conn,
-                                     int requeue_requests)
-{
-    serf_context_t *ctx = conn->ctx;
-    apr_status_t status;
-    serf_request_t *old_reqs;
-
-    conn->probable_keepalive_limit = conn->completed_responses;
-    conn->completed_requests = 0;
-    conn->completed_responses = 0;
-
-    old_reqs = conn->requests;
-
-    conn->requests = NULL;
-    conn->requests_tail = NULL;
-
-    /* Handle all outstanding requests. These have either not been written yet,
-       or have been written but the expected reply wasn't received yet. */
-    while (old_reqs) {
-        /* If we haven't started to write the connection, bring it over
-         * unchanged to our new socket.
-         * Do not copy a CONNECT request to the new connection, the ssl tunnel
-         * setup code will create a new CONNECT request already.
-         */
-        if (requeue_requests && !old_reqs->writing_started &&
-            !old_reqs->ssltunnel) {
-
-            serf_request_t *req = old_reqs;
-            old_reqs = old_reqs->next;
-            req->next = NULL;
-            link_requests(&conn->requests, &conn->requests_tail, req);
-        }
-        else {
-            /* Request has been consumed, or we don't want to requeue the
-               request. Either way, inform the application that the request
-               is cancelled. */
-            cancel_request(old_reqs, &old_reqs, requeue_requests);
-        }
-    }
-
-    /* Requests queue has been prepared for a new socket, close the old one. */
-    if (conn->skt != NULL) {
-        remove_connection(ctx, conn);
-        status = apr_socket_close(conn->skt);
-        serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt,
-                      "closed socket, status %d\n", status);
-        if (conn->closed != NULL) {
-            handle_conn_closed(conn, status);
-        }
-        conn->skt = NULL;
-    }
-
-    if (conn->stream != NULL) {
-        serf_bucket_destroy(conn->stream);
-        conn->stream = NULL;
-    }
-
-    destroy_ostream(conn);
-
-    /* Don't try to resume any writes */
-    conn->vec_len = 0;
-
-    conn->dirty_conn = 1;
-    conn->ctx->dirty_pollset = 1;
-    conn->state = SERF_CONN_INIT;
-
-    serf__log(CONN_VERBOSE, __FILE__, "reset connection 0x%x\n", conn);
-
-    conn->status = APR_SUCCESS;
-
-    /* Let our context know that we've 'reset' the socket already. */
-    conn->seen_in_pollset |= APR_POLLHUP;
-
-    /* Found the connection. Closed it. All done. */
-    return APR_SUCCESS;
-}
-
-static apr_status_t socket_writev(serf_connection_t *conn)
-{
-    apr_size_t written;
-    apr_status_t status;
-
-    status = apr_socket_sendv(conn->skt, conn->vec,
-                              conn->vec_len, &written);
-    if (status && !APR_STATUS_IS_EAGAIN(status))
-        serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt,
-                      "socket_sendv error %d\n", status);
-
-    /* did we write everything? */
-    if (written) {
-        apr_size_t len = 0;
-        int i;
-
-        serf__log_skt(SOCK_MSG_VERBOSE, __FILE__, conn->skt,
-                      "--- socket_sendv:\n");
-
-        for (i = 0; i < conn->vec_len; i++) {
-            len += conn->vec[i].iov_len;
-            if (written < len) {
-                serf__log_nopref(SOCK_MSG_VERBOSE, "%.*s",
-                                   conn->vec[i].iov_len - (len - written),
-                                   conn->vec[i].iov_base);
-                if (i) {
-                    memmove(conn->vec, &conn->vec[i],
-                            sizeof(struct iovec) * (conn->vec_len - i));
-                    conn->vec_len -= i;
-                }
-                conn->vec[0].iov_base = (char *)conn->vec[0].iov_base + (conn->vec[0].iov_len - (len - written));
-                conn->vec[0].iov_len = len - written;
-                break;
-            } else {
-                serf__log_nopref(SOCK_MSG_VERBOSE, "%.*s",
-                                   conn->vec[i].iov_len, conn->vec[i].iov_base);
-            }
-        }
-        if (len == written) {
-            conn->vec_len = 0;
-        }
-        serf__log_nopref(SOCK_MSG_VERBOSE, "-(%d)-\n", written);
-
-        /* Log progress information */
-        serf__context_progress_delta(conn->ctx, 0, written);
-    }
-
-    return status;
-}
-
-static apr_status_t setup_request(serf_request_t *request)
-{
-    serf_connection_t *conn = request->conn;
-    apr_status_t status;
-
-    /* Now that we are about to serve the request, allocate a pool. */
-    apr_pool_create(&request->respool, conn->pool);
-    request->allocator = serf_bucket_allocator_create(request->respool,
-                                                      NULL, NULL);
-    apr_pool_cleanup_register(request->respool, request,
-                              clean_resp, clean_resp);
-
-    /* Fill in the rest of the values for the request. */
-    status = request->setup(request, request->setup_baton,
-                            &request->req_bkt,
-                            &request->acceptor,
-                            &request->acceptor_baton,
-                            &request->handler,
-                            &request->handler_baton,
-                            request->respool);
-    return status;
-}
-
-/* write data out to the connection */
-static apr_status_t write_to_connection(serf_connection_t *conn)
-{
-    if (conn->probable_keepalive_limit &&
-        conn->completed_requests > conn->probable_keepalive_limit) {
-
-        conn->dirty_conn = 1;
-        conn->ctx->dirty_pollset = 1;
-
-        /* backoff for now. */
-        return APR_SUCCESS;
-    }
-
-    /* Keep reading and sending until we run out of stuff to read, or
-     * writing would block.
-     */
-    while (1) {
-        serf_request_t *request;
-        int stop_reading = 0;
-        apr_status_t status;
-        apr_status_t read_status;
-        serf_bucket_t *ostreamt;
-        serf_bucket_t *ostreamh;
-        int max_outstanding_requests = conn->max_outstanding_requests;
-
-        /* If we're setting up an ssl tunnel, we can't send real requests
-           at yet, as they need to be encrypted and our encrypt buckets
-           aren't created yet as we still need to read the unencrypted
-           response of the CONNECT request. */
-        if (conn->state != SERF_CONN_CONNECTED)
-            max_outstanding_requests = 1;
-
-        if (max_outstanding_requests &&
-            conn->completed_requests -
-                conn->completed_responses >= 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);
-
-            /* If the write would have blocked, then we're done. Don't try
-             * to write anything else to the socket.
-             */
-            if (APR_STATUS_IS_EAGAIN(status))
-                return APR_SUCCESS;
-            if (APR_STATUS_IS_EPIPE(status) ||
-                APR_STATUS_IS_ECONNRESET(status) ||
-                APR_STATUS_IS_ECONNABORTED(status))
-                return no_more_writes(conn);
-            if (status)
-                return status;
-        }
-        /* ### can we have a short write, yet no EAGAIN? a short write
-           ### would imply unwritten_len > 0 ... */
-        /* assert: unwritten_len == 0. */
-
-        /* We may need to move forward to a request which has something
-         * to write.
-         */
-        if (!request_or_data_pending(&request, conn)) {
-            /* No more requests (with data) are registered with the
-             * connection, and no data is pending on the outgoing stream.
-             * Let's update the pollset so that we don't try to write to this
-             * socket again.
-             */
-            conn->dirty_conn = 1;
-            conn->ctx->dirty_pollset = 1;
-            return APR_SUCCESS;
-        }
-
-        status = prepare_conn_streams(conn, &conn->stream, &ostreamt, &ostreamh);
-        if (status) {
-            return status;
-        }
-
-        if (request) {
-            if (request->req_bkt == NULL) {
-                read_status = setup_request(request);
-                if (read_status) {
-                    /* Something bad happened. Propagate any errors. */
-                    return read_status;
-                }
-            }
-
-            if (!request->writing_started) {
-                request->writing_started = 1;
-                serf_bucket_aggregate_append(ostreamt, request->req_bkt);
-            }
-        }
-
-        /* ### optimize at some point by using read_for_sendfile */
-        /* TODO: now that read_iovec will effectively try to return as much
-           data as available, we probably don't want to read ALL_AVAIL, but
-           a lower number, like the size of one or a few TCP packets, the
-           available TCP buffer size ... */
-        read_status = serf_bucket_read_iovec(ostreamh,
-                                             SERF_READ_ALL_AVAIL,
-                                             IOV_MAX,
-                                             conn->vec,
-                                             &conn->vec_len);
-
-        if (!conn->hit_eof) {
-            if (APR_STATUS_IS_EAGAIN(read_status)) {
-                /* We read some stuff, but should not try to read again. */
-                stop_reading = 1;
-            }
-            else if (read_status == SERF_ERROR_WAIT_CONN) {
-                /* The bucket told us that it can't provide more data until
-                   more data is read from the socket. This normally happens
-                   during a SSL handshake.
-
-                   We should avoid looking for writability for a while so
-                   that (hopefully) something will appear in the bucket so
-                   we can actually write something. otherwise, we could
-                   end up in a CPU spin: socket wants something, but we
-                   don't have anything (and keep returning EAGAIN)
-                 */
-                conn->stop_writing = 1;
-                conn->dirty_conn = 1;
-                conn->ctx->dirty_pollset = 1;
-            }
-            else if (read_status && !APR_STATUS_IS_EOF(read_status)) {
-                /* Something bad happened. Propagate any errors. */
-                return read_status;
-            }
-        }
-
-        /* If we got some data, then deliver it. */
-        /* ### what to do if we got no data?? is that a problem? */
-        if (conn->vec_len > 0) {
-            status = socket_writev(conn);
-
-            /* If we can't write any more, or an error occurred, then
-             * we're done here.
-             */
-            if (APR_STATUS_IS_EAGAIN(status))
-                return APR_SUCCESS;
-            if (APR_STATUS_IS_EPIPE(status))
-                return no_more_writes(conn);
-            if (APR_STATUS_IS_ECONNRESET(status) ||
-                APR_STATUS_IS_ECONNABORTED(status)) {
-                return no_more_writes(conn);
-            }
-            if (status)
-                return status;
-        }
-
-        if (read_status == SERF_ERROR_WAIT_CONN) {
-            stop_reading = 1;
-            conn->stop_writing = 1;
-            conn->dirty_conn = 1;
-            conn->ctx->dirty_pollset = 1;
-        }
-        else if (request && read_status && conn->hit_eof &&
-                 conn->vec_len == 0) {
-            /* If we hit the end of the request bucket and all of its data has
-             * been written, then clear it out to signify that we're done
-             * sending the request. On the next iteration through this loop:
-             * - if there are remaining bytes they will be written, and as the 
-             * request bucket will be completely read it will be destroyed then.
-             * - we'll see if there are other requests that need to be sent 
-             * ("pipelining").
-             */
-            conn->hit_eof = 0;
-            serf_bucket_destroy(request->req_bkt);
-            request->req_bkt = NULL;
-
-            /* If our connection has async responses enabled, we're not
-             * going to get a reply back, so kill the request.
-             */
-            if (conn->async_responses) {
-                conn->requests = request->next;
-                destroy_request(request);
-            }
-
-            conn->completed_requests++;
-
-            if (conn->probable_keepalive_limit &&
-                conn->completed_requests > conn->probable_keepalive_limit) {
-                /* backoff for now. */
-                stop_reading = 1;
-            }
-        }
-
-        if (stop_reading) {
-            return APR_SUCCESS;
-        }
-    }
-    /* NOTREACHED */
-}
-
-/* A response message was received from the server, so call
-   the handler as specified on the original request. */
-static apr_status_t handle_response(serf_request_t *request,
-                                    apr_pool_t *pool)
-{
-    apr_status_t status = APR_SUCCESS;
-    int consumed_response = 0;
-
-    /* Only enable the new authentication framework if the program has
-     * registered an authentication credential callback.
-     *
-     * This permits older Serf apps to still handle authentication
-     * themselves by not registering credential callbacks.
-     */
-    if (request->conn->ctx->cred_cb) {
-      status = serf__handle_auth_response(&consumed_response,
-                                          request,
-                                          request->resp_bkt,
-                                          request->handler_baton,
-                                          pool);
-
-      /* If there was an error reading the response (maybe there wasn't
-         enough data available), don't bother passing the response to the
-         application.
-
-         If the authentication was tried, but failed, pass the response
-         to the application, maybe it can do better. */
-      if (status) {
-          return status;
-      }
-    }
-
-    if (!consumed_response) {
-        return (*request->handler)(request,
-                                   request->resp_bkt,
-                                   request->handler_baton,
-                                   pool);
-    }
-
-    return status;
-}
-
-/* An async response message was received from the server. */
-static apr_status_t handle_async_response(serf_connection_t *conn,
-                                          apr_pool_t *pool)
-{
-    apr_status_t status;
-
-    if (conn->current_async_response == NULL) {
-        conn->current_async_response =
-            (*conn->async_acceptor)(NULL, conn->stream,
-                                    conn->async_acceptor_baton, pool);
-    }
-
-    status = (*conn->async_handler)(NULL, conn->current_async_response,
-                                    conn->async_handler_baton, pool);
-
-    if (APR_STATUS_IS_EOF(status)) {
-        serf_bucket_destroy(conn->current_async_response);
-        conn->current_async_response = NULL;
-        status = APR_SUCCESS;
-    }
-
-    return status;
-}
-
-
-apr_status_t
-serf__provide_credentials(serf_context_t *ctx,
-                          char **username,
-                          char **password,
-                          serf_request_t *request, void *baton,
-                          int code, const char *authn_type,
-                          const char *realm,
-                          apr_pool_t *pool)
-{
-    serf_connection_t *conn = request->conn;
-    serf_request_t *authn_req = request;
-    apr_status_t status;
-
-    if (request->ssltunnel == 1 &&
-        conn->state == SERF_CONN_SETUP_SSLTUNNEL) {
-        /* This is a CONNECT request to set up an SSL tunnel over a proxy.
-           This request is created by serf, so if the proxy requires
-           authentication, we can't ask the application for credentials with
-           this request.
-
-           Solution: setup the first request created by the application on
-           this connection, and use that request and its handler_baton to
-           call back to the application. */
-
-        authn_req = request->next;
-        /* assert: app_request != NULL */
-        if (!authn_req)
-            return APR_EGENERAL;
-
-        if (!authn_req->req_bkt) {
-            apr_status_t status;
-
-            status = setup_request(authn_req);
-            /* If we can't setup a request, don't bother setting up the
-               ssl tunnel. */
-            if (status)
-                return status;
-        }
-    }
-
-    /* Ask the application. */
-    status = (*ctx->cred_cb)(username, password,
-                             authn_req, authn_req->handler_baton,
-                             code, authn_type, realm, pool);
-    if (status)
-        return status;
-
-    return APR_SUCCESS;
-}
-
-/* read data from the connection */
-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.
-     */
-    serf_request_t *request = conn->requests;
-
-    /* If the stop_writing flag was set on the connection, reset it now because
-       there is some data to read. */
-    if (conn->stop_writing) {
-        conn->stop_writing = 0;
-        conn->dirty_conn = 1;
-        conn->ctx->dirty_pollset = 1;
-    }
-
-    /* assert: request != NULL */
-
-    if ((status = apr_pool_create(&tmppool, conn->pool)) != APR_SUCCESS)
-        goto error;
-
-    /* Invoke response handlers until we have no more work. */
-    while (1) {
-        serf_bucket_t *dummy1, *dummy2;
-
-        apr_pool_clear(tmppool);
-
-        /* Only interested in the input stream here. */
-        status = prepare_conn_streams(conn, &conn->stream, &dummy1, &dummy2);
-        if (status) {
-            goto error;
-        }
-
-        /* We have a different codepath when we can have async responses. */
-        if (conn->async_responses) {
-            /* TODO What about socket errors? */
-            status = handle_async_response(conn, tmppool);
-            if (APR_STATUS_IS_EAGAIN(status)) {
-                status = APR_SUCCESS;
-                goto error;
-            }
-            if (status) {
-                goto error;
-            }
-            continue;
-        }
-
-        /* We are reading a response for a request we haven't
-         * written yet!
-         *
-         * This shouldn't normally happen EXCEPT:
-         *
-         * 1) when the other end has closed the socket and we're
-         *    pending an EOF return.
-         * 2) Doing the initial SSL handshake - we'll get EAGAIN
-         *    as the SSL buckets will hide the handshake from us
-         *    but not return any data.
-         * 3) When the server sends us an SSL alert.
-         *
-         * In these cases, we should not receive any actual user data.
-         *
-         * 4) When the server sends a error response, like 408 Request timeout.
-         *    This response should be passed to the application.
-         *
-         * If we see an EOF (due to either an expired timeout or the server
-         * sending the SSL 'close notify' shutdown alert), we'll reset the
-         * connection and open a new one.
-         */
-        if (request->req_bkt || !request->writing_started) {
-            const char *data;
-            apr_size_t len;
-
-            status = serf_bucket_peek(conn->stream, &data, &len);
-
-            if (APR_STATUS_IS_EOF(status)) {
-                reset_connection(conn, 1);
-                status = APR_SUCCESS;
-                goto error;
-            }
-            else if (APR_STATUS_IS_EAGAIN(status) && !len) {
-                status = APR_SUCCESS;
-                goto error;
-            } else if (status && !APR_STATUS_IS_EAGAIN(status)) {
-                /* Read error */
-                goto error;
-            }
-
-            /* Unexpected response from the server */
-
-        }
-
-        /* If the request doesn't have a response bucket, then call the
-         * acceptor to get one created.
-         */
-        if (request->resp_bkt == NULL) {
-            request->resp_bkt = (*request->acceptor)(request, conn->stream,
-                                                     request->acceptor_baton,
-                                                     tmppool);
-            apr_pool_clear(tmppool);
-        }
-
-        status = handle_response(request, tmppool);
-
-        /* Some systems will not generate a HUP poll event so we have to
-         * handle the ECONNRESET issue and ECONNABORT here.
-         */
-        if (APR_STATUS_IS_ECONNRESET(status) ||
-            APR_STATUS_IS_ECONNABORTED(status) ||
-            status == SERF_ERROR_REQUEST_LOST) {
-            /* If the connection had ever been good, be optimistic & try again.
-             * If it has never tried again (incl. a retry), fail.
-             */
-            if (conn->completed_responses) {
-                reset_connection(conn, 1);
-                status = APR_SUCCESS;
-            }
-            else if (status == SERF_ERROR_REQUEST_LOST) {
-                status = SERF_ERROR_ABORTED_CONNECTION;
-            }
-            goto error;
-        }
-
-        /* If our response handler says it can't do anything more, we now
-         * treat that as a success.
-         */
-        if (APR_STATUS_IS_EAGAIN(status)) {
-            /* It is possible that while reading the response, the ssl layer
-               has prepared some data to send. If this was the last request,
-               serf will not check for socket writability, so force this here.
-             */
-            if (request_or_data_pending(&request, conn) && !request) {
-                conn->dirty_conn = 1;
-                conn->ctx->dirty_pollset = 1;
-            }
-            status = APR_SUCCESS;
-            goto error;
-        }
-
-        /* If we received APR_SUCCESS, run this loop again. */
-        if (!status) {
-            continue;
-        }
-
-        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.
-             */
-            goto error;
-        }
-
-        /* The response has been fully-read, so that means the request has
-         * either been fully-delivered (most likely), or that we don't need to
-         * write the rest of it anymore, e.g. when a 408 Request timeout was
-         $ received.
-         * Remove it from our queue and loop to read another response.
-         */
-        conn->requests = request->next;
-
-        destroy_request(request);
-
-        request = conn->requests;
-
-        /* If we're truly empty, update our tail. */
-        if (request == NULL) {
-            conn->requests_tail = NULL;
-        }
-
-        conn->completed_responses++;
-
-        /* We've to rebuild pollset since completed_responses is changed. */
-        conn->dirty_conn = 1;
-        conn->ctx->dirty_pollset = 1;
-
-        /* This means that we're being advised that the connection is done. */
-        if (close_connection == SERF_ERROR_CLOSING) {
-            reset_connection(conn, 1);
-            if (APR_STATUS_IS_EOF(status))
-                status = APR_SUCCESS;
-            goto error;
-        }
-
-        /* The server is suddenly deciding to serve more responses than we've
-         * seen before.
-         *
-         * Let our requests go.
-         */
-        if (conn->probable_keepalive_limit &&
-            conn->completed_responses > conn->probable_keepalive_limit) {
-            conn->probable_keepalive_limit = 0;
-        }
-
-        /* If we just ran out of requests or have unwritten requests, then
-         * update the pollset. We don't want to read from this socket any
-         * more. We are definitely done with this loop, too.
-         */
-        if (request == NULL || !request->writing_started) {
-            conn->dirty_conn = 1;
-            conn->ctx->dirty_pollset = 1;
-            status = APR_SUCCESS;
-            goto error;
-        }
-    }
-
-error:
-    apr_pool_destroy(tmppool);
-    return status;
-}
-
-/* process all events on the connection */
-apr_status_t serf__process_connection(serf_connection_t *conn,
-                                      apr_int16_t events)
-{
-    apr_status_t status;
-
-    /* POLLHUP/ERR should come after POLLIN so if there's an error message or
-     * the like sitting on the connection, we give the app a chance to read
-     * it before we trigger a reset condition.
-     */
-    if ((events & APR_POLLIN) != 0) {
-        if ((status = read_from_connection(conn)) != APR_SUCCESS)
-            return status;
-
-        /* If we decided to reset our connection, return now as we don't
-         * want to write.
-         */
-        if ((conn->seen_in_pollset & APR_POLLHUP) != 0) {
-            return APR_SUCCESS;
-        }
-    }
-    if ((events & APR_POLLHUP) != 0) {
-        /* The connection got reset by the server. On Windows this can happen
-           when all data is read, so just cleanup the connection and open
-           a new one.
-           If we haven't had any successful responses on this connection,
-           then error out as it is likely a server issue. */
-        if (conn->completed_responses) {
-            return reset_connection(conn, 1);
-        }
-        return SERF_ERROR_ABORTED_CONNECTION;
-    }
-    if ((events & APR_POLLERR) != 0) {
-        /* We might be talking to a buggy HTTP server that doesn't
-         * do lingering-close.  (httpd < 2.1.8 does this.)
-         *
-         * See:
-         *
-         * http://issues.apache.org/bugzilla/show_bug.cgi?id=35292
-         */
-        if (conn->completed_requests && !conn->probable_keepalive_limit) {
-            return reset_connection(conn, 1);
-        }
-#ifdef SO_ERROR
-        /* If possible, get the error from the platform's socket layer and
-           convert it to an APR status code. */
-        {
-            apr_os_sock_t osskt;
-            if (!apr_os_sock_get(&osskt, conn->skt)) {
-                int error;
-                apr_socklen_t l = sizeof(error);
-
-                if (!getsockopt(osskt, SOL_SOCKET, SO_ERROR, (char*)&error,
-                                &l)) {
-                    status = APR_FROM_OS_ERROR(error);
-
-                    /* Handle fallback for multi-homed servers.
-                     
-                       ### Improve algorithm to find better than just 'next'?
-
-                       Current Windows versions already handle re-ordering for
-                       api users by using statistics on the recently failed
-                       connections to order the list of addresses. */
-                    if (conn->completed_requests == 0
-                        && conn->address->next != NULL
-                        && (APR_STATUS_IS_ECONNREFUSED(status)
-                            || APR_STATUS_IS_TIMEUP(status)
-                            || APR_STATUS_IS_ENETUNREACH(status))) {
-
-                        conn->address = conn->address->next;
-                        return reset_connection(conn, 1);
-                    }
-
-                    return status;
-                  }
-            }
-        }
-#endif
-        return APR_EGENERAL;
-    }
-    if ((events & APR_POLLOUT) != 0) {
-        if ((status = write_to_connection(conn)) != APR_SUCCESS)
-            return status;
-    }
-    return APR_SUCCESS;
-}
-
-serf_connection_t *serf_connection_create(
-    serf_context_t *ctx,
-    apr_sockaddr_t *address,
-    serf_connection_setup_t setup,
-    void *setup_baton,
-    serf_connection_closed_t closed,
-    void *closed_baton,
-    apr_pool_t *pool)
-{
-    serf_connection_t *conn = apr_pcalloc(pool, sizeof(*conn));
-
-    conn->ctx = ctx;
-    conn->status = APR_SUCCESS;
-    /* Ignore server address if proxy was specified. */
-    conn->address = ctx->proxy_address ? ctx->proxy_address : address;
-    conn->setup = setup;
-    conn->setup_baton = setup_baton;
-    conn->closed = closed;
-    conn->closed_baton = closed_baton;
-    conn->pool = pool;
-    conn->allocator = serf_bucket_allocator_create(pool, NULL, NULL);
-    conn->stream = NULL;
-    conn->ostream_head = NULL;
-    conn->ostream_tail = NULL;
-    conn->baton.type = SERF_IO_CONN;
-    conn->baton.u.conn = conn;
-    conn->hit_eof = 0;
-    conn->state = SERF_CONN_INIT;
-    conn->latency = -1; /* unknown */
-
-    /* Create a subpool for our connection. */
-    apr_pool_create(&conn->skt_pool, conn->pool);
-
-    /* register a cleanup */
-    apr_pool_cleanup_register(conn->pool, conn, clean_conn,
-                              apr_pool_cleanup_null);
-
-    /* Add the connection to the context. */
-    *(serf_connection_t **)apr_array_push(ctx->conns) = conn;
-
-    serf__log(CONN_VERBOSE, __FILE__, "created connection 0x%x\n",
-              conn);
-
-    return conn;
-}
-
-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 = APR_SUCCESS;
-    serf_connection_t *c;
-    apr_sockaddr_t *host_address = NULL;
-
-    /* Set the port number explicitly, needed to create the socket later. */
-    if (!host_info.port) {
-        host_info.port = apr_uri_port_of_scheme(host_info.scheme);
-    }
-
-    /* Only lookup the address of the server if no proxy server was
-       configured. */
-    if (!ctx->proxy_address) {
-        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 |
-                                  APR_URI_UNP_OMITUSERINFO);
-
-    /* Store the host info without the path on the connection. */
-    (void)apr_uri_parse(c->pool, c->host_url, &(c->host_info));
-    if (!c->host_info.port) {
-        c->host_info.port = apr_uri_port_of_scheme(c->host_info.scheme);
-    }
-
-    *conn = c;
-
-    return status;
-}
-
-apr_status_t serf_connection_reset(
-    serf_connection_t *conn)
-{
-    return reset_connection(conn, 0);
-}
-
-
-apr_status_t serf_connection_close(
-    serf_connection_t *conn)
-{
-    int i;
-    serf_context_t *ctx = conn->ctx;
-    apr_status_t status;
-
-    for (i = ctx->conns->nelts; i--; ) {
-        serf_connection_t *conn_seq = GET_CONN(ctx, i);
-
-        if (conn_seq == conn) {
-            while (conn->requests) {
-                serf_request_cancel(conn->requests);
-            }
-            if (conn->skt != NULL) {
-                remove_connection(ctx, conn);
-                status = apr_socket_close(conn->skt);
-                serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt,
-                              "closed socket, status %d\n",
-                              status);
-                if (conn->closed != NULL) {
-                    handle_conn_closed(conn, status);
-                }
-                conn->skt = NULL;
-            }
-            if (conn->stream != NULL) {
-                serf_bucket_destroy(conn->stream);
-                conn->stream = NULL;
-            }
-
-            destroy_ostream(conn);
-
-            /* Remove the connection from the context. We don't want to
-             * deal with it any more.
-             */
-            if (i < ctx->conns->nelts - 1) {
-                /* move later connections over this one. */
-                memmove(
-                    &GET_CONN(ctx, i),
-                    &GET_CONN(ctx, i + 1),
-                    (ctx->conns->nelts - i - 1) * sizeof(serf_connection_t *));
-            }
-            --ctx->conns->nelts;
-
-            serf__log(CONN_VERBOSE, __FILE__, "closed connection 0x%x\n",
-                      conn);
-
-            /* Found the connection. Closed it. All done. */
-            return APR_SUCCESS;
-        }
-    }
-
-    /* We didn't find the specified connection. */
-    /* ### doc talks about this w.r.t poll structures. use something else? */
-    return APR_NOTFOUND;
-}
-
-
-void serf_connection_set_max_outstanding_requests(
-    serf_connection_t *conn,
-    unsigned int max_requests)
-{
-    if (max_requests == 0)
-        serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt,
-                      "Set max. nr. of outstanding requests for this "
-                      "connection to unlimited.\n");
-    else
-        serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt,
-                      "Limit max. nr. of outstanding requests for this "
-                      "connection to %u.\n", max_requests);
-
-    conn->max_outstanding_requests = max_requests;
-}
-
-
-void serf_connection_set_async_responses(
-    serf_connection_t *conn,
-    serf_response_acceptor_t acceptor,
-    void *acceptor_baton,
-    serf_response_handler_t handler,
-    void *handler_baton)
-{
-    conn->async_responses = 1;
-    conn->async_acceptor = acceptor;
-    conn->async_acceptor_baton = acceptor_baton;
-    conn->async_handler = handler;
-    conn->async_handler_baton = handler_baton;
-}
-
-static serf_request_t *
-create_request(serf_connection_t *conn,
-               serf_request_setup_t setup,
-               void *setup_baton,
-               int priority,
-               int ssltunnel)
-{
-    serf_request_t *request;
-
-    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->priority = priority;
-    request->writing_started = 0;
-    request->ssltunnel = ssltunnel;
-    request->next = NULL;
-    request->auth_baton = NULL;
-
-    return request;
-}
-
-serf_request_t *serf_connection_request_create(
-    serf_connection_t *conn,
-    serf_request_setup_t setup,
-    void *setup_baton)
-{
-    serf_request_t *request;
-
-    request = create_request(conn, setup, setup_baton,
-                             0, /* priority */
-                             0  /* ssl tunnel */);
-
-    /* Link the request to the end of the request chain. */
-    link_requests(&conn->requests, &conn->requests_tail, request);
-    
-    /* Ensure our pollset becomes writable in context run */
-    conn->ctx->dirty_pollset = 1;
-    conn->dirty_conn = 1;
-
-    return request;
-}
-
-static serf_request_t *
-priority_request_create(serf_connection_t *conn,
-                        int ssltunnelreq,
-                        serf_request_setup_t setup,
-                        void *setup_baton)
-{
-    serf_request_t *request;
-    serf_request_t *iter, *prev;
-
-    request = create_request(conn, setup, setup_baton,
-                             1, /* priority */
-                             ssltunnelreq);
-
-    /* Link the new request after the last written request. */
-    iter = conn->requests;
-    prev = NULL;
-
-    /* Find a request that has data which needs to be delivered. */
-    while (iter != NULL && iter->req_bkt == NULL && iter->writing_started) {
-        prev = iter;
-        iter = iter->next;
-    }
-
-    /* A CONNECT request to setup an ssltunnel has absolute priority over all
-       other requests on the connection, so:
-       a. add it first to the queue 
-       b. ensure that other priority requests are added after the CONNECT
-          request */
-    if (!request->ssltunnel) {
-        /* Advance to next non priority request */
-        while (iter != NULL && iter->priority) {
-            prev = iter;
-            iter = iter->next;
-        }
-    }
-
-    if (prev) {
-        request->next = iter;
-        prev->next = request;
-    } else {
-        request->next = iter;
-        conn->requests = request;
-    }
-
-    /* Ensure our pollset becomes writable in context run */
-    conn->ctx->dirty_pollset = 1;
-    conn->dirty_conn = 1;
-
-    return request;
-}
-
-serf_request_t *serf_connection_priority_request_create(
-    serf_connection_t *conn,
-    serf_request_setup_t setup,
-    void *setup_baton)
-{
-    return priority_request_create(conn,
-                                   0, /* not a ssltunnel CONNECT request */
-                                   setup, setup_baton);
-}
-
-serf_request_t *serf__ssltunnel_request_create(serf_connection_t *conn,
-                                               serf_request_setup_t setup,
-                                               void *setup_baton)
-{
-    return priority_request_create(conn,
-                                   1, /* This is a ssltunnel CONNECT request */
-                                   setup, setup_baton);
-}
-
-apr_status_t serf_request_cancel(serf_request_t *request)
-{
-    return cancel_request(request, &request->conn->requests, 0);
-}
-
-apr_status_t serf_request_is_written(serf_request_t *request)
-{
-    if (request->writing_started && !request->req_bkt)
-        return APR_SUCCESS;
-
-    return APR_EBUSY;
-}
-
-apr_pool_t *serf_request_get_pool(const serf_request_t *request)
-{
-    return request->respool;
-}
-
-
-serf_bucket_alloc_t *serf_request_get_alloc(
-    const serf_request_t *request)
-{
-    return request->allocator;
-}
-
-
-serf_connection_t *serf_request_get_conn(
-    const serf_request_t *request)
-{
-    return request->conn;
-}
-
-
-void serf_request_set_handler(
-    serf_request_t *request,
-    const serf_response_handler_t handler,
-    const void **handler_baton)
-{
-    request->handler = handler;
-    request->handler_baton = handler_baton;
-}
-
-
-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;
-    serf_connection_t *conn = request->conn;
-    serf_context_t *ctx = conn->ctx;
-    int ssltunnel;
-
-    ssltunnel = ctx->proxy_address &&
-                (strcmp(conn->host_info.scheme, "https") == 0);
-
-    req_bkt = serf_bucket_request_create(method, uri, body, allocator);
-    hdrs_bkt = serf_bucket_request_get_headers(req_bkt);
-
-    /* Use absolute uri's in requests to a proxy. USe relative uri's in
-       requests directly to a server or sent through an SSL tunnel. */
-    if (ctx->proxy_address && conn->host_url &&
-        !(ssltunnel && !request->ssltunnel)) {
-
-        serf_bucket_request_set_root(req_bkt, conn->host_url);
-    }
-
-    if (conn->host_info.hostinfo)
-        serf_bucket_headers_setn(hdrs_bkt, "Host",
-                                 conn->host_info.hostinfo);
-
-    /* Setup server authorization headers, unless this is a CONNECT request. */
-    if (!request->ssltunnel) {
-        serf__authn_info_t *authn_info;
-        authn_info = serf__get_authn_info_for_server(conn);
-        if (authn_info->scheme)
-            authn_info->scheme->setup_request_func(HOST, 0, conn, request,
-                                                   method, uri,
-                                                   hdrs_bkt);
-    }
-
-    /* Setup proxy authorization headers.
-       Don't set these headers on the requests to the server if we're using
-       an SSL tunnel, only on the CONNECT request to setup the tunnel. */
-    if (ctx->proxy_authn_info.scheme) {
-        if (strcmp(conn->host_info.scheme, "https") == 0) {
-            if (request->ssltunnel)
-                ctx->proxy_authn_info.scheme->setup_request_func(PROXY, 0, conn,
-                                                                 request,
-                                                                 method, uri,
-                                                                 hdrs_bkt);
-        } else {
-            ctx->proxy_authn_info.scheme->setup_request_func(PROXY, 0, conn,
-                                                             request,
-                                                             method, uri,
-                                                             hdrs_bkt);
-        }
-    }
-
-    return req_bkt;
-}
-
-apr_interval_time_t serf_connection_get_latency(serf_connection_t *conn)
-{
-    if (conn->ctx->proxy_address) {
-        /* Detecting network latency for proxied connection is not implemented
-           yet. */
-        return -1;
-    }
-
-    return conn->latency;
-}

Copied: vendor/serf/1.3.9/outgoing.c (from rev 9259, vendor/serf/dist/outgoing.c)
===================================================================
--- vendor/serf/1.3.9/outgoing.c	                        (rev 0)
+++ vendor/serf/1.3.9/outgoing.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,1754 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_pools.h>
+#include <apr_poll.h>
+#include <apr_version.h>
+#include <apr_portable.h>
+
+#include "serf.h"
+#include "serf_bucket_util.h"
+
+#include "serf_private.h"
+
+/* cleanup for sockets */
+static apr_status_t clean_skt(void *data)
+{
+    serf_connection_t *conn = data;
+    apr_status_t status = APR_SUCCESS;
+
+    if (conn->skt) {
+        serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt, "cleanup - ");
+        status = apr_socket_close(conn->skt);
+        conn->skt = NULL;
+        serf__log_nopref(SOCK_VERBOSE, "closed socket, status %d\n", status);
+    }
+
+    return status;
+}
+
+static apr_status_t clean_resp(void *data)
+{
+    serf_request_t *request = data;
+
+    /* The request's RESPOOL is being cleared.  */
+
+    /* If the response has allocated some buckets, then destroy them (since
+       the bucket may hold resources other than memory in RESPOOL). Also
+       make sure to set their fields to NULL so connection closure does
+       not attempt to free them again.  */
+    if (request->resp_bkt) {
+        serf_bucket_destroy(request->resp_bkt);
+        request->resp_bkt = NULL;
+    }
+    if (request->req_bkt) {
+        serf_bucket_destroy(request->req_bkt);
+        request->req_bkt = NULL;
+    }
+
+    /* ### should we worry about debug stuff, like that performed in
+       ### destroy_request()? should we worry about calling req->handler
+       ### to notify this "cancellation" due to pool clearing?  */
+
+    /* This pool just got cleared/destroyed. Don't try to destroy the pool
+       (again) when the request is canceled.  */
+    request->respool = NULL;
+
+    return APR_SUCCESS;
+}
+
+/* cleanup for conns */
+static apr_status_t clean_conn(void *data)
+{
+    serf_connection_t *conn = data;
+
+    serf__log(CONN_VERBOSE, __FILE__, "cleaning up connection 0x%x\n",
+              conn);
+    serf_connection_close(conn);
+
+    return APR_SUCCESS;
+}
+
+/* Check if there is data waiting to be sent over the socket. This can happen
+   in two situations:
+   - The connection queue has atleast one request with unwritten data.
+   - All requests are written and the ssl layer wrote some data while reading
+     the response. This can happen when the server triggers a renegotiation,
+     e.g. after the first and only request on that connection was received.
+   Returns 1 if data is pending on CONN, NULL if not.
+   If NEXT_REQ is not NULL, it will be filled in with the next available request
+   with unwritten data. */
+static int
+request_or_data_pending(serf_request_t **next_req, serf_connection_t *conn)
+{
+    serf_request_t *request = conn->requests;
+
+    while (request != NULL && request->req_bkt == NULL &&
+           request->writing_started)
+        request = request->next;
+
+    if (next_req)
+        *next_req = request;
+
+    if (request != NULL) {
+        return 1;
+    } else if (conn->ostream_head) {
+        const char *dummy;
+        apr_size_t len;
+        apr_status_t status;
+
+        status = serf_bucket_peek(conn->ostream_head, &dummy,
+                                  &len);
+        if (!SERF_BUCKET_READ_ERROR(status) && len) {
+            serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt,
+                          "All requests written but still data pending.\n");
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+/* Update the pollset for this connection. We tweak the pollset based on
+ * whether we want to read and/or write, given conditions within the
+ * connection. If the connection is not (yet) in the pollset, then it
+ * will be added.
+ */
+apr_status_t serf__conn_update_pollset(serf_connection_t *conn)
+{
+    serf_context_t *ctx = conn->ctx;
+    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 = ctx->pollset_rm(ctx->pollset_baton,
+                             &desc, &conn->baton);
+    if (status && !APR_STATUS_IS_NOTFOUND(status))
+        return status;
+
+    /* Now put it back in with the correct read/write values. */
+    desc.reqevents = APR_POLLHUP | APR_POLLERR;
+    if (conn->requests &&
+        conn->state != SERF_CONN_INIT) {
+        /* If there are any outstanding events, then we want to read. */
+        /* ### not true. we only want to read IF we have sent some data */
+        desc.reqevents |= APR_POLLIN;
+
+        /* Don't write if OpenSSL told us that it needs to read data first. */
+        if (conn->stop_writing != 1) {
+
+            /* If the connection is not closing down and
+             *   has unwritten data or
+             *   there are any requests that still have buckets to write out,
+             *     then we want to write.
+             */
+            if (conn->vec_len &&
+                conn->state != SERF_CONN_CLOSING)
+                desc.reqevents |= APR_POLLOUT;
+            else {
+
+                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 if (request_or_data_pending(NULL, conn)) {
+                    desc.reqevents |= APR_POLLOUT;
+                }
+            }
+        }
+    }
+
+    /* If we can have async responses, always look for something to read. */
+    if (conn->async_responses) {
+        desc.reqevents |= APR_POLLIN;
+    }
+
+    /* 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 ctx->pollset_add(ctx->pollset_baton,
+                            &desc, &conn->baton);
+}
+
+#ifdef SERF_DEBUG_BUCKET_USE
+
+/* Make sure all response buckets were drained. */
+static void check_buckets_drained(serf_connection_t *conn)
+{
+    serf_request_t *request = conn->requests;
+
+    for ( ; request ; request = request->next ) {
+        if (request->resp_bkt != NULL) {
+            /* ### crap. can't do this. this allocator may have un-drained
+             * ### REQUEST buckets.
+             */
+            /* serf_debug__entered_loop(request->resp_bkt->allocator); */
+            /* ### for now, pretend we closed the conn (resets the tracking) */
+            serf_debug__closed_conn(request->resp_bkt->allocator);
+        }
+    }
+}
+
+#endif
+
+static void destroy_ostream(serf_connection_t *conn)
+{
+    if (conn->ostream_head != NULL) {
+        serf_bucket_destroy(conn->ostream_head);
+        conn->ostream_head = NULL;
+        conn->ostream_tail = NULL;
+    }
+}
+
+static apr_status_t detect_eof(void *baton, serf_bucket_t *aggregate_bucket)
+{
+    serf_connection_t *conn = baton;
+    conn->hit_eof = 1;
+    return APR_EAGAIN;
+}
+
+static apr_status_t do_conn_setup(serf_connection_t *conn)
+{
+    apr_status_t status;
+    serf_bucket_t *ostream;
+
+    if (conn->ostream_head == NULL) {
+        conn->ostream_head = serf_bucket_aggregate_create(conn->allocator);
+    }
+
+    if (conn->ostream_tail == NULL) {
+        conn->ostream_tail = serf__bucket_stream_create(conn->allocator,
+                                                        detect_eof,
+                                                        conn);
+    }
+
+    ostream = conn->ostream_tail;
+
+    status = (*conn->setup)(conn->skt,
+                            &conn->stream,
+                            &ostream,
+                            conn->setup_baton,
+                            conn->pool);
+    if (status) {
+        /* extra destroy here since it wasn't added to the head bucket yet. */
+        serf_bucket_destroy(conn->ostream_tail);
+        destroy_ostream(conn);
+        return status;
+    }
+
+    serf_bucket_aggregate_append(conn->ostream_head,
+                                 ostream);
+
+    return status;
+}
+
+/* Set up the input and output stream buckets.
+ When a tunnel over an http proxy is needed, create a socket bucket and
+ empty aggregate bucket for sending and receiving unencrypted requests
+ over the socket.
+
+ After the tunnel is there, or no tunnel was needed, ask the application
+ to create the input and output buckets, which should take care of the
+ [en/de]cryption.
+ */
+
+static apr_status_t prepare_conn_streams(serf_connection_t *conn,
+                                         serf_bucket_t **istream,
+                                         serf_bucket_t **ostreamt,
+                                         serf_bucket_t **ostreamh)
+{
+    apr_status_t status;
+
+    if (conn->stream == NULL) {
+        conn->latency = apr_time_now() - conn->connect_time;
+    }
+
+    /* Do we need a SSL tunnel first? */
+    if (conn->state == SERF_CONN_CONNECTED) {
+        /* If the connection does not have an associated bucket, then
+         * call the setup callback to get one.
+         */
+        if (conn->stream == NULL) {
+            status = do_conn_setup(conn);
+            if (status) {
+                return status;
+            }
+        }
+        *ostreamt = conn->ostream_tail;
+        *ostreamh = conn->ostream_head;
+        *istream = conn->stream;
+    } else {
+        /* SSL tunnel needed and not set up yet, get a direct unencrypted
+         stream for this socket */
+        if (conn->stream == NULL) {
+            *istream = serf_bucket_socket_create(conn->skt,
+                                                 conn->allocator);
+        }
+        /* Don't create the ostream bucket chain including the ssl_encrypt
+         bucket yet. This ensure the CONNECT request is sent unencrypted
+         to the proxy. */
+        *ostreamt = *ostreamh = conn->ssltunnel_ostream;
+    }
+
+    return APR_SUCCESS;
+}
+
+/* Create and connect sockets for any connections which don't have them
+ * yet. This is the core of our lazy-connect behavior.
+ */
+apr_status_t serf__open_connections(serf_context_t *ctx)
+{
+    int i;
+
+    for (i = ctx->conns->nelts; i--; ) {
+        serf_connection_t *conn = GET_CONN(ctx, i);
+        serf__authn_info_t *authn_info;
+        apr_status_t status;
+        apr_socket_t *skt;
+
+        conn->seen_in_pollset = 0;
+
+        if (conn->skt != NULL) {
+#ifdef SERF_DEBUG_BUCKET_USE
+            check_buckets_drained(conn);
+#endif
+            continue;
+        }
+
+        /* Delay opening until we have something to deliver! */
+        if (conn->requests == NULL) {
+            continue;
+        }
+
+        apr_pool_clear(conn->skt_pool);
+        apr_pool_cleanup_register(conn->skt_pool, conn, clean_skt, clean_skt);
+
+        status = apr_socket_create(&skt, conn->address->family,
+                                   SOCK_STREAM,
+#if APR_MAJOR_VERSION > 0
+                                   APR_PROTO_TCP,
+#endif
+                                   conn->skt_pool);
+        serf__log(SOCK_VERBOSE, __FILE__,
+                  "created socket for conn 0x%x, status %d\n", conn, status);
+        if (status != APR_SUCCESS)
+            return status;
+
+        /* Set the socket to be non-blocking */
+        if ((status = apr_socket_timeout_set(skt, 0)) != APR_SUCCESS)
+            return status;
+
+        /* Disable Nagle's algorithm */
+        if ((status = apr_socket_opt_set(skt,
+                                         APR_TCP_NODELAY, 1)) != APR_SUCCESS)
+            return status;
+
+        /* Configured. Store it into the connection now. */
+        conn->skt = skt;
+
+        /* Remember time when we started connecting to server to calculate
+           network latency. */
+        conn->connect_time = apr_time_now();
+
+        /* Now that the socket is set up, let's connect it. This should
+         * return immediately.
+         */
+        status = apr_socket_connect(skt, conn->address);
+        serf__log_skt(SOCK_VERBOSE, __FILE__, skt,
+                      "connected socket for conn 0x%x, status %d\n",
+                      conn, status);
+        if (status != APR_SUCCESS) {
+            if (!APR_STATUS_IS_EINPROGRESS(status))
+                return status;
+        }
+
+        /* Flag our pollset as dirty now that we have a new socket. */
+        conn->dirty_conn = 1;
+        ctx->dirty_pollset = 1;
+
+        /* If the authentication was already started on another connection,
+           prepare this connection (it might be possible to skip some
+           part of the handshaking). */
+        if (ctx->proxy_address) {
+            authn_info = &ctx->proxy_authn_info;
+            if (authn_info->scheme) {
+                authn_info->scheme->init_conn_func(authn_info->scheme, 407,
+                                                   conn, conn->pool);
+            }
+        }
+
+        authn_info = serf__get_authn_info_for_server(conn);
+        if (authn_info->scheme) {
+            authn_info->scheme->init_conn_func(authn_info->scheme, 401,
+                                               conn, conn->pool);
+        }
+
+        /* Does this connection require a SSL tunnel over the proxy? */
+        if (ctx->proxy_address && strcmp(conn->host_info.scheme, "https") == 0)
+            serf__ssltunnel_connect(conn);
+        else {
+            serf_bucket_t *dummy1, *dummy2;
+
+            conn->state = SERF_CONN_CONNECTED;
+
+            status = prepare_conn_streams(conn, &conn->stream,
+                                          &dummy1, &dummy2);
+            if (status) {
+                return status;
+            }
+        }
+    }
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t no_more_writes(serf_connection_t *conn)
+{
+    /* Note that we should hold new requests until we open our new socket. */
+    conn->state = SERF_CONN_CLOSING;
+    serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt,
+                  "stop writing on conn 0x%x\n", conn);
+
+    /* Clear our iovec. */
+    conn->vec_len = 0;
+
+    /* Update the pollset to know we don't want to write on this socket any
+     * more.
+     */
+    conn->dirty_conn = 1;
+    conn->ctx->dirty_pollset = 1;
+    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)
+{
+    if (*list == NULL) {
+        *list = request;
+        *tail = request;
+    }
+    else {
+        (*tail)->next = request;
+        *tail = request;
+    }
+}
+
+static apr_status_t destroy_request(serf_request_t *request)
+{
+    serf_connection_t *conn = request->conn;
+
+    /* The request and response buckets are no longer needed,
+       nor is the request's pool.  */
+    if (request->resp_bkt) {
+        serf_debug__closed_conn(request->resp_bkt->allocator);
+        serf_bucket_destroy(request->resp_bkt);
+        request->resp_bkt = NULL;
+    }
+    if (request->req_bkt) {
+        serf_debug__closed_conn(request->req_bkt->allocator);
+        serf_bucket_destroy(request->req_bkt);
+        request->req_bkt = NULL;
+    }
+
+    serf_debug__bucket_alloc_check(request->allocator);
+    if (request->respool) {
+        /* ### unregister the pool cleanup for self?  */
+        apr_pool_destroy(request->respool);
+    }
+
+    serf_bucket_mem_free(conn->allocator, request);
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t cancel_request(serf_request_t *request,
+                                   serf_request_t **list,
+                                   int notify_request)
+{
+    /* If we haven't run setup, then we won't have a handler to call. */
+    if (request->handler && notify_request) {
+        /* We actually don't care what the handler returns.
+         * We have bigger matters at hand.
+         */
+        (*request->handler)(request, NULL, request->handler_baton,
+                            request->respool);
+    }
+
+    if (*list == request) {
+        *list = request->next;
+    }
+    else {
+        serf_request_t *scan = *list;
+
+        while (scan->next && scan->next != request)
+            scan = scan->next;
+
+        if (scan->next) {
+            scan->next = scan->next->next;
+        }
+    }
+
+    return destroy_request(request);
+}
+
+static apr_status_t remove_connection(serf_context_t *ctx,
+                                      serf_connection_t *conn)
+{
+    apr_pollfd_t desc = { 0 };
+
+    desc.desc_type = APR_POLL_SOCKET;
+    desc.desc.s = conn->skt;
+    desc.reqevents = conn->reqevents;
+
+    return ctx->pollset_rm(ctx->pollset_baton,
+                           &desc, &conn->baton);
+}
+
+/* A socket was closed, inform the application. */
+static void handle_conn_closed(serf_connection_t *conn, apr_status_t status)
+{
+    (*conn->closed)(conn, conn->closed_baton, status,
+                    conn->pool);
+}
+
+static apr_status_t reset_connection(serf_connection_t *conn,
+                                     int requeue_requests)
+{
+    serf_context_t *ctx = conn->ctx;
+    apr_status_t status;
+    serf_request_t *old_reqs;
+
+    conn->probable_keepalive_limit = conn->completed_responses;
+    conn->completed_requests = 0;
+    conn->completed_responses = 0;
+
+    old_reqs = conn->requests;
+
+    conn->requests = NULL;
+    conn->requests_tail = NULL;
+
+    /* Handle all outstanding requests. These have either not been written yet,
+       or have been written but the expected reply wasn't received yet. */
+    while (old_reqs) {
+        /* If we haven't started to write the connection, bring it over
+         * unchanged to our new socket.
+         * Do not copy a CONNECT request to the new connection, the ssl tunnel
+         * setup code will create a new CONNECT request already.
+         */
+        if (requeue_requests && !old_reqs->writing_started &&
+            !old_reqs->ssltunnel) {
+
+            serf_request_t *req = old_reqs;
+            old_reqs = old_reqs->next;
+            req->next = NULL;
+            link_requests(&conn->requests, &conn->requests_tail, req);
+        }
+        else {
+            /* Request has been consumed, or we don't want to requeue the
+               request. Either way, inform the application that the request
+               is cancelled. */
+            cancel_request(old_reqs, &old_reqs, requeue_requests);
+        }
+    }
+
+    /* Requests queue has been prepared for a new socket, close the old one. */
+    if (conn->skt != NULL) {
+        remove_connection(ctx, conn);
+        status = apr_socket_close(conn->skt);
+        serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt,
+                      "closed socket, status %d\n", status);
+        if (conn->closed != NULL) {
+            handle_conn_closed(conn, status);
+        }
+        conn->skt = NULL;
+    }
+
+    if (conn->stream != NULL) {
+        serf_bucket_destroy(conn->stream);
+        conn->stream = NULL;
+    }
+
+    destroy_ostream(conn);
+
+    /* Don't try to resume any writes */
+    conn->vec_len = 0;
+
+    conn->dirty_conn = 1;
+    conn->ctx->dirty_pollset = 1;
+    conn->state = SERF_CONN_INIT;
+
+    conn->hit_eof = 0;
+    conn->connect_time = 0;
+    conn->latency = -1;
+    conn->stop_writing = 0;
+
+    serf__log(CONN_VERBOSE, __FILE__, "reset connection 0x%x\n", conn);
+
+    conn->status = APR_SUCCESS;
+
+    /* Let our context know that we've 'reset' the socket already. */
+    conn->seen_in_pollset |= APR_POLLHUP;
+
+    /* Found the connection. Closed it. All done. */
+    return APR_SUCCESS;
+}
+
+static apr_status_t socket_writev(serf_connection_t *conn)
+{
+    apr_size_t written;
+    apr_status_t status;
+
+    status = apr_socket_sendv(conn->skt, conn->vec,
+                              conn->vec_len, &written);
+    if (status && !APR_STATUS_IS_EAGAIN(status))
+        serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt,
+                      "socket_sendv error %d\n", status);
+
+    /* did we write everything? */
+    if (written) {
+        apr_size_t len = 0;
+        int i;
+
+        serf__log_skt(SOCK_MSG_VERBOSE, __FILE__, conn->skt,
+                      "--- socket_sendv:\n");
+
+        for (i = 0; i < conn->vec_len; i++) {
+            len += conn->vec[i].iov_len;
+            if (written < len) {
+                serf__log_nopref(SOCK_MSG_VERBOSE, "%.*s",
+                                   conn->vec[i].iov_len - (len - written),
+                                   conn->vec[i].iov_base);
+                if (i) {
+                    memmove(conn->vec, &conn->vec[i],
+                            sizeof(struct iovec) * (conn->vec_len - i));
+                    conn->vec_len -= i;
+                }
+                conn->vec[0].iov_base = (char *)conn->vec[0].iov_base + (conn->vec[0].iov_len - (len - written));
+                conn->vec[0].iov_len = len - written;
+                break;
+            } else {
+                serf__log_nopref(SOCK_MSG_VERBOSE, "%.*s",
+                                   conn->vec[i].iov_len, conn->vec[i].iov_base);
+            }
+        }
+        if (len == written) {
+            conn->vec_len = 0;
+        }
+        serf__log_nopref(SOCK_MSG_VERBOSE, "-(%d)-\n", written);
+
+        /* Log progress information */
+        serf__context_progress_delta(conn->ctx, 0, written);
+    }
+
+    return status;
+}
+
+static apr_status_t setup_request(serf_request_t *request)
+{
+    serf_connection_t *conn = request->conn;
+    apr_status_t status;
+
+    /* Now that we are about to serve the request, allocate a pool. */
+    apr_pool_create(&request->respool, conn->pool);
+    request->allocator = serf_bucket_allocator_create(request->respool,
+                                                      NULL, NULL);
+    apr_pool_cleanup_register(request->respool, request,
+                              clean_resp, clean_resp);
+
+    /* Fill in the rest of the values for the request. */
+    status = request->setup(request, request->setup_baton,
+                            &request->req_bkt,
+                            &request->acceptor,
+                            &request->acceptor_baton,
+                            &request->handler,
+                            &request->handler_baton,
+                            request->respool);
+    return status;
+}
+
+/* write data out to the connection */
+static apr_status_t write_to_connection(serf_connection_t *conn)
+{
+    if (conn->probable_keepalive_limit &&
+        conn->completed_requests > conn->probable_keepalive_limit) {
+
+        conn->dirty_conn = 1;
+        conn->ctx->dirty_pollset = 1;
+
+        /* backoff for now. */
+        return APR_SUCCESS;
+    }
+
+    /* Keep reading and sending until we run out of stuff to read, or
+     * writing would block.
+     */
+    while (1) {
+        serf_request_t *request;
+        int stop_reading = 0;
+        apr_status_t status;
+        apr_status_t read_status;
+        serf_bucket_t *ostreamt;
+        serf_bucket_t *ostreamh;
+        int max_outstanding_requests = conn->max_outstanding_requests;
+
+        /* If we're setting up an ssl tunnel, we can't send real requests
+           at yet, as they need to be encrypted and our encrypt buckets
+           aren't created yet as we still need to read the unencrypted
+           response of the CONNECT request. */
+        if (conn->state != SERF_CONN_CONNECTED)
+            max_outstanding_requests = 1;
+
+        if (max_outstanding_requests &&
+            conn->completed_requests -
+                conn->completed_responses >= 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);
+
+            /* If the write would have blocked, then we're done. Don't try
+             * to write anything else to the socket.
+             */
+            if (APR_STATUS_IS_EAGAIN(status))
+                return APR_SUCCESS;
+            if (APR_STATUS_IS_EPIPE(status) ||
+                APR_STATUS_IS_ECONNRESET(status) ||
+                APR_STATUS_IS_ECONNABORTED(status))
+                return no_more_writes(conn);
+            if (status)
+                return status;
+        }
+        /* ### can we have a short write, yet no EAGAIN? a short write
+           ### would imply unwritten_len > 0 ... */
+        /* assert: unwritten_len == 0. */
+
+        /* We may need to move forward to a request which has something
+         * to write.
+         */
+        if (!request_or_data_pending(&request, conn)) {
+            /* No more requests (with data) are registered with the
+             * connection, and no data is pending on the outgoing stream.
+             * Let's update the pollset so that we don't try to write to this
+             * socket again.
+             */
+            conn->dirty_conn = 1;
+            conn->ctx->dirty_pollset = 1;
+            return APR_SUCCESS;
+        }
+
+        status = prepare_conn_streams(conn, &conn->stream, &ostreamt, &ostreamh);
+        if (status) {
+            return status;
+        }
+
+        if (request) {
+            if (request->req_bkt == NULL) {
+                read_status = setup_request(request);
+                if (read_status) {
+                    /* Something bad happened. Propagate any errors. */
+                    return read_status;
+                }
+            }
+
+            if (!request->writing_started) {
+                request->writing_started = 1;
+                serf_bucket_aggregate_append(ostreamt, request->req_bkt);
+            }
+        }
+
+        /* ### optimize at some point by using read_for_sendfile */
+        /* TODO: now that read_iovec will effectively try to return as much
+           data as available, we probably don't want to read ALL_AVAIL, but
+           a lower number, like the size of one or a few TCP packets, the
+           available TCP buffer size ... */
+        read_status = serf_bucket_read_iovec(ostreamh,
+                                             SERF_READ_ALL_AVAIL,
+                                             IOV_MAX,
+                                             conn->vec,
+                                             &conn->vec_len);
+
+        if (!conn->hit_eof) {
+            if (APR_STATUS_IS_EAGAIN(read_status)) {
+                /* We read some stuff, but should not try to read again. */
+                stop_reading = 1;
+            }
+            else if (read_status == SERF_ERROR_WAIT_CONN) {
+                /* The bucket told us that it can't provide more data until
+                   more data is read from the socket. This normally happens
+                   during a SSL handshake.
+
+                   We should avoid looking for writability for a while so
+                   that (hopefully) something will appear in the bucket so
+                   we can actually write something. otherwise, we could
+                   end up in a CPU spin: socket wants something, but we
+                   don't have anything (and keep returning EAGAIN)
+                 */
+                conn->stop_writing = 1;
+                conn->dirty_conn = 1;
+                conn->ctx->dirty_pollset = 1;
+            }
+            else if (read_status && !APR_STATUS_IS_EOF(read_status)) {
+                /* Something bad happened. Propagate any errors. */
+                return read_status;
+            }
+        }
+
+        /* If we got some data, then deliver it. */
+        /* ### what to do if we got no data?? is that a problem? */
+        if (conn->vec_len > 0) {
+            status = socket_writev(conn);
+
+            /* If we can't write any more, or an error occurred, then
+             * we're done here.
+             */
+            if (APR_STATUS_IS_EAGAIN(status))
+                return APR_SUCCESS;
+            if (APR_STATUS_IS_EPIPE(status))
+                return no_more_writes(conn);
+            if (APR_STATUS_IS_ECONNRESET(status) ||
+                APR_STATUS_IS_ECONNABORTED(status)) {
+                return no_more_writes(conn);
+            }
+            if (status)
+                return status;
+        }
+
+        if (read_status == SERF_ERROR_WAIT_CONN) {
+            stop_reading = 1;
+            conn->stop_writing = 1;
+            conn->dirty_conn = 1;
+            conn->ctx->dirty_pollset = 1;
+        }
+        else if (request && read_status && conn->hit_eof &&
+                 conn->vec_len == 0) {
+            /* If we hit the end of the request bucket and all of its data has
+             * been written, then clear it out to signify that we're done
+             * sending the request. On the next iteration through this loop:
+             * - if there are remaining bytes they will be written, and as the 
+             * request bucket will be completely read it will be destroyed then.
+             * - we'll see if there are other requests that need to be sent 
+             * ("pipelining").
+             */
+            conn->hit_eof = 0;
+            serf_bucket_destroy(request->req_bkt);
+            request->req_bkt = NULL;
+
+            /* If our connection has async responses enabled, we're not
+             * going to get a reply back, so kill the request.
+             */
+            if (conn->async_responses) {
+                conn->requests = request->next;
+                destroy_request(request);
+            }
+
+            conn->completed_requests++;
+
+            if (conn->probable_keepalive_limit &&
+                conn->completed_requests > conn->probable_keepalive_limit) {
+                /* backoff for now. */
+                stop_reading = 1;
+            }
+        }
+
+        if (stop_reading) {
+            return APR_SUCCESS;
+        }
+    }
+    /* NOTREACHED */
+}
+
+/* A response message was received from the server, so call
+   the handler as specified on the original request. */
+static apr_status_t handle_response(serf_request_t *request,
+                                    apr_pool_t *pool)
+{
+    apr_status_t status = APR_SUCCESS;
+    int consumed_response = 0;
+
+    /* Only enable the new authentication framework if the program has
+     * registered an authentication credential callback.
+     *
+     * This permits older Serf apps to still handle authentication
+     * themselves by not registering credential callbacks.
+     */
+    if (request->conn->ctx->cred_cb) {
+      status = serf__handle_auth_response(&consumed_response,
+                                          request,
+                                          request->resp_bkt,
+                                          request->handler_baton,
+                                          pool);
+
+      /* If there was an error reading the response (maybe there wasn't
+         enough data available), don't bother passing the response to the
+         application.
+
+         If the authentication was tried, but failed, pass the response
+         to the application, maybe it can do better. */
+      if (status) {
+          return status;
+      }
+    }
+
+    if (!consumed_response) {
+        return (*request->handler)(request,
+                                   request->resp_bkt,
+                                   request->handler_baton,
+                                   pool);
+    }
+
+    return status;
+}
+
+/* An async response message was received from the server. */
+static apr_status_t handle_async_response(serf_connection_t *conn,
+                                          apr_pool_t *pool)
+{
+    apr_status_t status;
+
+    if (conn->current_async_response == NULL) {
+        conn->current_async_response =
+            (*conn->async_acceptor)(NULL, conn->stream,
+                                    conn->async_acceptor_baton, pool);
+    }
+
+    status = (*conn->async_handler)(NULL, conn->current_async_response,
+                                    conn->async_handler_baton, pool);
+
+    if (APR_STATUS_IS_EOF(status)) {
+        serf_bucket_destroy(conn->current_async_response);
+        conn->current_async_response = NULL;
+        status = APR_SUCCESS;
+    }
+
+    return status;
+}
+
+
+apr_status_t
+serf__provide_credentials(serf_context_t *ctx,
+                          char **username,
+                          char **password,
+                          serf_request_t *request, void *baton,
+                          int code, const char *authn_type,
+                          const char *realm,
+                          apr_pool_t *pool)
+{
+    serf_connection_t *conn = request->conn;
+    serf_request_t *authn_req = request;
+    apr_status_t status;
+
+    if (request->ssltunnel == 1 &&
+        conn->state == SERF_CONN_SETUP_SSLTUNNEL) {
+        /* This is a CONNECT request to set up an SSL tunnel over a proxy.
+           This request is created by serf, so if the proxy requires
+           authentication, we can't ask the application for credentials with
+           this request.
+
+           Solution: setup the first request created by the application on
+           this connection, and use that request and its handler_baton to
+           call back to the application. */
+
+        authn_req = request->next;
+        /* assert: app_request != NULL */
+        if (!authn_req)
+            return APR_EGENERAL;
+
+        if (!authn_req->req_bkt) {
+            apr_status_t status;
+
+            status = setup_request(authn_req);
+            /* If we can't setup a request, don't bother setting up the
+               ssl tunnel. */
+            if (status)
+                return status;
+        }
+    }
+
+    /* Ask the application. */
+    status = (*ctx->cred_cb)(username, password,
+                             authn_req, authn_req->handler_baton,
+                             code, authn_type, realm, pool);
+    if (status)
+        return status;
+
+    return APR_SUCCESS;
+}
+
+/* read data from the connection */
+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.
+     */
+    serf_request_t *request = conn->requests;
+
+    /* If the stop_writing flag was set on the connection, reset it now because
+       there is some data to read. */
+    if (conn->stop_writing) {
+        conn->stop_writing = 0;
+        conn->dirty_conn = 1;
+        conn->ctx->dirty_pollset = 1;
+    }
+
+    /* assert: request != NULL */
+
+    if ((status = apr_pool_create(&tmppool, conn->pool)) != APR_SUCCESS)
+        goto error;
+
+    /* Invoke response handlers until we have no more work. */
+    while (1) {
+        serf_bucket_t *dummy1, *dummy2;
+
+        apr_pool_clear(tmppool);
+
+        /* Only interested in the input stream here. */
+        status = prepare_conn_streams(conn, &conn->stream, &dummy1, &dummy2);
+        if (status) {
+            goto error;
+        }
+
+        /* We have a different codepath when we can have async responses. */
+        if (conn->async_responses) {
+            /* TODO What about socket errors? */
+            status = handle_async_response(conn, tmppool);
+            if (APR_STATUS_IS_EAGAIN(status)) {
+                status = APR_SUCCESS;
+                goto error;
+            }
+            if (status) {
+                goto error;
+            }
+            continue;
+        }
+
+        /* We are reading a response for a request we haven't
+         * written yet!
+         *
+         * This shouldn't normally happen EXCEPT:
+         *
+         * 1) when the other end has closed the socket and we're
+         *    pending an EOF return.
+         * 2) Doing the initial SSL handshake - we'll get EAGAIN
+         *    as the SSL buckets will hide the handshake from us
+         *    but not return any data.
+         * 3) When the server sends us an SSL alert.
+         *
+         * In these cases, we should not receive any actual user data.
+         *
+         * 4) When the server sends a error response, like 408 Request timeout.
+         *    This response should be passed to the application.
+         *
+         * If we see an EOF (due to either an expired timeout or the server
+         * sending the SSL 'close notify' shutdown alert), we'll reset the
+         * connection and open a new one.
+         */
+        if (request->req_bkt || !request->writing_started) {
+            const char *data;
+            apr_size_t len;
+
+            status = serf_bucket_peek(conn->stream, &data, &len);
+
+            if (APR_STATUS_IS_EOF(status)) {
+                reset_connection(conn, 1);
+                status = APR_SUCCESS;
+                goto error;
+            }
+            else if (APR_STATUS_IS_EAGAIN(status) && !len) {
+                status = APR_SUCCESS;
+                goto error;
+            } else if (status && !APR_STATUS_IS_EAGAIN(status)) {
+                /* Read error */
+                goto error;
+            }
+
+            /* Unexpected response from the server */
+
+        }
+
+        /* If the request doesn't have a response bucket, then call the
+         * acceptor to get one created.
+         */
+        if (request->resp_bkt == NULL) {
+            request->resp_bkt = (*request->acceptor)(request, conn->stream,
+                                                     request->acceptor_baton,
+                                                     tmppool);
+            apr_pool_clear(tmppool);
+        }
+
+        status = handle_response(request, tmppool);
+
+        /* Some systems will not generate a HUP poll event so we have to
+         * handle the ECONNRESET issue and ECONNABORT here.
+         */
+        if (APR_STATUS_IS_ECONNRESET(status) ||
+            APR_STATUS_IS_ECONNABORTED(status) ||
+            status == SERF_ERROR_REQUEST_LOST) {
+            /* If the connection had ever been good, be optimistic & try again.
+             * If it has never tried again (incl. a retry), fail.
+             */
+            if (conn->completed_responses) {
+                reset_connection(conn, 1);
+                status = APR_SUCCESS;
+            }
+            else if (status == SERF_ERROR_REQUEST_LOST) {
+                status = SERF_ERROR_ABORTED_CONNECTION;
+            }
+            goto error;
+        }
+
+        /* If our response handler says it can't do anything more, we now
+         * treat that as a success.
+         */
+        if (APR_STATUS_IS_EAGAIN(status)) {
+            /* It is possible that while reading the response, the ssl layer
+               has prepared some data to send. If this was the last request,
+               serf will not check for socket writability, so force this here.
+             */
+            if (request_or_data_pending(&request, conn) && !request) {
+                conn->dirty_conn = 1;
+                conn->ctx->dirty_pollset = 1;
+            }
+            status = APR_SUCCESS;
+            goto error;
+        }
+
+        /* If we received APR_SUCCESS, run this loop again. */
+        if (!status) {
+            continue;
+        }
+
+        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.
+             */
+            goto error;
+        }
+
+        /* The response has been fully-read, so that means the request has
+         * either been fully-delivered (most likely), or that we don't need to
+         * write the rest of it anymore, e.g. when a 408 Request timeout was
+         $ received.
+         * Remove it from our queue and loop to read another response.
+         */
+        conn->requests = request->next;
+
+        destroy_request(request);
+
+        request = conn->requests;
+
+        /* If we're truly empty, update our tail. */
+        if (request == NULL) {
+            conn->requests_tail = NULL;
+        }
+
+        conn->completed_responses++;
+
+        /* We've to rebuild pollset since completed_responses is changed. */
+        conn->dirty_conn = 1;
+        conn->ctx->dirty_pollset = 1;
+
+        /* This means that we're being advised that the connection is done. */
+        if (close_connection == SERF_ERROR_CLOSING) {
+            reset_connection(conn, 1);
+            if (APR_STATUS_IS_EOF(status))
+                status = APR_SUCCESS;
+            goto error;
+        }
+
+        /* The server is suddenly deciding to serve more responses than we've
+         * seen before.
+         *
+         * Let our requests go.
+         */
+        if (conn->probable_keepalive_limit &&
+            conn->completed_responses > conn->probable_keepalive_limit) {
+            conn->probable_keepalive_limit = 0;
+        }
+
+        /* If we just ran out of requests or have unwritten requests, then
+         * update the pollset. We don't want to read from this socket any
+         * more. We are definitely done with this loop, too.
+         */
+        if (request == NULL || !request->writing_started) {
+            conn->dirty_conn = 1;
+            conn->ctx->dirty_pollset = 1;
+            status = APR_SUCCESS;
+            goto error;
+        }
+    }
+
+error:
+    apr_pool_destroy(tmppool);
+    return status;
+}
+
+/* process all events on the connection */
+apr_status_t serf__process_connection(serf_connection_t *conn,
+                                      apr_int16_t events)
+{
+    apr_status_t status;
+
+    /* POLLHUP/ERR should come after POLLIN so if there's an error message or
+     * the like sitting on the connection, we give the app a chance to read
+     * it before we trigger a reset condition.
+     */
+    if ((events & APR_POLLIN) != 0) {
+        if ((status = read_from_connection(conn)) != APR_SUCCESS)
+            return status;
+
+        /* If we decided to reset our connection, return now as we don't
+         * want to write.
+         */
+        if ((conn->seen_in_pollset & APR_POLLHUP) != 0) {
+            return APR_SUCCESS;
+        }
+    }
+    if ((events & APR_POLLHUP) != 0) {
+        /* The connection got reset by the server. On Windows this can happen
+           when all data is read, so just cleanup the connection and open
+           a new one.
+           If we haven't had any successful responses on this connection,
+           then error out as it is likely a server issue. */
+        if (conn->completed_responses) {
+            return reset_connection(conn, 1);
+        }
+        return SERF_ERROR_ABORTED_CONNECTION;
+    }
+    if ((events & APR_POLLERR) != 0) {
+        /* We might be talking to a buggy HTTP server that doesn't
+         * do lingering-close.  (httpd < 2.1.8 does this.)
+         *
+         * See:
+         *
+         * http://issues.apache.org/bugzilla/show_bug.cgi?id=35292
+         */
+        if (conn->completed_requests && !conn->probable_keepalive_limit) {
+            return reset_connection(conn, 1);
+        }
+#ifdef SO_ERROR
+        /* If possible, get the error from the platform's socket layer and
+           convert it to an APR status code. */
+        {
+            apr_os_sock_t osskt;
+            if (!apr_os_sock_get(&osskt, conn->skt)) {
+                int error;
+                apr_socklen_t l = sizeof(error);
+
+                if (!getsockopt(osskt, SOL_SOCKET, SO_ERROR, (char*)&error,
+                                &l)) {
+                    status = APR_FROM_OS_ERROR(error);
+
+                    /* Handle fallback for multi-homed servers.
+                     
+                       ### Improve algorithm to find better than just 'next'?
+
+                       Current Windows versions already handle re-ordering for
+                       api users by using statistics on the recently failed
+                       connections to order the list of addresses. */
+                    if (conn->completed_requests == 0
+                        && conn->address->next != NULL
+                        && (APR_STATUS_IS_ECONNREFUSED(status)
+                            || APR_STATUS_IS_TIMEUP(status)
+                            || APR_STATUS_IS_ENETUNREACH(status))) {
+
+                        conn->address = conn->address->next;
+                        return reset_connection(conn, 1);
+                    }
+
+                    return status;
+                  }
+            }
+        }
+#endif
+        return APR_EGENERAL;
+    }
+    if ((events & APR_POLLOUT) != 0) {
+        if ((status = write_to_connection(conn)) != APR_SUCCESS)
+            return status;
+    }
+    return APR_SUCCESS;
+}
+
+serf_connection_t *serf_connection_create(
+    serf_context_t *ctx,
+    apr_sockaddr_t *address,
+    serf_connection_setup_t setup,
+    void *setup_baton,
+    serf_connection_closed_t closed,
+    void *closed_baton,
+    apr_pool_t *pool)
+{
+    serf_connection_t *conn = apr_pcalloc(pool, sizeof(*conn));
+
+    conn->ctx = ctx;
+    conn->status = APR_SUCCESS;
+    /* Ignore server address if proxy was specified. */
+    conn->address = ctx->proxy_address ? ctx->proxy_address : address;
+    conn->setup = setup;
+    conn->setup_baton = setup_baton;
+    conn->closed = closed;
+    conn->closed_baton = closed_baton;
+    conn->pool = pool;
+    conn->allocator = serf_bucket_allocator_create(pool, NULL, NULL);
+    conn->stream = NULL;
+    conn->ostream_head = NULL;
+    conn->ostream_tail = NULL;
+    conn->baton.type = SERF_IO_CONN;
+    conn->baton.u.conn = conn;
+    conn->hit_eof = 0;
+    conn->state = SERF_CONN_INIT;
+    conn->latency = -1; /* unknown */
+
+    /* Create a subpool for our connection. */
+    apr_pool_create(&conn->skt_pool, conn->pool);
+
+    /* register a cleanup */
+    apr_pool_cleanup_register(conn->pool, conn, clean_conn,
+                              apr_pool_cleanup_null);
+
+    /* Add the connection to the context. */
+    *(serf_connection_t **)apr_array_push(ctx->conns) = conn;
+
+    serf__log(CONN_VERBOSE, __FILE__, "created connection 0x%x\n",
+              conn);
+
+    return conn;
+}
+
+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 = APR_SUCCESS;
+    serf_connection_t *c;
+    apr_sockaddr_t *host_address = NULL;
+
+    /* Set the port number explicitly, needed to create the socket later. */
+    if (!host_info.port) {
+        host_info.port = apr_uri_port_of_scheme(host_info.scheme);
+    }
+
+    /* Only lookup the address of the server if no proxy server was
+       configured. */
+    if (!ctx->proxy_address) {
+        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 |
+                                  APR_URI_UNP_OMITUSERINFO);
+
+    /* Store the host info without the path on the connection. */
+    (void)apr_uri_parse(c->pool, c->host_url, &(c->host_info));
+    if (!c->host_info.port) {
+        c->host_info.port = apr_uri_port_of_scheme(c->host_info.scheme);
+    }
+
+    *conn = c;
+
+    return status;
+}
+
+apr_status_t serf_connection_reset(
+    serf_connection_t *conn)
+{
+    return reset_connection(conn, 0);
+}
+
+
+apr_status_t serf_connection_close(
+    serf_connection_t *conn)
+{
+    int i;
+    serf_context_t *ctx = conn->ctx;
+    apr_status_t status;
+
+    for (i = ctx->conns->nelts; i--; ) {
+        serf_connection_t *conn_seq = GET_CONN(ctx, i);
+
+        if (conn_seq == conn) {
+            while (conn->requests) {
+                serf_request_cancel(conn->requests);
+            }
+            if (conn->skt != NULL) {
+                remove_connection(ctx, conn);
+                status = apr_socket_close(conn->skt);
+                serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt,
+                              "closed socket, status %d\n",
+                              status);
+                if (conn->closed != NULL) {
+                    handle_conn_closed(conn, status);
+                }
+                conn->skt = NULL;
+            }
+            if (conn->stream != NULL) {
+                serf_bucket_destroy(conn->stream);
+                conn->stream = NULL;
+            }
+
+            destroy_ostream(conn);
+
+            /* Remove the connection from the context. We don't want to
+             * deal with it any more.
+             */
+            if (i < ctx->conns->nelts - 1) {
+                /* move later connections over this one. */
+                memmove(
+                    &GET_CONN(ctx, i),
+                    &GET_CONN(ctx, i + 1),
+                    (ctx->conns->nelts - i - 1) * sizeof(serf_connection_t *));
+            }
+            --ctx->conns->nelts;
+
+            serf__log(CONN_VERBOSE, __FILE__, "closed connection 0x%x\n",
+                      conn);
+
+            /* Found the connection. Closed it. All done. */
+            return APR_SUCCESS;
+        }
+    }
+
+    /* We didn't find the specified connection. */
+    /* ### doc talks about this w.r.t poll structures. use something else? */
+    return APR_NOTFOUND;
+}
+
+
+void serf_connection_set_max_outstanding_requests(
+    serf_connection_t *conn,
+    unsigned int max_requests)
+{
+    if (max_requests == 0)
+        serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt,
+                      "Set max. nr. of outstanding requests for this "
+                      "connection to unlimited.\n");
+    else
+        serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt,
+                      "Limit max. nr. of outstanding requests for this "
+                      "connection to %u.\n", max_requests);
+
+    conn->max_outstanding_requests = max_requests;
+}
+
+
+void serf_connection_set_async_responses(
+    serf_connection_t *conn,
+    serf_response_acceptor_t acceptor,
+    void *acceptor_baton,
+    serf_response_handler_t handler,
+    void *handler_baton)
+{
+    conn->async_responses = 1;
+    conn->async_acceptor = acceptor;
+    conn->async_acceptor_baton = acceptor_baton;
+    conn->async_handler = handler;
+    conn->async_handler_baton = handler_baton;
+}
+
+static serf_request_t *
+create_request(serf_connection_t *conn,
+               serf_request_setup_t setup,
+               void *setup_baton,
+               int priority,
+               int ssltunnel)
+{
+    serf_request_t *request;
+
+    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->priority = priority;
+    request->writing_started = 0;
+    request->ssltunnel = ssltunnel;
+    request->next = NULL;
+    request->auth_baton = NULL;
+
+    return request;
+}
+
+serf_request_t *serf_connection_request_create(
+    serf_connection_t *conn,
+    serf_request_setup_t setup,
+    void *setup_baton)
+{
+    serf_request_t *request;
+
+    request = create_request(conn, setup, setup_baton,
+                             0, /* priority */
+                             0  /* ssl tunnel */);
+
+    /* Link the request to the end of the request chain. */
+    link_requests(&conn->requests, &conn->requests_tail, request);
+    
+    /* Ensure our pollset becomes writable in context run */
+    conn->ctx->dirty_pollset = 1;
+    conn->dirty_conn = 1;
+
+    return request;
+}
+
+static serf_request_t *
+priority_request_create(serf_connection_t *conn,
+                        int ssltunnelreq,
+                        serf_request_setup_t setup,
+                        void *setup_baton)
+{
+    serf_request_t *request;
+    serf_request_t *iter, *prev;
+
+    request = create_request(conn, setup, setup_baton,
+                             1, /* priority */
+                             ssltunnelreq);
+
+    /* Link the new request after the last written request. */
+    iter = conn->requests;
+    prev = NULL;
+
+    /* Find a request that has data which needs to be delivered. */
+    while (iter != NULL && iter->req_bkt == NULL && iter->writing_started) {
+        prev = iter;
+        iter = iter->next;
+    }
+
+    /* A CONNECT request to setup an ssltunnel has absolute priority over all
+       other requests on the connection, so:
+       a. add it first to the queue 
+       b. ensure that other priority requests are added after the CONNECT
+          request */
+    if (!request->ssltunnel) {
+        /* Advance to next non priority request */
+        while (iter != NULL && iter->priority) {
+            prev = iter;
+            iter = iter->next;
+        }
+    }
+
+    if (prev) {
+        request->next = iter;
+        prev->next = request;
+    } else {
+        request->next = iter;
+        conn->requests = request;
+    }
+
+    /* Ensure our pollset becomes writable in context run */
+    conn->ctx->dirty_pollset = 1;
+    conn->dirty_conn = 1;
+
+    return request;
+}
+
+serf_request_t *serf_connection_priority_request_create(
+    serf_connection_t *conn,
+    serf_request_setup_t setup,
+    void *setup_baton)
+{
+    return priority_request_create(conn,
+                                   0, /* not a ssltunnel CONNECT request */
+                                   setup, setup_baton);
+}
+
+serf_request_t *serf__ssltunnel_request_create(serf_connection_t *conn,
+                                               serf_request_setup_t setup,
+                                               void *setup_baton)
+{
+    return priority_request_create(conn,
+                                   1, /* This is a ssltunnel CONNECT request */
+                                   setup, setup_baton);
+}
+
+apr_status_t serf_request_cancel(serf_request_t *request)
+{
+    return cancel_request(request, &request->conn->requests, 0);
+}
+
+apr_status_t serf_request_is_written(serf_request_t *request)
+{
+    if (request->writing_started && !request->req_bkt)
+        return APR_SUCCESS;
+
+    return APR_EBUSY;
+}
+
+apr_pool_t *serf_request_get_pool(const serf_request_t *request)
+{
+    return request->respool;
+}
+
+
+serf_bucket_alloc_t *serf_request_get_alloc(
+    const serf_request_t *request)
+{
+    return request->allocator;
+}
+
+
+serf_connection_t *serf_request_get_conn(
+    const serf_request_t *request)
+{
+    return request->conn;
+}
+
+
+void serf_request_set_handler(
+    serf_request_t *request,
+    const serf_response_handler_t handler,
+    const void **handler_baton)
+{
+    request->handler = handler;
+    request->handler_baton = handler_baton;
+}
+
+
+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;
+    serf_connection_t *conn = request->conn;
+    serf_context_t *ctx = conn->ctx;
+    int ssltunnel;
+
+    ssltunnel = ctx->proxy_address &&
+                (strcmp(conn->host_info.scheme, "https") == 0);
+
+    req_bkt = serf_bucket_request_create(method, uri, body, allocator);
+    hdrs_bkt = serf_bucket_request_get_headers(req_bkt);
+
+    /* Use absolute uri's in requests to a proxy. USe relative uri's in
+       requests directly to a server or sent through an SSL tunnel. */
+    if (ctx->proxy_address && conn->host_url &&
+        !(ssltunnel && !request->ssltunnel)) {
+
+        serf_bucket_request_set_root(req_bkt, conn->host_url);
+    }
+
+    if (conn->host_info.hostinfo)
+        serf_bucket_headers_setn(hdrs_bkt, "Host",
+                                 conn->host_info.hostinfo);
+
+    /* Setup server authorization headers, unless this is a CONNECT request. */
+    if (!request->ssltunnel) {
+        serf__authn_info_t *authn_info;
+        authn_info = serf__get_authn_info_for_server(conn);
+        if (authn_info->scheme)
+            authn_info->scheme->setup_request_func(HOST, 0, conn, request,
+                                                   method, uri,
+                                                   hdrs_bkt);
+    }
+
+    /* Setup proxy authorization headers.
+       Don't set these headers on the requests to the server if we're using
+       an SSL tunnel, only on the CONNECT request to setup the tunnel. */
+    if (ctx->proxy_authn_info.scheme) {
+        if (strcmp(conn->host_info.scheme, "https") == 0) {
+            if (request->ssltunnel)
+                ctx->proxy_authn_info.scheme->setup_request_func(PROXY, 0, conn,
+                                                                 request,
+                                                                 method, uri,
+                                                                 hdrs_bkt);
+        } else {
+            ctx->proxy_authn_info.scheme->setup_request_func(PROXY, 0, conn,
+                                                             request,
+                                                             method, uri,
+                                                             hdrs_bkt);
+        }
+    }
+
+    return req_bkt;
+}
+
+apr_interval_time_t serf_connection_get_latency(serf_connection_t *conn)
+{
+    if (conn->ctx->proxy_address) {
+        /* Detecting network latency for proxied connection is not implemented
+           yet. */
+        return -1;
+    }
+
+    return conn->latency;
+}

Deleted: vendor/serf/1.3.9/serf.h
===================================================================
--- vendor/serf/dist/serf.h	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/serf.h	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,1117 +0,0 @@
-/* Copyright 2002-2004 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 SERF_H
-#define SERF_H
-
-/**
- * @file serf.h
- * @brief Main serf header file
- */
-
-#include <apr.h>
-#include <apr_errno.h>
-#include <apr_allocator.h>
-#include <apr_pools.h>
-#include <apr_network_io.h>
-#include <apr_time.h>
-#include <apr_poll.h>
-#include <apr_uri.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Forward declare some structures */
-typedef struct serf_context_t serf_context_t;
-
-typedef struct serf_bucket_t serf_bucket_t;
-typedef struct serf_bucket_type_t serf_bucket_type_t;
-typedef struct serf_bucket_alloc_t serf_bucket_alloc_t;
-
-typedef struct serf_connection_t serf_connection_t;
-typedef struct serf_listener_t serf_listener_t;
-typedef struct serf_incoming_t serf_incoming_t;
-typedef struct serf_incoming_request_t serf_incoming_request_t;
-
-typedef struct serf_request_t serf_request_t;
-
-
-/**
- * @defgroup serf high-level constructs
- * @ingroup serf
- * @{
- */
-
-/**
- * Serf-specific error codes
- */
-#define SERF_ERROR_RANGE 100
-#define SERF_ERROR_START (APR_OS_START_USERERR + SERF_ERROR_RANGE)
-
-/* This code is for when this is the last response on this connection:
- * i.e. do not send any more requests on this connection or expect
- * any more responses.
- */
-#define SERF_ERROR_CLOSING (SERF_ERROR_START + 1)
-/* This code is for when the connection terminated before the request
- * could be processed on the other side.
- */
-#define SERF_ERROR_REQUEST_LOST (SERF_ERROR_START + 2)
-/* This code is for when the connection is blocked - we can not proceed
- * until something happens - generally due to SSL negotiation-like behavior
- * where a write() is blocked until a read() is processed.
- */
-#define SERF_ERROR_WAIT_CONN (SERF_ERROR_START + 3)
-/* This code is for when something went wrong during deflating compressed
- * data e.g. a CRC error. */
-#define SERF_ERROR_DECOMPRESSION_FAILED (SERF_ERROR_START + 4)
-/* This code is for when a response received from a http server is not in
- * http-compliant syntax. */
-#define SERF_ERROR_BAD_HTTP_RESPONSE (SERF_ERROR_START + 5)
-/* The server sent less data than what was announced. */
-#define SERF_ERROR_TRUNCATED_HTTP_RESPONSE (SERF_ERROR_START + 6)
-/* The proxy server returned an error while setting up the SSL tunnel. */
-#define SERF_ERROR_SSLTUNNEL_SETUP_FAILED (SERF_ERROR_START + 7)
-/* The server unexpectedly closed the connection prematurely. */
-#define SERF_ERROR_ABORTED_CONNECTION (SERF_ERROR_START + 8)
-
-/* SSL certificates related errors */
-#define SERF_ERROR_SSL_CERT_FAILED (SERF_ERROR_START + 70)
-
-/* SSL communications related errors */
-#define SERF_ERROR_SSL_COMM_FAILED (SERF_ERROR_START + 71)
-
-/* General authentication related errors */
-#define SERF_ERROR_AUTHN_FAILED (SERF_ERROR_START + 90)
-
-/* None of the available authn mechanisms for the request are supported */
-#define SERF_ERROR_AUTHN_NOT_SUPPORTED (SERF_ERROR_START + 91)
-
-/* Authn was requested by the server but the header lacked some attribute  */
-#define SERF_ERROR_AUTHN_MISSING_ATTRIBUTE (SERF_ERROR_START + 92)
-
-/* Authentication handler initialization related errors */
-#define SERF_ERROR_AUTHN_INITALIZATION_FAILED (SERF_ERROR_START + 93)
-
-/* Error code reserved for use in the test suite. */
-#define SERF_ERROR_ISSUE_IN_TESTSUITE (SERF_ERROR_START + 99)
-
-/* This macro groups errors potentially raised when reading a http response.  */
-#define SERF_BAD_RESPONSE_ERROR(status) ((status) \
-    && ((SERF_ERROR_DECOMPRESSION_FAILED == (status)) \
-        ||(SERF_ERROR_BAD_HTTP_RESPONSE == (status)) \
-        ||(SERF_ERROR_TRUNCATED_HTTP_RESPONSE == (status))))
-
-/**
- * Return a string that describes the specified error code.
- *
- * If the error code is not one of the above Serf error codes, then
- * NULL will be returned.
- *
- * Note regarding lifetime: the string is a statically-allocated constant
- */
-const char *serf_error_string(apr_status_t errcode);
-
-
-/**
- * Create a new context for serf operations.
- *
- * A serf context defines a control loop which processes multiple
- * connections simultaneously.
- *
- * The context will be allocated within @a pool.
- */
-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_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.
- */
-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". */
-#define SERF_DURATION_FOREVER 2000000000        /* approx 1^31 */
-
-/**
- * Run the main networking control loop.
- *
- * The set of connections defined by the serf context @a ctx are processed.
- * Any outbound data is delivered, and incoming data is made available to
- * the associated response handlers and their buckets. This function will
- * block on the network for no longer than @a duration microseconds.
- *
- * If any data is processed (incoming or outgoing), then this function will
- * return with APR_SUCCESS. Typically, the caller will just want to call it
- * again to continue processing data.
- *
- * If no activity occurs within the specified timeout duration, then
- * APR_TIMEUP is returned.
- *
- * All temporary allocations will be made in @a pool.
- */
-apr_status_t serf_context_run(
-    serf_context_t *ctx,
-    apr_short_interval_time_t duration,
-    apr_pool_t *pool);
-
-
-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.
- */
-void serf_context_set_progress_cb(
-    serf_context_t *ctx,
-    const serf_progress_t progress_func,
-    void *progress_baton);
-
-/** @} */
-
-/**
- * @defgroup serf connections and requests
- * @ingroup serf
- * @{
- */
-
-/**
- * When a connection is established, the application needs to wrap some
- * buckets around @a skt to enable serf to process incoming responses. This
- * is the control point for assembling connection-level processing logic
- * around the given socket.
- *
- * The @a setup_baton is the baton established at connection creation time.
- *
- * This callback corresponds to reading from the server. Since this is an
- * on-demand activity, we use a callback. The corresponding write operation
- * is based on the @see serf_request_deliver function, where the application
- * can assemble the appropriate bucket(s) before delivery.
- *
- * The returned bucket should live at least as long as the connection itself.
- * It is assumed that an appropriate allocator is passed in @a setup_baton.
- * ### we may want to create a connection-level allocator and pass that
- * ### along. however, that allocator would *only* be used for this
- * ### callback. it may be wasteful to create a per-conn allocator, so this
- * ### baton-based, app-responsible form might be best.
- *
- * Responsibility for the buckets is passed to the serf library. They will be
- * destroyed when the connection is closed.
- *
- * All temporary allocations should be made in @a pool.
- */
-typedef apr_status_t (*serf_connection_setup_t)(
-    apr_socket_t *skt,
-    serf_bucket_t **read_bkt,
-    serf_bucket_t **write_bkt,
-    void *setup_baton,
-    apr_pool_t *pool);
-
-/**
- * ### need to update docco w.r.t socket. became "stream" recently.
- * ### the stream does not have a barrier, this callback should generally
- * ### add a barrier around the stream before incorporating it into a
- * ### response bucket stack.
- * ### should serf add the barrier automatically to protect its data
- * ### structure? i.e. the passed bucket becomes owned rather than
- * ### borrowed. that might suit overall semantics better.
- * Accept an incoming response for @a request, and its @a socket. A bucket
- * for the response should be constructed and returned. This is the control
- * point for assembling the appropriate wrapper buckets around the socket to
- * enable processing of the incoming response.
- *
- * The @a acceptor_baton is the baton provided when the specified request
- * was created.
- *
- * The request's pool and bucket allocator should be used for any allocations
- * that need to live for the duration of the response. Care should be taken
- * to bound the amount of memory stored in this pool -- to ensure that
- * allocations are not proportional to the amount of data in the response.
- *
- * Responsibility for the bucket is passed to the serf library. It will be
- * destroyed when the response has been fully read (the bucket returns an
- * APR_EOF status from its read functions).
- *
- * All temporary allocations should be made in @a pool.
- */
-/* ### do we need to return an error? */
-typedef serf_bucket_t * (*serf_response_acceptor_t)(
-    serf_request_t *request,
-    serf_bucket_t *stream,
-    void *acceptor_baton,
-    apr_pool_t *pool);
-
-/**
- * Notification callback for when a connection closes.
- *
- * This callback is used to inform an application that the @a conn
- * connection has been (abnormally) closed. The @a closed_baton is the
- * baton provided when the connection was first opened. The reason for
- * closure is given in @a why, and will be APR_SUCCESS if the application
- * requested closure (by clearing the pool used to allocate this
- * connection or calling serf_connection_close).
- *
- * All temporary allocations should be made in @a pool.
- */
-typedef void (*serf_connection_closed_t)(
-    serf_connection_t *conn,
-    void *closed_baton,
-    apr_status_t why,
-    apr_pool_t *pool);
-
-/**
- * Response data has arrived and should be processed.
- *
- * Whenever response data for @a request arrives (initially, or continued data
- * arrival), this handler is invoked. The response data is available in the
- * @a response bucket. The @a handler_baton is passed along from the baton
- * provided by the request setup callback (@see serf_request_setup_t).
- *
- * The handler MUST process data from the @a response bucket until the
- * bucket's read function states it would block (see APR_STATUS_IS_EAGAIN).
- * The handler is invoked only when new data arrives. If no further data
- * arrives, and the handler does not process all available data, then the
- * system can result in a deadlock around the unprocessed, but read, data.
- *
- * The handler should return APR_EOF when the response has been fully read.
- * If calling the handler again would block, APR_EAGAIN should be returned.
- * If the handler should be invoked again, simply return APR_SUCCESS.
- *
- * Note: if the connection closed (at the request of the application, or
- * because of an (abnormal) termination) while a request is being delivered,
- * or before a response arrives, then @a response will be NULL. This is the
- * signal that the request was not delivered properly, and no further
- * response should be expected (this callback will not be invoked again).
- * If a request is injected into the connection (during this callback's
- * execution, or otherwise), then the connection will be reopened.
- *
- * All temporary allocations should be made in @a pool.
- */
-typedef apr_status_t (*serf_response_handler_t)(
-    serf_request_t *request,
-    serf_bucket_t *response,
-    void *handler_baton,
-    apr_pool_t *pool);
-
-/**
- * Callback function to be implemented by the application, so that serf
- * can handle server and proxy authentication.
- * code = 401 (server) or 407 (proxy).
- * baton = the baton passed to serf_context_run.
- * authn_type = one of "Basic", "Digest".
- */
-typedef apr_status_t (*serf_credentials_callback_t)(
-    char **username,
-    char **password,
-    serf_request_t *request, void *baton,
-    int code, const char *authn_type,
-    const char *realm,
-    apr_pool_t *pool);
-
-/**
- * Create a new connection associated with the @a ctx serf context.
- *
- * If no proxy server is configured, 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).
- * If a proxy server is configured, @address will be ignored.
- *
- * 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_connection_t *serf_connection_create(
-    serf_context_t *ctx,
-    apr_sockaddr_t *address,
-    serf_connection_setup_t setup,
-    void *setup_baton,
-    serf_connection_closed_t closed,
-    void *closed_baton,
-    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.
- */
-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);
-
-
-typedef apr_status_t (*serf_accept_client_t)(
-    serf_context_t *ctx,
-    serf_listener_t *l,
-    void *accept_baton,
-    apr_socket_t *insock,
-    apr_pool_t *pool);
-
-apr_status_t serf_listener_create(
-    serf_listener_t **listener,
-    serf_context_t *ctx,
-    const char *host,
-    apr_uint16_t port,
-    void *accept_baton,
-    serf_accept_client_t accept_func,
-    apr_pool_t *pool);
-
-typedef apr_status_t (*serf_incoming_request_cb_t)(
-    serf_context_t *ctx,
-    serf_incoming_request_t *req,
-    void *request_baton,
-    apr_pool_t *pool);
-
-apr_status_t serf_incoming_create(
-    serf_incoming_t **client,
-    serf_context_t *ctx,
-    apr_socket_t *insock,
-    void *request_baton,
-    serf_incoming_request_cb_t request,
-    apr_pool_t *pool);
-
-
-
-
-/**
- * Reset the connection, but re-open the socket again.
- */
-apr_status_t serf_connection_reset(
-    serf_connection_t *conn);
-
-/**
- * Close the connection associated with @a conn and cancel all pending requests.
- *
- * The closed callback passed to serf_connection_create() will be invoked
- * with APR_SUCCESS.
- */
-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.
- *
- * In general, serf tends to take around 16KB per outstanding request.
- */
-void serf_connection_set_max_outstanding_requests(
-    serf_connection_t *conn,
-    unsigned int max_requests);
-
-void serf_connection_set_async_responses(
-    serf_connection_t *conn,
-    serf_response_acceptor_t acceptor,
-    void *acceptor_baton,
-    serf_response_handler_t handler,
-    void *handler_baton);
-
-/**
- * Setup the @a request for delivery on its connection.
- *
- * Right before this is invoked, @a pool will be built within the
- * connection's pool for the request to use.  The associated response will
- * be allocated within that subpool. An associated bucket allocator will
- * be built. These items may be fetched from the request object through
- * @see serf_request_get_pool or @see serf_request_get_alloc.
- *
- * The content of the request is specified by the @a req_bkt bucket. When
- * a response arrives, the @a acceptor callback will be invoked (along with
- * the @a acceptor_baton) to produce a response bucket. That bucket will then
- * be passed to @a handler, along with the @a handler_baton.
- *
- * The responsibility for the request bucket is passed to the request
- * object. When the request is done with the bucket, it will be destroyed.
- */
-typedef apr_status_t (*serf_request_setup_t)(
-    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);
-
-/**
- * Construct a request object for the @a conn connection.
- *
- * 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_request_t *serf_connection_request_create(
-    serf_connection_t *conn,
-    serf_request_setup_t setup,
-    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_request_t *serf_connection_priority_request_create(
-    serf_connection_t *conn,
-    serf_request_setup_t setup,
-    void *setup_baton);
-
-
-/** Returns detected network latency for the @a conn connection. Negative
- *  value means that latency is unknwon.
- */
-apr_interval_time_t serf_connection_get_latency(serf_connection_t *conn);
-
-/** Check if a @a request has been completely written.
- *
- * Returns APR_SUCCESS if the request was written completely on the connection.
- * Returns APR_EBUSY if the request is not yet or partially written.
- */
-apr_status_t serf_request_is_written(
-    serf_request_t *request);
-
-/**
- * Cancel the request specified by the @a request object.
- *
- * If the request has been scheduled for delivery, then its response
- * handler will be run, passing NULL for the response bucket.
- *
- * If the request has already been (partially or fully) delivered, then
- * APR_EBUSY is returned and the request is *NOT* canceled. To properly
- * cancel the request, the connection must be closed (by clearing or
- * destroying its associated pool).
- */
-apr_status_t serf_request_cancel(
-    serf_request_t *request);
-
-/**
- * Return the pool associated with @a request.
- *
- * WARNING: be very careful about the kinds of things placed into this
- * pool. In particular, all allocation should be bounded in size, rather
- * than proportional to any data stream.
- */
-apr_pool_t *serf_request_get_pool(
-    const serf_request_t *request);
-
-/**
- * Return the bucket allocator associated with @a request.
- */
-serf_bucket_alloc_t *serf_request_get_alloc(
-    const serf_request_t *request);
-
-/**
- * Return the connection associated with @a request.
- */
-serf_connection_t *serf_request_get_conn(
-    const serf_request_t *request);
-
-/**
- * Update the @a handler and @a handler_baton for this @a request.
- *
- * This can be called after the request has started processing -
- * subsequent data will be delivered to this new handler.
- */
-void serf_request_set_handler(
-    serf_request_t *request,
-    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.
- */
-void serf_config_proxy(
-    serf_context_t *ctx,
-    apr_sockaddr_t *address);
-
-/* Supported authentication types. */
-#define SERF_AUTHN_NONE      0x00
-#define SERF_AUTHN_BASIC     0x01
-#define SERF_AUTHN_DIGEST    0x02
-#define SERF_AUTHN_NTLM      0x04
-#define SERF_AUTHN_NEGOTIATE 0x08
-#define SERF_AUTHN_ALL       0xFF
-
-/**
- * Define the authentication handlers that serf will try on incoming requests.
- */
-void serf_config_authn_types(
-    serf_context_t *ctx,
-    int authn_types);
-
-/**
- * Set the credentials callback handler.
- */
-void serf_config_credentials_callback(
-    serf_context_t *ctx,
-    serf_credentials_callback_t cred_cb);
-
-/* ### 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_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.
- *
- * This function will set following header(s):
- * - Host: if the connection was created with @a serf_connection_create2.
- */
-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);
-
-/** @} */
-
-
-/**
- * @defgroup serf buckets
- * @ingroup serf
- * @{
- */
-
-/** Pass as REQUESTED to the read function of a bucket to read, consume,
- * and return all available data.
- */
-#define SERF_READ_ALL_AVAIL ((apr_size_t)-1)
-
-/** Acceptable newline types for bucket->readline(). */
-#define SERF_NEWLINE_CR    0x0001
-#define SERF_NEWLINE_CRLF  0x0002
-#define SERF_NEWLINE_LF    0x0004
-#define SERF_NEWLINE_ANY   0x0007
-
-/** Used to indicate that a newline is not present in the data buffer. */
-/* ### should we make this zero? */
-#define SERF_NEWLINE_NONE  0x0008
-
-/** Used to indicate that a CR was found at the end of a buffer, and CRLF
- * was acceptable. It may be that the LF is present, but it needs to be
- * read first.
- *
- * Note: an alternative to using this symbol would be for callers to see
- * the SERF_NEWLINE_CR return value, and know that some "end of buffer" was
- * reached. While this works well for @see serf_util_readline, it does not
- * necessary work as well for buckets (there is no obvious "end of buffer",
- * although there is an "end of bucket"). The other problem with that
- * alternative is that developers might miss the condition. This symbol
- * calls out the possibility and ensures that callers will watch for it.
- */
-#define SERF_NEWLINE_CRLF_SPLIT 0x0010
-
-
-struct serf_bucket_type_t {
-
-    /** name of this bucket type */
-    const char *name;
-
-    /**
-     * Read (and consume) up to @a requested bytes from @a bucket.
-     *
-     * A pointer to the data will be returned in @a data, and its length
-     * is specified by @a len.
-     *
-     * The data will exist until one of two conditions occur:
-     *
-     * 1) this bucket is destroyed
-     * 2) another call to any read function or to peek()
-     *
-     * If an application needs the data to exist for a longer duration,
-     * then it must make a copy.
-     */
-    apr_status_t (*read)(serf_bucket_t *bucket, apr_size_t requested,
-                         const char **data, apr_size_t *len);
-
-    /**
-     * Read (and consume) a line of data from @a bucket.
-     *
-     * The acceptable forms of a newline are given by @a acceptable, and
-     * the type found is returned in @a found. If a newline is not present
-     * in the returned data, then SERF_NEWLINE_NONE is stored into @a found.
-     *
-     * A pointer to the data is returned in @a data, and its length is
-     * specified by @a len. The data will include the newline, if present.
-     *
-     * Note that there is no way to limit the amount of data returned
-     * by this function.
-     *
-     * The lifetime of the data is the same as that of the @see read
-     * function above.
-     */
-    apr_status_t (*readline)(serf_bucket_t *bucket, int acceptable,
-                             int *found,
-                             const char **data, apr_size_t *len);
-
-    /**
-     * Read a set of pointer/length pairs from the bucket.
-     *
-     * The size of the @a vecs array is specified by @a vecs_size. The
-     * bucket should fill in elements of the array, and return the number
-     * used in @a vecs_used.
-     *
-     * Each element of @a vecs should specify a pointer to a block of
-     * data and a length of that data.
-     *
-     * The total length of all data elements should not exceed the
-     * amount specified in @a requested.
-     *
-     * The lifetime of the data is the same as that of the @see read
-     * function above.
-     */
-    apr_status_t (*read_iovec)(serf_bucket_t *bucket, apr_size_t requested,
-                               int vecs_size, struct iovec *vecs,
-                               int *vecs_used);
-
-    /**
-     * Read data from the bucket in a form suitable for apr_socket_sendfile()
-     *
-     * On input, hdtr->numheaders and hdtr->numtrailers specify the size
-     * of the hdtr->headers and hdtr->trailers arrays, respectively. The
-     * bucket should fill in the headers and trailers, up to the specified
-     * limits, and set numheaders and numtrailers to the number of iovecs
-     * filled in for each item.
-     *
-     * @a file should be filled in with a file that can be read. If a file
-     * is not available or appropriate, then NULL should be stored. The
-     * file offset for the data should be stored in @a offset, and the
-     * length of that data should be stored in @a len. If a file is not
-     * returned, then @a offset and @a len should be ignored.
-     *
-     * The file position is not required to correspond to @a offset, and
-     * the caller may manipulate it at will.
-     *
-     * The total length of all data elements, and the portion of the
-     * file should not exceed the amount specified in @a requested.
-     *
-     * The lifetime of the data is the same as that of the @see read
-     * function above.
-     */
-    apr_status_t (*read_for_sendfile)(serf_bucket_t *bucket,
-                                      apr_size_t requested, apr_hdtr_t *hdtr,
-                                      apr_file_t **file, apr_off_t *offset,
-                                      apr_size_t *len);
-
-    /**
-     * Look within @a bucket for a bucket of the given @a type. The bucket
-     * must be the "initial" data because it will be consumed by this
-     * function. If the given bucket type is available, then read and consume
-     * it, and return it to the caller.
-     *
-     * This function is usually used by readers that have custom handling
-     * for specific bucket types (e.g. looking for a file bucket to pass
-     * to apr_socket_sendfile).
-     *
-     * If a bucket of the given type is not found, then NULL is returned.
-     *
-     * The returned bucket becomes the responsibility of the caller. When
-     * the caller is done with the bucket, it should be destroyed.
-     */
-    serf_bucket_t * (*read_bucket)(serf_bucket_t *bucket,
-                                   const serf_bucket_type_t *type);
-
-    /**
-     * Peek, but don't consume, the data in @a bucket.
-     *
-     * Since this function is non-destructive, the implicit read size is
-     * SERF_READ_ALL_AVAIL. The caller can then use whatever amount is
-     * appropriate.
-     *
-     * The @a data parameter will point to the data, and @a len will
-     * specify how much data is available. The lifetime of the data follows
-     * the same rules as the @see read function above.
-     *
-     * Note: if the peek does not return enough data for your particular
-     * use, then you must read/consume some first, then peek again.
-     *
-     * If the returned data represents all available data, then APR_EOF
-     * will be returned. Since this function does not consume data, it
-     * can return the same data repeatedly rather than blocking; thus,
-     * APR_EAGAIN will never be returned.
-     */
-    apr_status_t (*peek)(serf_bucket_t *bucket,
-                         const char **data, apr_size_t *len);
-
-    /**
-     * Destroy @a bucket, along with any associated resources.
-     */
-    void (*destroy)(serf_bucket_t *bucket);
-
-    /* ### apr buckets have 'copy', 'split', and 'setaside' functions.
-       ### not sure whether those will be needed in this bucket model.
-    */
-};
-
-/**
- * Should the use and lifecycle of buckets be tracked?
- *
- * When tracking, the system will ensure several semantic requirements
- * of bucket use:
- *
- *   - if a bucket returns APR_EAGAIN, one of its read functions should
- *     not be called immediately. the context's run loop should be called.
- *     ### and for APR_EOF, too?
- *   - all buckets must be drained of input before returning to the
- *     context's run loop.
- *   - buckets should not be destroyed before they return APR_EOF unless
- *     the connection is closed for some reason.
- *
- * Undefine this symbol to avoid the tracking (and a performance gain).
- *
- * ### we may want to examine when/how we provide this. should it always
- * ### be compiled in? and apps select it before including this header?
- */
-/* #define SERF_DEBUG_BUCKET_USE */
-
-
-/* Internal macros for tracking bucket use. */
-#ifdef SERF_DEBUG_BUCKET_USE
-#define SERF__RECREAD(b,s) serf_debug__record_read(b,s)
-#else
-#define SERF__RECREAD(b,s) (s)
-#endif
-
-#define serf_bucket_read(b,r,d,l) SERF__RECREAD(b, (b)->type->read(b,r,d,l))
-#define serf_bucket_readline(b,a,f,d,l) \
-    SERF__RECREAD(b, (b)->type->readline(b,a,f,d,l))
-#define serf_bucket_read_iovec(b,r,s,v,u) \
-    SERF__RECREAD(b, (b)->type->read_iovec(b,r,s,v,u))
-#define serf_bucket_read_for_sendfile(b,r,h,f,o,l) \
-    SERF__RECREAD(b, (b)->type->read_for_sendfile(b,r,h,f,o,l))
-#define serf_bucket_read_bucket(b,t) ((b)->type->read_bucket(b,t))
-#define serf_bucket_peek(b,d,l) ((b)->type->peek(b,d,l))
-#define serf_bucket_destroy(b) ((b)->type->destroy(b))
-
-/**
- * Check whether a real error occurred. Note that bucket read functions
- * can return EOF and EAGAIN as part of their "normal" operation, so they
- * should not be considered an error.
- */
-#define SERF_BUCKET_READ_ERROR(status) ((status) \
-                                        && !APR_STATUS_IS_EOF(status) \
-                                        && !APR_STATUS_IS_EAGAIN(status) \
-                                        && (SERF_ERROR_WAIT_CONN != status))
-
-
-struct serf_bucket_t {
-
-    /** the type of this bucket */
-    const serf_bucket_type_t *type;
-
-    /** bucket-private data */
-    void *data;
-
-    /** the allocator used for this bucket (needed at destroy time) */
-    serf_bucket_alloc_t *allocator;
-};
-
-
-/**
- * Generic macro to construct "is TYPE" macros.
- */
-#define SERF_BUCKET_CHECK(b, btype) ((b)->type == &serf_bucket_type_ ## btype)
-
-
-/**
- * Notification callback for a block that was not returned to the bucket
- * allocator when its pool was destroyed.
- *
- * The block of memory is given by @a block. The baton provided when the
- * allocator was constructed is passed as @a unfreed_baton.
- */
-typedef void (*serf_unfreed_func_t)(
-    void *unfreed_baton,
-    void *block);
-
-/**
- * Create a new allocator for buckets.
- *
- * All buckets are associated with a serf bucket allocator. This allocator
- * will be created within @a pool and will be destroyed when that pool is
- * cleared or destroyed.
- *
- * When the allocator is destroyed, if any allocations were not explicitly
- * returned (by calling serf_bucket_mem_free), then the @a unfreed callback
- * will be invoked for each block. @a unfreed_baton will be passed to the
- * callback.
- *
- * If @a unfreed is NULL, then the library will invoke the abort() stdlib
- * call. Any failure to return memory is a bug in the application, and an
- * abort can assist with determining what kinds of memory were not freed.
- */
-serf_bucket_alloc_t *serf_bucket_allocator_create(
-    apr_pool_t *pool,
-    serf_unfreed_func_t unfreed,
-    void *unfreed_baton);
-
-/**
- * Return the pool that was used for this @a allocator.
- *
- * WARNING: the use of this pool for allocations requires a very
- *   detailed understanding of pool behaviors, the bucket system,
- *   and knowledge of the bucket's use within the overall pattern
- *   of request/response behavior.
- *
- * See design-guide.txt for more information about pool usage.
- */
-apr_pool_t *serf_bucket_allocator_get_pool(
-    const serf_bucket_alloc_t *allocator);
-
-
-/**
- * Utility structure for reading a complete line of input from a bucket.
- *
- * Since it is entirely possible for a line to be broken by APR_EAGAIN,
- * this structure can be used to accumulate the data until a complete line
- * has been read from a bucket.
- */
-
-/* This limit applies to the line buffer functions. If an application needs
- * longer lines, then they will need to manually handle line buffering.
- */
-#define SERF_LINEBUF_LIMIT 8000
-
-typedef struct {
-
-    /* Current state of the buffer. */
-    enum {
-        SERF_LINEBUF_EMPTY,
-        SERF_LINEBUF_READY,
-        SERF_LINEBUF_PARTIAL,
-        SERF_LINEBUF_CRLF_SPLIT
-    } state;
-
-    /* How much of the buffer have we used? */
-    apr_size_t used;
-
-    /* The line is read into this buffer, minus CR/LF */
-    char line[SERF_LINEBUF_LIMIT];
-
-} serf_linebuf_t;
-
-/**
- * Initialize the @a linebuf structure.
- */
-void serf_linebuf_init(serf_linebuf_t *linebuf);
-
-/**
- * Fetch a line of text from @a bucket, accumulating the line into
- * @a linebuf. @a acceptable specifies the types of newlines which are
- * acceptable for this fetch.
- *
- * ### we should return a data/len pair so that we can avoid a copy,
- * ### rather than having callers look into our state and line buffer.
- */
-apr_status_t serf_linebuf_fetch(
-    serf_linebuf_t *linebuf,
-    serf_bucket_t *bucket,
-    int acceptable);
-
-/** @} */
-
-
-/* Internal functions for bucket use and lifecycle tracking */
-apr_status_t serf_debug__record_read(
-    const serf_bucket_t *bucket,
-    apr_status_t status);
-void serf_debug__entered_loop(
-    serf_bucket_alloc_t *allocator);
-void serf_debug__closed_conn(
-    serf_bucket_alloc_t *allocator);
-void serf_debug__bucket_destroy(
-    const serf_bucket_t *bucket);
-void serf_debug__bucket_alloc_check(
-    serf_bucket_alloc_t *allocator);
-
-/* Version info */
-#define SERF_MAJOR_VERSION 1
-#define SERF_MINOR_VERSION 3
-#define SERF_PATCH_VERSION 8
-
-/* 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
- * level.
- * @param major The major version component of the version checked
- * for (e.g., the "1" of "1.3.0").
- * @param minor The minor version component of the version checked
- * for (e.g., the "3" of "1.3.0").
- * @param patch The patch level component of the version checked
- * for (e.g., the "0" of "1.3.0").
- */
-#define SERF_VERSION_AT_LEAST(major,minor,patch)                         \
-(((major) < SERF_MAJOR_VERSION)                                          \
-  || ((major) == SERF_MAJOR_VERSION && (minor) < SERF_MINOR_VERSION)     \
-   || ((major) == SERF_MAJOR_VERSION && (minor) == SERF_MINOR_VERSION && \
-            (patch) <= SERF_PATCH_VERSION))
-
-
-/**
- * Returns the version of the library the application has linked/loaded.
- * Values are returned in @a major, @a minor, and @a patch.
- *
- * Applications will want to use this function to verify compatibility,
- * expecially while serf has not reached a 1.0 milestone. APIs and
- * semantics may change drastically until the library hits 1.0.
- */
-void serf_lib_version(
-    int *major,
-    int *minor,
-    int *patch);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-
-/*
- * Every user of serf will want to deal with our various bucket types.
- * Go ahead and include that header right now.
- *
- * Note: make sure this occurs outside of the C++ namespace block
- */
-#include "serf_bucket_types.h"
-
-
-#endif    /* !SERF_H */

Copied: vendor/serf/1.3.9/serf.h (from rev 9259, vendor/serf/dist/serf.h)
===================================================================
--- vendor/serf/1.3.9/serf.h	                        (rev 0)
+++ vendor/serf/1.3.9/serf.h	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,1122 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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 SERF_H
+#define SERF_H
+
+/**
+ * @file serf.h
+ * @brief Main serf header file
+ */
+
+#include <apr.h>
+#include <apr_errno.h>
+#include <apr_allocator.h>
+#include <apr_pools.h>
+#include <apr_network_io.h>
+#include <apr_time.h>
+#include <apr_poll.h>
+#include <apr_uri.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Forward declare some structures */
+typedef struct serf_context_t serf_context_t;
+
+typedef struct serf_bucket_t serf_bucket_t;
+typedef struct serf_bucket_type_t serf_bucket_type_t;
+typedef struct serf_bucket_alloc_t serf_bucket_alloc_t;
+
+typedef struct serf_connection_t serf_connection_t;
+typedef struct serf_listener_t serf_listener_t;
+typedef struct serf_incoming_t serf_incoming_t;
+typedef struct serf_incoming_request_t serf_incoming_request_t;
+
+typedef struct serf_request_t serf_request_t;
+
+
+/**
+ * @defgroup serf high-level constructs
+ * @ingroup serf
+ * @{
+ */
+
+/**
+ * Serf-specific error codes
+ */
+#define SERF_ERROR_RANGE 100
+#define SERF_ERROR_START (APR_OS_START_USERERR + SERF_ERROR_RANGE)
+
+/* This code is for when this is the last response on this connection:
+ * i.e. do not send any more requests on this connection or expect
+ * any more responses.
+ */
+#define SERF_ERROR_CLOSING (SERF_ERROR_START + 1)
+/* This code is for when the connection terminated before the request
+ * could be processed on the other side.
+ */
+#define SERF_ERROR_REQUEST_LOST (SERF_ERROR_START + 2)
+/* This code is for when the connection is blocked - we can not proceed
+ * until something happens - generally due to SSL negotiation-like behavior
+ * where a write() is blocked until a read() is processed.
+ */
+#define SERF_ERROR_WAIT_CONN (SERF_ERROR_START + 3)
+/* This code is for when something went wrong during deflating compressed
+ * data e.g. a CRC error. */
+#define SERF_ERROR_DECOMPRESSION_FAILED (SERF_ERROR_START + 4)
+/* This code is for when a response received from a http server is not in
+ * http-compliant syntax. */
+#define SERF_ERROR_BAD_HTTP_RESPONSE (SERF_ERROR_START + 5)
+/* The server sent less data than what was announced. */
+#define SERF_ERROR_TRUNCATED_HTTP_RESPONSE (SERF_ERROR_START + 6)
+/* The proxy server returned an error while setting up the SSL tunnel. */
+#define SERF_ERROR_SSLTUNNEL_SETUP_FAILED (SERF_ERROR_START + 7)
+/* The server unexpectedly closed the connection prematurely. */
+#define SERF_ERROR_ABORTED_CONNECTION (SERF_ERROR_START + 8)
+
+/* SSL certificates related errors */
+#define SERF_ERROR_SSL_CERT_FAILED (SERF_ERROR_START + 70)
+
+/* SSL communications related errors */
+#define SERF_ERROR_SSL_COMM_FAILED (SERF_ERROR_START + 71)
+
+/* General authentication related errors */
+#define SERF_ERROR_AUTHN_FAILED (SERF_ERROR_START + 90)
+
+/* None of the available authn mechanisms for the request are supported */
+#define SERF_ERROR_AUTHN_NOT_SUPPORTED (SERF_ERROR_START + 91)
+
+/* Authn was requested by the server but the header lacked some attribute  */
+#define SERF_ERROR_AUTHN_MISSING_ATTRIBUTE (SERF_ERROR_START + 92)
+
+/* Authentication handler initialization related errors */
+#define SERF_ERROR_AUTHN_INITALIZATION_FAILED (SERF_ERROR_START + 93)
+
+/* Error code reserved for use in the test suite. */
+#define SERF_ERROR_ISSUE_IN_TESTSUITE (SERF_ERROR_START + 99)
+
+/* This macro groups errors potentially raised when reading a http response.  */
+#define SERF_BAD_RESPONSE_ERROR(status) ((status) \
+    && ((SERF_ERROR_DECOMPRESSION_FAILED == (status)) \
+        ||(SERF_ERROR_BAD_HTTP_RESPONSE == (status)) \
+        ||(SERF_ERROR_TRUNCATED_HTTP_RESPONSE == (status))))
+
+/**
+ * Return a string that describes the specified error code.
+ *
+ * If the error code is not one of the above Serf error codes, then
+ * NULL will be returned.
+ *
+ * Note regarding lifetime: the string is a statically-allocated constant
+ */
+const char *serf_error_string(apr_status_t errcode);
+
+
+/**
+ * Create a new context for serf operations.
+ *
+ * A serf context defines a control loop which processes multiple
+ * connections simultaneously.
+ *
+ * The context will be allocated within @a pool.
+ */
+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_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.
+ */
+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". */
+#define SERF_DURATION_FOREVER 2000000000        /* approx 1^31 */
+
+/**
+ * Run the main networking control loop.
+ *
+ * The set of connections defined by the serf context @a ctx are processed.
+ * Any outbound data is delivered, and incoming data is made available to
+ * the associated response handlers and their buckets. This function will
+ * block on the network for no longer than @a duration microseconds.
+ *
+ * If any data is processed (incoming or outgoing), then this function will
+ * return with APR_SUCCESS. Typically, the caller will just want to call it
+ * again to continue processing data.
+ *
+ * If no activity occurs within the specified timeout duration, then
+ * APR_TIMEUP is returned.
+ *
+ * All temporary allocations will be made in @a pool.
+ */
+apr_status_t serf_context_run(
+    serf_context_t *ctx,
+    apr_short_interval_time_t duration,
+    apr_pool_t *pool);
+
+
+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.
+ */
+void serf_context_set_progress_cb(
+    serf_context_t *ctx,
+    const serf_progress_t progress_func,
+    void *progress_baton);
+
+/** @} */
+
+/**
+ * @defgroup serf connections and requests
+ * @ingroup serf
+ * @{
+ */
+
+/**
+ * When a connection is established, the application needs to wrap some
+ * buckets around @a skt to enable serf to process incoming responses. This
+ * is the control point for assembling connection-level processing logic
+ * around the given socket.
+ *
+ * The @a setup_baton is the baton established at connection creation time.
+ *
+ * This callback corresponds to reading from the server. Since this is an
+ * on-demand activity, we use a callback. The corresponding write operation
+ * is based on the @see serf_request_deliver function, where the application
+ * can assemble the appropriate bucket(s) before delivery.
+ *
+ * The returned bucket should live at least as long as the connection itself.
+ * It is assumed that an appropriate allocator is passed in @a setup_baton.
+ * ### we may want to create a connection-level allocator and pass that
+ * ### along. however, that allocator would *only* be used for this
+ * ### callback. it may be wasteful to create a per-conn allocator, so this
+ * ### baton-based, app-responsible form might be best.
+ *
+ * Responsibility for the buckets is passed to the serf library. They will be
+ * destroyed when the connection is closed.
+ *
+ * All temporary allocations should be made in @a pool.
+ */
+typedef apr_status_t (*serf_connection_setup_t)(
+    apr_socket_t *skt,
+    serf_bucket_t **read_bkt,
+    serf_bucket_t **write_bkt,
+    void *setup_baton,
+    apr_pool_t *pool);
+
+/**
+ * ### need to update docco w.r.t socket. became "stream" recently.
+ * ### the stream does not have a barrier, this callback should generally
+ * ### add a barrier around the stream before incorporating it into a
+ * ### response bucket stack.
+ * ### should serf add the barrier automatically to protect its data
+ * ### structure? i.e. the passed bucket becomes owned rather than
+ * ### borrowed. that might suit overall semantics better.
+ * Accept an incoming response for @a request, and its @a socket. A bucket
+ * for the response should be constructed and returned. This is the control
+ * point for assembling the appropriate wrapper buckets around the socket to
+ * enable processing of the incoming response.
+ *
+ * The @a acceptor_baton is the baton provided when the specified request
+ * was created.
+ *
+ * The request's pool and bucket allocator should be used for any allocations
+ * that need to live for the duration of the response. Care should be taken
+ * to bound the amount of memory stored in this pool -- to ensure that
+ * allocations are not proportional to the amount of data in the response.
+ *
+ * Responsibility for the bucket is passed to the serf library. It will be
+ * destroyed when the response has been fully read (the bucket returns an
+ * APR_EOF status from its read functions).
+ *
+ * All temporary allocations should be made in @a pool.
+ */
+/* ### do we need to return an error? */
+typedef serf_bucket_t * (*serf_response_acceptor_t)(
+    serf_request_t *request,
+    serf_bucket_t *stream,
+    void *acceptor_baton,
+    apr_pool_t *pool);
+
+/**
+ * Notification callback for when a connection closes.
+ *
+ * This callback is used to inform an application that the @a conn
+ * connection has been (abnormally) closed. The @a closed_baton is the
+ * baton provided when the connection was first opened. The reason for
+ * closure is given in @a why, and will be APR_SUCCESS if the application
+ * requested closure (by clearing the pool used to allocate this
+ * connection or calling serf_connection_close).
+ *
+ * All temporary allocations should be made in @a pool.
+ */
+typedef void (*serf_connection_closed_t)(
+    serf_connection_t *conn,
+    void *closed_baton,
+    apr_status_t why,
+    apr_pool_t *pool);
+
+/**
+ * Response data has arrived and should be processed.
+ *
+ * Whenever response data for @a request arrives (initially, or continued data
+ * arrival), this handler is invoked. The response data is available in the
+ * @a response bucket. The @a handler_baton is passed along from the baton
+ * provided by the request setup callback (@see serf_request_setup_t).
+ *
+ * The handler MUST process data from the @a response bucket until the
+ * bucket's read function states it would block (see APR_STATUS_IS_EAGAIN).
+ * The handler is invoked only when new data arrives. If no further data
+ * arrives, and the handler does not process all available data, then the
+ * system can result in a deadlock around the unprocessed, but read, data.
+ *
+ * The handler should return APR_EOF when the response has been fully read.
+ * If calling the handler again would block, APR_EAGAIN should be returned.
+ * If the handler should be invoked again, simply return APR_SUCCESS.
+ *
+ * Note: if the connection closed (at the request of the application, or
+ * because of an (abnormal) termination) while a request is being delivered,
+ * or before a response arrives, then @a response will be NULL. This is the
+ * signal that the request was not delivered properly, and no further
+ * response should be expected (this callback will not be invoked again).
+ * If a request is injected into the connection (during this callback's
+ * execution, or otherwise), then the connection will be reopened.
+ *
+ * All temporary allocations should be made in @a pool.
+ */
+typedef apr_status_t (*serf_response_handler_t)(
+    serf_request_t *request,
+    serf_bucket_t *response,
+    void *handler_baton,
+    apr_pool_t *pool);
+
+/**
+ * Callback function to be implemented by the application, so that serf
+ * can handle server and proxy authentication.
+ * code = 401 (server) or 407 (proxy).
+ * baton = the baton passed to serf_context_run.
+ * authn_type = one of "Basic", "Digest".
+ */
+typedef apr_status_t (*serf_credentials_callback_t)(
+    char **username,
+    char **password,
+    serf_request_t *request, void *baton,
+    int code, const char *authn_type,
+    const char *realm,
+    apr_pool_t *pool);
+
+/**
+ * Create a new connection associated with the @a ctx serf context.
+ *
+ * If no proxy server is configured, 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).
+ * If a proxy server is configured, @address will be ignored.
+ *
+ * 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_connection_t *serf_connection_create(
+    serf_context_t *ctx,
+    apr_sockaddr_t *address,
+    serf_connection_setup_t setup,
+    void *setup_baton,
+    serf_connection_closed_t closed,
+    void *closed_baton,
+    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.
+ */
+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);
+
+
+typedef apr_status_t (*serf_accept_client_t)(
+    serf_context_t *ctx,
+    serf_listener_t *l,
+    void *accept_baton,
+    apr_socket_t *insock,
+    apr_pool_t *pool);
+
+apr_status_t serf_listener_create(
+    serf_listener_t **listener,
+    serf_context_t *ctx,
+    const char *host,
+    apr_uint16_t port,
+    void *accept_baton,
+    serf_accept_client_t accept_func,
+    apr_pool_t *pool);
+
+typedef apr_status_t (*serf_incoming_request_cb_t)(
+    serf_context_t *ctx,
+    serf_incoming_request_t *req,
+    void *request_baton,
+    apr_pool_t *pool);
+
+apr_status_t serf_incoming_create(
+    serf_incoming_t **client,
+    serf_context_t *ctx,
+    apr_socket_t *insock,
+    void *request_baton,
+    serf_incoming_request_cb_t request,
+    apr_pool_t *pool);
+
+
+
+
+/**
+ * Reset the connection, but re-open the socket again.
+ */
+apr_status_t serf_connection_reset(
+    serf_connection_t *conn);
+
+/**
+ * Close the connection associated with @a conn and cancel all pending requests.
+ *
+ * The closed callback passed to serf_connection_create() will be invoked
+ * with APR_SUCCESS.
+ */
+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.
+ *
+ * In general, serf tends to take around 16KB per outstanding request.
+ */
+void serf_connection_set_max_outstanding_requests(
+    serf_connection_t *conn,
+    unsigned int max_requests);
+
+void serf_connection_set_async_responses(
+    serf_connection_t *conn,
+    serf_response_acceptor_t acceptor,
+    void *acceptor_baton,
+    serf_response_handler_t handler,
+    void *handler_baton);
+
+/**
+ * Setup the @a request for delivery on its connection.
+ *
+ * Right before this is invoked, @a pool will be built within the
+ * connection's pool for the request to use.  The associated response will
+ * be allocated within that subpool. An associated bucket allocator will
+ * be built. These items may be fetched from the request object through
+ * @see serf_request_get_pool or @see serf_request_get_alloc.
+ *
+ * The content of the request is specified by the @a req_bkt bucket. When
+ * a response arrives, the @a acceptor callback will be invoked (along with
+ * the @a acceptor_baton) to produce a response bucket. That bucket will then
+ * be passed to @a handler, along with the @a handler_baton.
+ *
+ * The responsibility for the request bucket is passed to the request
+ * object. When the request is done with the bucket, it will be destroyed.
+ */
+typedef apr_status_t (*serf_request_setup_t)(
+    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);
+
+/**
+ * Construct a request object for the @a conn connection.
+ *
+ * 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_request_t *serf_connection_request_create(
+    serf_connection_t *conn,
+    serf_request_setup_t setup,
+    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_request_t *serf_connection_priority_request_create(
+    serf_connection_t *conn,
+    serf_request_setup_t setup,
+    void *setup_baton);
+
+
+/** Returns detected network latency for the @a conn connection. Negative
+ *  value means that latency is unknwon.
+ */
+apr_interval_time_t serf_connection_get_latency(serf_connection_t *conn);
+
+/** Check if a @a request has been completely written.
+ *
+ * Returns APR_SUCCESS if the request was written completely on the connection.
+ * Returns APR_EBUSY if the request is not yet or partially written.
+ */
+apr_status_t serf_request_is_written(
+    serf_request_t *request);
+
+/**
+ * Cancel the request specified by the @a request object.
+ *
+ * If the request has been scheduled for delivery, then its response
+ * handler will be run, passing NULL for the response bucket.
+ *
+ * If the request has already been (partially or fully) delivered, then
+ * APR_EBUSY is returned and the request is *NOT* canceled. To properly
+ * cancel the request, the connection must be closed (by clearing or
+ * destroying its associated pool).
+ */
+apr_status_t serf_request_cancel(
+    serf_request_t *request);
+
+/**
+ * Return the pool associated with @a request.
+ *
+ * WARNING: be very careful about the kinds of things placed into this
+ * pool. In particular, all allocation should be bounded in size, rather
+ * than proportional to any data stream.
+ */
+apr_pool_t *serf_request_get_pool(
+    const serf_request_t *request);
+
+/**
+ * Return the bucket allocator associated with @a request.
+ */
+serf_bucket_alloc_t *serf_request_get_alloc(
+    const serf_request_t *request);
+
+/**
+ * Return the connection associated with @a request.
+ */
+serf_connection_t *serf_request_get_conn(
+    const serf_request_t *request);
+
+/**
+ * Update the @a handler and @a handler_baton for this @a request.
+ *
+ * This can be called after the request has started processing -
+ * subsequent data will be delivered to this new handler.
+ */
+void serf_request_set_handler(
+    serf_request_t *request,
+    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.
+ */
+void serf_config_proxy(
+    serf_context_t *ctx,
+    apr_sockaddr_t *address);
+
+/* Supported authentication types. */
+#define SERF_AUTHN_NONE      0x00
+#define SERF_AUTHN_BASIC     0x01
+#define SERF_AUTHN_DIGEST    0x02
+#define SERF_AUTHN_NTLM      0x04
+#define SERF_AUTHN_NEGOTIATE 0x08
+#define SERF_AUTHN_ALL       0xFF
+
+/**
+ * Define the authentication handlers that serf will try on incoming requests.
+ */
+void serf_config_authn_types(
+    serf_context_t *ctx,
+    int authn_types);
+
+/**
+ * Set the credentials callback handler.
+ */
+void serf_config_credentials_callback(
+    serf_context_t *ctx,
+    serf_credentials_callback_t cred_cb);
+
+/* ### 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_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.
+ *
+ * This function will set following header(s):
+ * - Host: if the connection was created with @a serf_connection_create2.
+ */
+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);
+
+/** @} */
+
+
+/**
+ * @defgroup serf buckets
+ * @ingroup serf
+ * @{
+ */
+
+/** Pass as REQUESTED to the read function of a bucket to read, consume,
+ * and return all available data.
+ */
+#define SERF_READ_ALL_AVAIL ((apr_size_t)-1)
+
+/** Acceptable newline types for bucket->readline(). */
+#define SERF_NEWLINE_CR    0x0001
+#define SERF_NEWLINE_CRLF  0x0002
+#define SERF_NEWLINE_LF    0x0004
+#define SERF_NEWLINE_ANY   0x0007
+
+/** Used to indicate that a newline is not present in the data buffer. */
+/* ### should we make this zero? */
+#define SERF_NEWLINE_NONE  0x0008
+
+/** Used to indicate that a CR was found at the end of a buffer, and CRLF
+ * was acceptable. It may be that the LF is present, but it needs to be
+ * read first.
+ *
+ * Note: an alternative to using this symbol would be for callers to see
+ * the SERF_NEWLINE_CR return value, and know that some "end of buffer" was
+ * reached. While this works well for @see serf_util_readline, it does not
+ * necessary work as well for buckets (there is no obvious "end of buffer",
+ * although there is an "end of bucket"). The other problem with that
+ * alternative is that developers might miss the condition. This symbol
+ * calls out the possibility and ensures that callers will watch for it.
+ */
+#define SERF_NEWLINE_CRLF_SPLIT 0x0010
+
+
+struct serf_bucket_type_t {
+
+    /** name of this bucket type */
+    const char *name;
+
+    /**
+     * Read (and consume) up to @a requested bytes from @a bucket.
+     *
+     * A pointer to the data will be returned in @a data, and its length
+     * is specified by @a len.
+     *
+     * The data will exist until one of two conditions occur:
+     *
+     * 1) this bucket is destroyed
+     * 2) another call to any read function or to peek()
+     *
+     * If an application needs the data to exist for a longer duration,
+     * then it must make a copy.
+     */
+    apr_status_t (*read)(serf_bucket_t *bucket, apr_size_t requested,
+                         const char **data, apr_size_t *len);
+
+    /**
+     * Read (and consume) a line of data from @a bucket.
+     *
+     * The acceptable forms of a newline are given by @a acceptable, and
+     * the type found is returned in @a found. If a newline is not present
+     * in the returned data, then SERF_NEWLINE_NONE is stored into @a found.
+     *
+     * A pointer to the data is returned in @a data, and its length is
+     * specified by @a len. The data will include the newline, if present.
+     *
+     * Note that there is no way to limit the amount of data returned
+     * by this function.
+     *
+     * The lifetime of the data is the same as that of the @see read
+     * function above.
+     */
+    apr_status_t (*readline)(serf_bucket_t *bucket, int acceptable,
+                             int *found,
+                             const char **data, apr_size_t *len);
+
+    /**
+     * Read a set of pointer/length pairs from the bucket.
+     *
+     * The size of the @a vecs array is specified by @a vecs_size. The
+     * bucket should fill in elements of the array, and return the number
+     * used in @a vecs_used.
+     *
+     * Each element of @a vecs should specify a pointer to a block of
+     * data and a length of that data.
+     *
+     * The total length of all data elements should not exceed the
+     * amount specified in @a requested.
+     *
+     * The lifetime of the data is the same as that of the @see read
+     * function above.
+     */
+    apr_status_t (*read_iovec)(serf_bucket_t *bucket, apr_size_t requested,
+                               int vecs_size, struct iovec *vecs,
+                               int *vecs_used);
+
+    /**
+     * Read data from the bucket in a form suitable for apr_socket_sendfile()
+     *
+     * On input, hdtr->numheaders and hdtr->numtrailers specify the size
+     * of the hdtr->headers and hdtr->trailers arrays, respectively. The
+     * bucket should fill in the headers and trailers, up to the specified
+     * limits, and set numheaders and numtrailers to the number of iovecs
+     * filled in for each item.
+     *
+     * @a file should be filled in with a file that can be read. If a file
+     * is not available or appropriate, then NULL should be stored. The
+     * file offset for the data should be stored in @a offset, and the
+     * length of that data should be stored in @a len. If a file is not
+     * returned, then @a offset and @a len should be ignored.
+     *
+     * The file position is not required to correspond to @a offset, and
+     * the caller may manipulate it at will.
+     *
+     * The total length of all data elements, and the portion of the
+     * file should not exceed the amount specified in @a requested.
+     *
+     * The lifetime of the data is the same as that of the @see read
+     * function above.
+     */
+    apr_status_t (*read_for_sendfile)(serf_bucket_t *bucket,
+                                      apr_size_t requested, apr_hdtr_t *hdtr,
+                                      apr_file_t **file, apr_off_t *offset,
+                                      apr_size_t *len);
+
+    /**
+     * Look within @a bucket for a bucket of the given @a type. The bucket
+     * must be the "initial" data because it will be consumed by this
+     * function. If the given bucket type is available, then read and consume
+     * it, and return it to the caller.
+     *
+     * This function is usually used by readers that have custom handling
+     * for specific bucket types (e.g. looking for a file bucket to pass
+     * to apr_socket_sendfile).
+     *
+     * If a bucket of the given type is not found, then NULL is returned.
+     *
+     * The returned bucket becomes the responsibility of the caller. When
+     * the caller is done with the bucket, it should be destroyed.
+     */
+    serf_bucket_t * (*read_bucket)(serf_bucket_t *bucket,
+                                   const serf_bucket_type_t *type);
+
+    /**
+     * Peek, but don't consume, the data in @a bucket.
+     *
+     * Since this function is non-destructive, the implicit read size is
+     * SERF_READ_ALL_AVAIL. The caller can then use whatever amount is
+     * appropriate.
+     *
+     * The @a data parameter will point to the data, and @a len will
+     * specify how much data is available. The lifetime of the data follows
+     * the same rules as the @see read function above.
+     *
+     * Note: if the peek does not return enough data for your particular
+     * use, then you must read/consume some first, then peek again.
+     *
+     * If the returned data represents all available data, then APR_EOF
+     * will be returned. Since this function does not consume data, it
+     * can return the same data repeatedly rather than blocking; thus,
+     * APR_EAGAIN will never be returned.
+     */
+    apr_status_t (*peek)(serf_bucket_t *bucket,
+                         const char **data, apr_size_t *len);
+
+    /**
+     * Destroy @a bucket, along with any associated resources.
+     */
+    void (*destroy)(serf_bucket_t *bucket);
+
+    /* ### apr buckets have 'copy', 'split', and 'setaside' functions.
+       ### not sure whether those will be needed in this bucket model.
+    */
+};
+
+/**
+ * Should the use and lifecycle of buckets be tracked?
+ *
+ * When tracking, the system will ensure several semantic requirements
+ * of bucket use:
+ *
+ *   - if a bucket returns APR_EAGAIN, one of its read functions should
+ *     not be called immediately. the context's run loop should be called.
+ *     ### and for APR_EOF, too?
+ *   - all buckets must be drained of input before returning to the
+ *     context's run loop.
+ *   - buckets should not be destroyed before they return APR_EOF unless
+ *     the connection is closed for some reason.
+ *
+ * Undefine this symbol to avoid the tracking (and a performance gain).
+ *
+ * ### we may want to examine when/how we provide this. should it always
+ * ### be compiled in? and apps select it before including this header?
+ */
+/* #define SERF_DEBUG_BUCKET_USE */
+
+
+/* Internal macros for tracking bucket use. */
+#ifdef SERF_DEBUG_BUCKET_USE
+#define SERF__RECREAD(b,s) serf_debug__record_read(b,s)
+#else
+#define SERF__RECREAD(b,s) (s)
+#endif
+
+#define serf_bucket_read(b,r,d,l) SERF__RECREAD(b, (b)->type->read(b,r,d,l))
+#define serf_bucket_readline(b,a,f,d,l) \
+    SERF__RECREAD(b, (b)->type->readline(b,a,f,d,l))
+#define serf_bucket_read_iovec(b,r,s,v,u) \
+    SERF__RECREAD(b, (b)->type->read_iovec(b,r,s,v,u))
+#define serf_bucket_read_for_sendfile(b,r,h,f,o,l) \
+    SERF__RECREAD(b, (b)->type->read_for_sendfile(b,r,h,f,o,l))
+#define serf_bucket_read_bucket(b,t) ((b)->type->read_bucket(b,t))
+#define serf_bucket_peek(b,d,l) ((b)->type->peek(b,d,l))
+#define serf_bucket_destroy(b) ((b)->type->destroy(b))
+
+/**
+ * Check whether a real error occurred. Note that bucket read functions
+ * can return EOF and EAGAIN as part of their "normal" operation, so they
+ * should not be considered an error.
+ */
+#define SERF_BUCKET_READ_ERROR(status) ((status) \
+                                        && !APR_STATUS_IS_EOF(status) \
+                                        && !APR_STATUS_IS_EAGAIN(status) \
+                                        && (SERF_ERROR_WAIT_CONN != status))
+
+
+struct serf_bucket_t {
+
+    /** the type of this bucket */
+    const serf_bucket_type_t *type;
+
+    /** bucket-private data */
+    void *data;
+
+    /** the allocator used for this bucket (needed at destroy time) */
+    serf_bucket_alloc_t *allocator;
+};
+
+
+/**
+ * Generic macro to construct "is TYPE" macros.
+ */
+#define SERF_BUCKET_CHECK(b, btype) ((b)->type == &serf_bucket_type_ ## btype)
+
+
+/**
+ * Notification callback for a block that was not returned to the bucket
+ * allocator when its pool was destroyed.
+ *
+ * The block of memory is given by @a block. The baton provided when the
+ * allocator was constructed is passed as @a unfreed_baton.
+ */
+typedef void (*serf_unfreed_func_t)(
+    void *unfreed_baton,
+    void *block);
+
+/**
+ * Create a new allocator for buckets.
+ *
+ * All buckets are associated with a serf bucket allocator. This allocator
+ * will be created within @a pool and will be destroyed when that pool is
+ * cleared or destroyed.
+ *
+ * When the allocator is destroyed, if any allocations were not explicitly
+ * returned (by calling serf_bucket_mem_free), then the @a unfreed callback
+ * will be invoked for each block. @a unfreed_baton will be passed to the
+ * callback.
+ *
+ * If @a unfreed is NULL, then the library will invoke the abort() stdlib
+ * call. Any failure to return memory is a bug in the application, and an
+ * abort can assist with determining what kinds of memory were not freed.
+ */
+serf_bucket_alloc_t *serf_bucket_allocator_create(
+    apr_pool_t *pool,
+    serf_unfreed_func_t unfreed,
+    void *unfreed_baton);
+
+/**
+ * Return the pool that was used for this @a allocator.
+ *
+ * WARNING: the use of this pool for allocations requires a very
+ *   detailed understanding of pool behaviors, the bucket system,
+ *   and knowledge of the bucket's use within the overall pattern
+ *   of request/response behavior.
+ *
+ * See design-guide.txt for more information about pool usage.
+ */
+apr_pool_t *serf_bucket_allocator_get_pool(
+    const serf_bucket_alloc_t *allocator);
+
+
+/**
+ * Utility structure for reading a complete line of input from a bucket.
+ *
+ * Since it is entirely possible for a line to be broken by APR_EAGAIN,
+ * this structure can be used to accumulate the data until a complete line
+ * has been read from a bucket.
+ */
+
+/* This limit applies to the line buffer functions. If an application needs
+ * longer lines, then they will need to manually handle line buffering.
+ */
+#define SERF_LINEBUF_LIMIT 8000
+
+typedef struct {
+
+    /* Current state of the buffer. */
+    enum {
+        SERF_LINEBUF_EMPTY,
+        SERF_LINEBUF_READY,
+        SERF_LINEBUF_PARTIAL,
+        SERF_LINEBUF_CRLF_SPLIT
+    } state;
+
+    /* How much of the buffer have we used? */
+    apr_size_t used;
+
+    /* The line is read into this buffer, minus CR/LF */
+    char line[SERF_LINEBUF_LIMIT];
+
+} serf_linebuf_t;
+
+/**
+ * Initialize the @a linebuf structure.
+ */
+void serf_linebuf_init(serf_linebuf_t *linebuf);
+
+/**
+ * Fetch a line of text from @a bucket, accumulating the line into
+ * @a linebuf. @a acceptable specifies the types of newlines which are
+ * acceptable for this fetch.
+ *
+ * ### we should return a data/len pair so that we can avoid a copy,
+ * ### rather than having callers look into our state and line buffer.
+ */
+apr_status_t serf_linebuf_fetch(
+    serf_linebuf_t *linebuf,
+    serf_bucket_t *bucket,
+    int acceptable);
+
+/** @} */
+
+
+/* Internal functions for bucket use and lifecycle tracking */
+apr_status_t serf_debug__record_read(
+    const serf_bucket_t *bucket,
+    apr_status_t status);
+void serf_debug__entered_loop(
+    serf_bucket_alloc_t *allocator);
+void serf_debug__closed_conn(
+    serf_bucket_alloc_t *allocator);
+void serf_debug__bucket_destroy(
+    const serf_bucket_t *bucket);
+void serf_debug__bucket_alloc_check(
+    serf_bucket_alloc_t *allocator);
+
+/* Version info */
+#define SERF_MAJOR_VERSION 1
+#define SERF_MINOR_VERSION 3
+#define SERF_PATCH_VERSION 9
+
+/* 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
+ * level.
+ * @param major The major version component of the version checked
+ * for (e.g., the "1" of "1.3.0").
+ * @param minor The minor version component of the version checked
+ * for (e.g., the "3" of "1.3.0").
+ * @param patch The patch level component of the version checked
+ * for (e.g., the "0" of "1.3.0").
+ */
+#define SERF_VERSION_AT_LEAST(major,minor,patch)                         \
+(((major) < SERF_MAJOR_VERSION)                                          \
+  || ((major) == SERF_MAJOR_VERSION && (minor) < SERF_MINOR_VERSION)     \
+   || ((major) == SERF_MAJOR_VERSION && (minor) == SERF_MINOR_VERSION && \
+            (patch) <= SERF_PATCH_VERSION))
+
+
+/**
+ * Returns the version of the library the application has linked/loaded.
+ * Values are returned in @a major, @a minor, and @a patch.
+ *
+ * Applications will want to use this function to verify compatibility,
+ * expecially while serf has not reached a 1.0 milestone. APIs and
+ * semantics may change drastically until the library hits 1.0.
+ */
+void serf_lib_version(
+    int *major,
+    int *minor,
+    int *patch);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/*
+ * Every user of serf will want to deal with our various bucket types.
+ * Go ahead and include that header right now.
+ *
+ * Note: make sure this occurs outside of the C++ namespace block
+ */
+#include "serf_bucket_types.h"
+
+
+#endif    /* !SERF_H */

Deleted: vendor/serf/1.3.9/serf_bucket_types.h
===================================================================
--- vendor/serf/dist/serf_bucket_types.h	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/serf_bucket_types.h	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,688 +0,0 @@
-/* Copyright 2002-2004 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 SERF_BUCKET_TYPES_H
-#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
-#include "serf.h"
-#endif
-
-
-/**
- * @file serf_bucket_types.h
- * @brief serf-supported bucket types
- */
-/* ### this whole file needs docco ... */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* ==================================================================== */
-
-
-extern const serf_bucket_type_t serf_bucket_type_request;
-#define SERF_BUCKET_IS_REQUEST(b) SERF_BUCKET_CHECK((b), request)
-
-serf_bucket_t *serf_bucket_request_create(
-    const char *method,
-    const char *URI,
-    serf_bucket_t *body,
-    serf_bucket_alloc_t *allocator);
-
-/* Send a Content-Length header with @a len. The @a body bucket should
-   contain precisely that much data.  */
-void serf_bucket_request_set_CL(
-    serf_bucket_t *bucket,
-    apr_int64_t len);
-
-serf_bucket_t *serf_bucket_request_get_headers(
-    serf_bucket_t *request);
-
-void serf_bucket_request_become(
-    serf_bucket_t *bucket,
-    const char *method,
-    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 '/'.
- */
-void serf_bucket_request_set_root(
-    serf_bucket_t *bucket,
-    const char *root_url);
-
-/* ==================================================================== */
-
-
-extern const serf_bucket_type_t serf_bucket_type_response;
-#define SERF_BUCKET_IS_RESPONSE(b) SERF_BUCKET_CHECK((b), response)
-
-serf_bucket_t *serf_bucket_response_create(
-    serf_bucket_t *stream,
-    serf_bucket_alloc_t *allocator);
-
-#define SERF_HTTP_VERSION(major, minor)  ((major) * 1000 + (minor))
-#define SERF_HTTP_11 SERF_HTTP_VERSION(1, 1)
-#define SERF_HTTP_10 SERF_HTTP_VERSION(1, 0)
-#define SERF_HTTP_VERSION_MAJOR(shv) ((int)shv / 1000)
-#define SERF_HTTP_VERSION_MINOR(shv) ((int)shv % 1000)
-
-typedef struct {
-    int version;
-    int code;
-    const char *reason;
-} serf_status_line;
-
-/**
- * Return the Status-Line information, if available. This function
- * works like other bucket read functions: it may return APR_EAGAIN or
- * APR_EOF to signal the state of the bucket for reading. A return
- * value of APR_SUCCESS will always indicate that status line
- * information was returned; for other return values the caller must
- * check the version field in @a sline. A value of 0 means that the
- * data is not (yet) present.
- */
-apr_status_t serf_bucket_response_status(
-    serf_bucket_t *bkt,
-    serf_status_line *sline);
-
-/**
- * Wait for the HTTP headers to be processed for a @a response.
- *
- * If the headers are available, APR_SUCCESS is returned.
- * If the headers aren't available, APR_EAGAIN is returned.
- */
-apr_status_t serf_bucket_response_wait_for_headers(
-    serf_bucket_t *response);
-
-/**
- * Get the headers bucket for @a response.
- */
-serf_bucket_t *serf_bucket_response_get_headers(
-    serf_bucket_t *response);
-
-/**
- * Advise the response @a bucket that this was from a HEAD request and
- * that it should not expect to see a response body.
- */
-void serf_bucket_response_set_head(
-    serf_bucket_t *bucket);
-
-/* ==================================================================== */
-
-extern const serf_bucket_type_t serf_bucket_type_response_body;
-#define SERF_BUCKET_IS_RESPONSE_BODY(b) SERF_BUCKET_CHECK((b), response_body)
-
-serf_bucket_t *serf_bucket_response_body_create(
-    serf_bucket_t *stream,
-    apr_uint64_t limit,
-    serf_bucket_alloc_t *allocator);
-
-/* ==================================================================== */
-
-extern const serf_bucket_type_t serf_bucket_type_bwtp_frame;
-#define SERF_BUCKET_IS_BWTP_FRAME(b) SERF_BUCKET_CHECK((b), bwtp_frame)
-
-extern const serf_bucket_type_t serf_bucket_type_bwtp_incoming_frame;
-#define SERF_BUCKET_IS_BWTP_INCOMING_FRAME(b) SERF_BUCKET_CHECK((b), bwtp_incoming_frame)
-
-int serf_bucket_bwtp_frame_get_channel(
-    serf_bucket_t *hdr);
-
-int serf_bucket_bwtp_frame_get_type(
-    serf_bucket_t *hdr);
-
-const char *serf_bucket_bwtp_frame_get_phrase(
-    serf_bucket_t *hdr);
-
-serf_bucket_t *serf_bucket_bwtp_frame_get_headers(
-    serf_bucket_t *hdr);
-
-serf_bucket_t *serf_bucket_bwtp_channel_open(
-    int channel,
-    const char *URI,
-    serf_bucket_alloc_t *allocator);
-
-serf_bucket_t *serf_bucket_bwtp_channel_close(
-    int channel,
-    serf_bucket_alloc_t *allocator);
-
-serf_bucket_t *serf_bucket_bwtp_header_create(
-    int channel,
-    const char *phrase,
-    serf_bucket_alloc_t *allocator);
-
-serf_bucket_t *serf_bucket_bwtp_message_create(
-    int channel,
-    serf_bucket_t *body,
-    serf_bucket_alloc_t *allocator);
-
-serf_bucket_t *serf_bucket_bwtp_incoming_frame_create(
-    serf_bucket_t *bkt,
-    serf_bucket_alloc_t *allocator);
-
-apr_status_t serf_bucket_bwtp_incoming_frame_wait_for_headers(
-    serf_bucket_t *bkt);
-
-/* ==================================================================== */
-
-
-extern const serf_bucket_type_t serf_bucket_type_aggregate;
-#define SERF_BUCKET_IS_AGGREGATE(b) SERF_BUCKET_CHECK((b), aggregate)
-
-typedef apr_status_t (*serf_bucket_aggregate_eof_t)(
-    void *baton,
-    serf_bucket_t *aggregate_bucket);
-
-/** serf_bucket_aggregate_cleanup will instantly destroy all buckets in
-    the aggregate bucket that have been read completely. Whereas normally, 
-    these buckets are destroyed on every read operation. */ 
-void serf_bucket_aggregate_cleanup(
-    serf_bucket_t *bucket,
-    serf_bucket_alloc_t *allocator);
-
-serf_bucket_t *serf_bucket_aggregate_create(
-    serf_bucket_alloc_t *allocator);
-
-/* Creates a stream bucket.
-   A stream bucket is like an aggregate bucket, but:
-   - it doesn't destroy its child buckets on cleanup
-   - one can always keep adding child buckets, the handler FN should return
-     APR_EOF when no more buckets will be added.
-
-  Note: keep this factory function internal for now. If it turns out this
-  bucket type is useful outside serf, we should make it an actual separate
-  type.
-  */
-serf_bucket_t *serf__bucket_stream_create(
-    serf_bucket_alloc_t *allocator,
-    serf_bucket_aggregate_eof_t fn,
-    void *baton);
-
-/** Transform @a bucket in-place into an aggregate bucket. */
-void serf_bucket_aggregate_become(
-    serf_bucket_t *bucket);
-
-void serf_bucket_aggregate_prepend(
-    serf_bucket_t *aggregate_bucket,
-    serf_bucket_t *prepend_bucket);
-
-void serf_bucket_aggregate_append(
-    serf_bucket_t *aggregate_bucket,
-    serf_bucket_t *append_bucket);
-    
-void serf_bucket_aggregate_hold_open(
-    serf_bucket_t *aggregate_bucket,
-    serf_bucket_aggregate_eof_t fn,
-    void *baton);
-
-void serf_bucket_aggregate_prepend_iovec(
-    serf_bucket_t *aggregate_bucket,
-    struct iovec *vecs,
-    int vecs_count);
-
-void serf_bucket_aggregate_append_iovec(
-    serf_bucket_t *aggregate_bucket,
-    struct iovec *vecs,
-    int vecs_count);
-
-/* ==================================================================== */
-
-
-extern const serf_bucket_type_t serf_bucket_type_file;
-#define SERF_BUCKET_IS_FILE(b) SERF_BUCKET_CHECK((b), file)
-
-serf_bucket_t *serf_bucket_file_create(
-    apr_file_t *file,
-    serf_bucket_alloc_t *allocator);
-
-
-/* ==================================================================== */
-
-
-extern const serf_bucket_type_t serf_bucket_type_socket;
-#define SERF_BUCKET_IS_SOCKET(b) SERF_BUCKET_CHECK((b), socket)
-
-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.
- */
-void serf_bucket_socket_set_read_progress_cb(
-    serf_bucket_t *bucket,
-    const serf_progress_t progress_func,
-    void *progress_baton);
-
-/* ==================================================================== */
-
-
-extern const serf_bucket_type_t serf_bucket_type_simple;
-#define SERF_BUCKET_IS_SIMPLE(b) SERF_BUCKET_CHECK((b), simple)
-
-typedef void (*serf_simple_freefunc_t)(
-    void *baton,
-    const char *data);
-
-serf_bucket_t *serf_bucket_simple_create(
-    const char *data,
-    apr_size_t len,
-    serf_simple_freefunc_t freefunc,
-    void *freefunc_baton,
-    serf_bucket_alloc_t *allocator);
-
-/**
- * Equivalent to serf_bucket_simple_create, except that the bucket takes
- * ownership of a private copy of the data.
- */
-serf_bucket_t *serf_bucket_simple_copy_create(
-    const char *data,
-    apr_size_t len,
-    serf_bucket_alloc_t *allocator);
-
-/**
- * Equivalent to serf_bucket_simple_create, except that the bucket assumes
- * responsibility for freeing the data on this allocator without making
- * a copy.  It is assumed that data was created by a call from allocator.
- */
-serf_bucket_t *serf_bucket_simple_own_create(
-    const char *data,
-    apr_size_t len,
-    serf_bucket_alloc_t *allocator);
-
-#define SERF_BUCKET_SIMPLE_STRING(s,a) \
-    serf_bucket_simple_create(s, strlen(s), NULL, NULL, a);
-
-#define SERF_BUCKET_SIMPLE_STRING_LEN(s,l,a) \
-    serf_bucket_simple_create(s, l, NULL, NULL, a);
-
-/* ==================================================================== */
-
-
-/* Note: apr_mmap_t is always defined, but if APR doesn't have mmaps, then
-   the caller can never create an apr_mmap_t to pass to this function. */
-
-extern const serf_bucket_type_t serf_bucket_type_mmap;
-#define SERF_BUCKET_IS_MMAP(b) SERF_BUCKET_CHECK((b), mmap)
-
-serf_bucket_t *serf_bucket_mmap_create(
-    apr_mmap_t *mmap,
-    serf_bucket_alloc_t *allocator);
-
-
-/* ==================================================================== */
-
-
-extern const serf_bucket_type_t serf_bucket_type_headers;
-#define SERF_BUCKET_IS_HEADERS(b) SERF_BUCKET_CHECK((b), headers)
-
-serf_bucket_t *serf_bucket_headers_create(
-    serf_bucket_alloc_t *allocator);
-
-/**
- * Set, default: value copied.
- *
- * Set the specified @a header within the bucket, copying the @a value
- * into space from this bucket's allocator. The header is NOT copied,
- * so it should remain in scope at least as long as the bucket.
- */
-void serf_bucket_headers_set(
-    serf_bucket_t *headers_bucket,
-    const char *header,
-    const char *value);
-
-/**
- * Set, copies: header and value copied.
- *
- * Copy the specified @a header and @a value into the bucket, using space
- * from this bucket's allocator.
- */
-void serf_bucket_headers_setc(
-    serf_bucket_t *headers_bucket,
-    const char *header,
-    const char *value);
-
-/**
- * Set, no copies.
- *
- * 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.
- */
-void serf_bucket_headers_setn(
-    serf_bucket_t *headers_bucket,
-    const char *header,
-    const char *value);
-
-/**
- * Set, extended: fine grained copy control of header and value.
- *
- * Set the specified @a header, with length @a header_size with the
- * @a value, and length @a value_size, into the bucket. The header will
- * 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.
- */
-void serf_bucket_headers_setx(
-    serf_bucket_t *headers_bucket,
-    const char *header,
-    apr_size_t header_size,
-    int header_copy,
-    const char *value,
-    apr_size_t value_size,
-    int value_copy);
-
-const char *serf_bucket_headers_get(
-    serf_bucket_t *headers_bucket,
-    const char *header);
-
-/**
- * @param baton opaque baton as passed to @see serf_bucket_headers_do
- * @param key The header key from this iteration through the table
- * @param value The header value from this iteration through the table
- */
-typedef int (serf_bucket_headers_do_callback_fn_t)(
-    void *baton,
-    const char *key,
-    const char *value);
-
-/**
- * Iterates over all headers of the message and invokes the callback 
- * function with header key and value. Stop iterating when no more
- * headers are available or when the callback function returned a 
- * non-0 value.
- *
- * @param headers_bucket headers to iterate over
- * @param func callback routine to invoke for every header in the bucket
- * @param baton baton to pass on each invocation to func
- */
-void serf_bucket_headers_do(
-    serf_bucket_t *headers_bucket,
-    serf_bucket_headers_do_callback_fn_t func,
-    void *baton);
-
-
-/* ==================================================================== */
-
-
-extern const serf_bucket_type_t serf_bucket_type_chunk;
-#define SERF_BUCKET_IS_CHUNK(b) SERF_BUCKET_CHECK((b), chunk)
-
-serf_bucket_t *serf_bucket_chunk_create(
-    serf_bucket_t *stream,
-    serf_bucket_alloc_t *allocator);
-
-
-/* ==================================================================== */
-
-
-extern const serf_bucket_type_t serf_bucket_type_dechunk;
-#define SERF_BUCKET_IS_DECHUNK(b) SERF_BUCKET_CHECK((b), dechunk)
-
-serf_bucket_t *serf_bucket_dechunk_create(
-    serf_bucket_t *stream,
-    serf_bucket_alloc_t *allocator);
-
-
-/* ==================================================================== */
-
-
-extern const serf_bucket_type_t serf_bucket_type_deflate;
-#define SERF_BUCKET_IS_DEFLATE(b) SERF_BUCKET_CHECK((b), deflate)
-
-#define SERF_DEFLATE_GZIP 0
-#define SERF_DEFLATE_DEFLATE 1
-
-serf_bucket_t *serf_bucket_deflate_create(
-    serf_bucket_t *stream,
-    serf_bucket_alloc_t *allocator,
-    int format);
-
-
-/* ==================================================================== */
-
-
-extern const serf_bucket_type_t serf_bucket_type_limit;
-#define SERF_BUCKET_IS_LIMIT(b) SERF_BUCKET_CHECK((b), limit)
-
-serf_bucket_t *serf_bucket_limit_create(
-    serf_bucket_t *stream,
-    apr_uint64_t limit,
-    serf_bucket_alloc_t *allocator);
-
-
-/* ==================================================================== */
-#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
-#define SERF_SSL_CERT_REVOKED          32
-
-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);
-
-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);
-
-typedef apr_status_t (*serf_ssl_server_cert_chain_cb_t)(
-    void *data,
-    int failures,
-    int error_depth,
-    const serf_ssl_certificate_t * const * certs,
-    apr_size_t certs_len);
-
-void serf_ssl_client_cert_provider_set(
-    serf_ssl_context_t *context,
-    serf_ssl_need_client_cert_t callback,
-    void *data,
-    void *cache_pool);
-
-void 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.
- */
-void serf_ssl_server_cert_callback_set(
-    serf_ssl_context_t *context,
-    serf_ssl_need_server_cert_t callback,
-    void *data);
-
-/**
- * Set callbacks to override the default SSL server certificate validation 
- * algorithm for the current certificate or the entire certificate chain. 
- */
-void serf_ssl_server_cert_chain_callback_set(
-    serf_ssl_context_t *context,
-    serf_ssl_need_server_cert_t cert_callback,
-    serf_ssl_server_cert_chain_cb_t cert_chain_callback,
-    void *data);
-
-/**
- * Use the default root CA certificates as included with the OpenSSL library.
- */
-apr_status_t serf_ssl_use_default_certificates(
-    serf_ssl_context_t *context);
-
-/**
- * Allow SNI indicators to be sent to the server.
- */
-apr_status_t serf_ssl_set_hostname(
-    serf_ssl_context_t *context, const char *hostname);
-
-/**
- * Return the depth of the certificate.
- */
-int serf_ssl_cert_depth(
-    const serf_ssl_certificate_t *cert);
-
-/**
- * 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.
- */
-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.
- */
-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, subjectAltName). The returned table will be allocated in @a pool.
- */
-apr_hash_t *serf_ssl_cert_certificate(
-    const serf_ssl_certificate_t *cert,
-    apr_pool_t *pool);
-
-/**
- * Export a certificate to base64-encoded, zero-terminated string.
- * The returned string is allocated in @a pool. Returns NULL on failure.
- */
-const char *serf_ssl_cert_export(
-    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.
- */
-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.
- */
-apr_status_t serf_ssl_trust_cert(
-    serf_ssl_context_t *ssl_ctx,
-    serf_ssl_certificate_t *cert);
-
-/**
- * Enable or disable SSL compression on a SSL session.
- * @a enabled = 1 to enable compression, 0 to disable compression.
- * Default = disabled.
- */
-apr_status_t serf_ssl_use_compression(
-    serf_ssl_context_t *ssl_ctx,
-    int enabled);
-
-serf_bucket_t *serf_bucket_ssl_encrypt_create(
-    serf_bucket_t *stream,
-    serf_ssl_context_t *ssl_context,
-    serf_bucket_alloc_t *allocator);
-
-serf_ssl_context_t *serf_bucket_ssl_encrypt_context_get(
-    serf_bucket_t *bucket);
-
-/* ==================================================================== */
-
-
-extern const serf_bucket_type_t serf_bucket_type_ssl_decrypt;
-#define SERF_BUCKET_IS_SSL_DECRYPT(b) SERF_BUCKET_CHECK((b), ssl_decrypt)
-
-serf_bucket_t *serf_bucket_ssl_decrypt_create(
-    serf_bucket_t *stream,
-    serf_ssl_context_t *ssl_context,
-    serf_bucket_alloc_t *allocator);
-
-serf_ssl_context_t *serf_bucket_ssl_decrypt_context_get(
-    serf_bucket_t *bucket);
-
-
-/* ==================================================================== */
-
-
-extern const serf_bucket_type_t serf_bucket_type_barrier;
-#define SERF_BUCKET_IS_BARRIER(b) SERF_BUCKET_CHECK((b), barrier)
-
-serf_bucket_t *serf_bucket_barrier_create(
-    serf_bucket_t *stream,
-    serf_bucket_alloc_t *allocator);
-
-
-/* ==================================================================== */
-
-extern const serf_bucket_type_t serf_bucket_type_iovec;
-#define SERF_BUCKET_IS_IOVEC(b) SERF_BUCKET_CHECK((b), iovec)
-
-serf_bucket_t *serf_bucket_iovec_create(
-    struct iovec vecs[],
-    int len,
-    serf_bucket_alloc_t *allocator);
-
-
-/* ==================================================================== */
-
-/* ### do we need a PIPE bucket type? they are simple apr_file_t objects */
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif	/* !SERF_BUCKET_TYPES_H */

Copied: vendor/serf/1.3.9/serf_bucket_types.h (from rev 9259, vendor/serf/dist/serf_bucket_types.h)
===================================================================
--- vendor/serf/1.3.9/serf_bucket_types.h	                        (rev 0)
+++ vendor/serf/1.3.9/serf_bucket_types.h	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,693 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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 SERF_BUCKET_TYPES_H
+#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
+#include "serf.h"
+#endif
+
+
+/**
+ * @file serf_bucket_types.h
+ * @brief serf-supported bucket types
+ */
+/* ### this whole file needs docco ... */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ==================================================================== */
+
+
+extern const serf_bucket_type_t serf_bucket_type_request;
+#define SERF_BUCKET_IS_REQUEST(b) SERF_BUCKET_CHECK((b), request)
+
+serf_bucket_t *serf_bucket_request_create(
+    const char *method,
+    const char *URI,
+    serf_bucket_t *body,
+    serf_bucket_alloc_t *allocator);
+
+/* Send a Content-Length header with @a len. The @a body bucket should
+   contain precisely that much data.  */
+void serf_bucket_request_set_CL(
+    serf_bucket_t *bucket,
+    apr_int64_t len);
+
+serf_bucket_t *serf_bucket_request_get_headers(
+    serf_bucket_t *request);
+
+void serf_bucket_request_become(
+    serf_bucket_t *bucket,
+    const char *method,
+    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 '/'.
+ */
+void serf_bucket_request_set_root(
+    serf_bucket_t *bucket,
+    const char *root_url);
+
+/* ==================================================================== */
+
+
+extern const serf_bucket_type_t serf_bucket_type_response;
+#define SERF_BUCKET_IS_RESPONSE(b) SERF_BUCKET_CHECK((b), response)
+
+serf_bucket_t *serf_bucket_response_create(
+    serf_bucket_t *stream,
+    serf_bucket_alloc_t *allocator);
+
+#define SERF_HTTP_VERSION(major, minor)  ((major) * 1000 + (minor))
+#define SERF_HTTP_11 SERF_HTTP_VERSION(1, 1)
+#define SERF_HTTP_10 SERF_HTTP_VERSION(1, 0)
+#define SERF_HTTP_VERSION_MAJOR(shv) ((int)shv / 1000)
+#define SERF_HTTP_VERSION_MINOR(shv) ((int)shv % 1000)
+
+typedef struct {
+    int version;
+    int code;
+    const char *reason;
+} serf_status_line;
+
+/**
+ * Return the Status-Line information, if available. This function
+ * works like other bucket read functions: it may return APR_EAGAIN or
+ * APR_EOF to signal the state of the bucket for reading. A return
+ * value of APR_SUCCESS will always indicate that status line
+ * information was returned; for other return values the caller must
+ * check the version field in @a sline. A value of 0 means that the
+ * data is not (yet) present.
+ */
+apr_status_t serf_bucket_response_status(
+    serf_bucket_t *bkt,
+    serf_status_line *sline);
+
+/**
+ * Wait for the HTTP headers to be processed for a @a response.
+ *
+ * If the headers are available, APR_SUCCESS is returned.
+ * If the headers aren't available, APR_EAGAIN is returned.
+ */
+apr_status_t serf_bucket_response_wait_for_headers(
+    serf_bucket_t *response);
+
+/**
+ * Get the headers bucket for @a response.
+ */
+serf_bucket_t *serf_bucket_response_get_headers(
+    serf_bucket_t *response);
+
+/**
+ * Advise the response @a bucket that this was from a HEAD request and
+ * that it should not expect to see a response body.
+ */
+void serf_bucket_response_set_head(
+    serf_bucket_t *bucket);
+
+/* ==================================================================== */
+
+extern const serf_bucket_type_t serf_bucket_type_response_body;
+#define SERF_BUCKET_IS_RESPONSE_BODY(b) SERF_BUCKET_CHECK((b), response_body)
+
+serf_bucket_t *serf_bucket_response_body_create(
+    serf_bucket_t *stream,
+    apr_uint64_t limit,
+    serf_bucket_alloc_t *allocator);
+
+/* ==================================================================== */
+
+extern const serf_bucket_type_t serf_bucket_type_bwtp_frame;
+#define SERF_BUCKET_IS_BWTP_FRAME(b) SERF_BUCKET_CHECK((b), bwtp_frame)
+
+extern const serf_bucket_type_t serf_bucket_type_bwtp_incoming_frame;
+#define SERF_BUCKET_IS_BWTP_INCOMING_FRAME(b) SERF_BUCKET_CHECK((b), bwtp_incoming_frame)
+
+int serf_bucket_bwtp_frame_get_channel(
+    serf_bucket_t *hdr);
+
+int serf_bucket_bwtp_frame_get_type(
+    serf_bucket_t *hdr);
+
+const char *serf_bucket_bwtp_frame_get_phrase(
+    serf_bucket_t *hdr);
+
+serf_bucket_t *serf_bucket_bwtp_frame_get_headers(
+    serf_bucket_t *hdr);
+
+serf_bucket_t *serf_bucket_bwtp_channel_open(
+    int channel,
+    const char *URI,
+    serf_bucket_alloc_t *allocator);
+
+serf_bucket_t *serf_bucket_bwtp_channel_close(
+    int channel,
+    serf_bucket_alloc_t *allocator);
+
+serf_bucket_t *serf_bucket_bwtp_header_create(
+    int channel,
+    const char *phrase,
+    serf_bucket_alloc_t *allocator);
+
+serf_bucket_t *serf_bucket_bwtp_message_create(
+    int channel,
+    serf_bucket_t *body,
+    serf_bucket_alloc_t *allocator);
+
+serf_bucket_t *serf_bucket_bwtp_incoming_frame_create(
+    serf_bucket_t *bkt,
+    serf_bucket_alloc_t *allocator);
+
+apr_status_t serf_bucket_bwtp_incoming_frame_wait_for_headers(
+    serf_bucket_t *bkt);
+
+/* ==================================================================== */
+
+
+extern const serf_bucket_type_t serf_bucket_type_aggregate;
+#define SERF_BUCKET_IS_AGGREGATE(b) SERF_BUCKET_CHECK((b), aggregate)
+
+typedef apr_status_t (*serf_bucket_aggregate_eof_t)(
+    void *baton,
+    serf_bucket_t *aggregate_bucket);
+
+/** serf_bucket_aggregate_cleanup will instantly destroy all buckets in
+    the aggregate bucket that have been read completely. Whereas normally, 
+    these buckets are destroyed on every read operation. */ 
+void serf_bucket_aggregate_cleanup(
+    serf_bucket_t *bucket,
+    serf_bucket_alloc_t *allocator);
+
+serf_bucket_t *serf_bucket_aggregate_create(
+    serf_bucket_alloc_t *allocator);
+
+/* Creates a stream bucket.
+   A stream bucket is like an aggregate bucket, but:
+   - it doesn't destroy its child buckets on cleanup
+   - one can always keep adding child buckets, the handler FN should return
+     APR_EOF when no more buckets will be added.
+
+  Note: keep this factory function internal for now. If it turns out this
+  bucket type is useful outside serf, we should make it an actual separate
+  type.
+  */
+serf_bucket_t *serf__bucket_stream_create(
+    serf_bucket_alloc_t *allocator,
+    serf_bucket_aggregate_eof_t fn,
+    void *baton);
+
+/** Transform @a bucket in-place into an aggregate bucket. */
+void serf_bucket_aggregate_become(
+    serf_bucket_t *bucket);
+
+void serf_bucket_aggregate_prepend(
+    serf_bucket_t *aggregate_bucket,
+    serf_bucket_t *prepend_bucket);
+
+void serf_bucket_aggregate_append(
+    serf_bucket_t *aggregate_bucket,
+    serf_bucket_t *append_bucket);
+    
+void serf_bucket_aggregate_hold_open(
+    serf_bucket_t *aggregate_bucket,
+    serf_bucket_aggregate_eof_t fn,
+    void *baton);
+
+void serf_bucket_aggregate_prepend_iovec(
+    serf_bucket_t *aggregate_bucket,
+    struct iovec *vecs,
+    int vecs_count);
+
+void serf_bucket_aggregate_append_iovec(
+    serf_bucket_t *aggregate_bucket,
+    struct iovec *vecs,
+    int vecs_count);
+
+/* ==================================================================== */
+
+
+extern const serf_bucket_type_t serf_bucket_type_file;
+#define SERF_BUCKET_IS_FILE(b) SERF_BUCKET_CHECK((b), file)
+
+serf_bucket_t *serf_bucket_file_create(
+    apr_file_t *file,
+    serf_bucket_alloc_t *allocator);
+
+
+/* ==================================================================== */
+
+
+extern const serf_bucket_type_t serf_bucket_type_socket;
+#define SERF_BUCKET_IS_SOCKET(b) SERF_BUCKET_CHECK((b), socket)
+
+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.
+ */
+void serf_bucket_socket_set_read_progress_cb(
+    serf_bucket_t *bucket,
+    const serf_progress_t progress_func,
+    void *progress_baton);
+
+/* ==================================================================== */
+
+
+extern const serf_bucket_type_t serf_bucket_type_simple;
+#define SERF_BUCKET_IS_SIMPLE(b) SERF_BUCKET_CHECK((b), simple)
+
+typedef void (*serf_simple_freefunc_t)(
+    void *baton,
+    const char *data);
+
+serf_bucket_t *serf_bucket_simple_create(
+    const char *data,
+    apr_size_t len,
+    serf_simple_freefunc_t freefunc,
+    void *freefunc_baton,
+    serf_bucket_alloc_t *allocator);
+
+/**
+ * Equivalent to serf_bucket_simple_create, except that the bucket takes
+ * ownership of a private copy of the data.
+ */
+serf_bucket_t *serf_bucket_simple_copy_create(
+    const char *data,
+    apr_size_t len,
+    serf_bucket_alloc_t *allocator);
+
+/**
+ * Equivalent to serf_bucket_simple_create, except that the bucket assumes
+ * responsibility for freeing the data on this allocator without making
+ * a copy.  It is assumed that data was created by a call from allocator.
+ */
+serf_bucket_t *serf_bucket_simple_own_create(
+    const char *data,
+    apr_size_t len,
+    serf_bucket_alloc_t *allocator);
+
+#define SERF_BUCKET_SIMPLE_STRING(s,a) \
+    serf_bucket_simple_create(s, strlen(s), NULL, NULL, a);
+
+#define SERF_BUCKET_SIMPLE_STRING_LEN(s,l,a) \
+    serf_bucket_simple_create(s, l, NULL, NULL, a);
+
+/* ==================================================================== */
+
+
+/* Note: apr_mmap_t is always defined, but if APR doesn't have mmaps, then
+   the caller can never create an apr_mmap_t to pass to this function. */
+
+extern const serf_bucket_type_t serf_bucket_type_mmap;
+#define SERF_BUCKET_IS_MMAP(b) SERF_BUCKET_CHECK((b), mmap)
+
+serf_bucket_t *serf_bucket_mmap_create(
+    apr_mmap_t *mmap,
+    serf_bucket_alloc_t *allocator);
+
+
+/* ==================================================================== */
+
+
+extern const serf_bucket_type_t serf_bucket_type_headers;
+#define SERF_BUCKET_IS_HEADERS(b) SERF_BUCKET_CHECK((b), headers)
+
+serf_bucket_t *serf_bucket_headers_create(
+    serf_bucket_alloc_t *allocator);
+
+/**
+ * Set, default: value copied.
+ *
+ * Set the specified @a header within the bucket, copying the @a value
+ * into space from this bucket's allocator. The header is NOT copied,
+ * so it should remain in scope at least as long as the bucket.
+ */
+void serf_bucket_headers_set(
+    serf_bucket_t *headers_bucket,
+    const char *header,
+    const char *value);
+
+/**
+ * Set, copies: header and value copied.
+ *
+ * Copy the specified @a header and @a value into the bucket, using space
+ * from this bucket's allocator.
+ */
+void serf_bucket_headers_setc(
+    serf_bucket_t *headers_bucket,
+    const char *header,
+    const char *value);
+
+/**
+ * Set, no copies.
+ *
+ * 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.
+ */
+void serf_bucket_headers_setn(
+    serf_bucket_t *headers_bucket,
+    const char *header,
+    const char *value);
+
+/**
+ * Set, extended: fine grained copy control of header and value.
+ *
+ * Set the specified @a header, with length @a header_size with the
+ * @a value, and length @a value_size, into the bucket. The header will
+ * 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.
+ */
+void serf_bucket_headers_setx(
+    serf_bucket_t *headers_bucket,
+    const char *header,
+    apr_size_t header_size,
+    int header_copy,
+    const char *value,
+    apr_size_t value_size,
+    int value_copy);
+
+const char *serf_bucket_headers_get(
+    serf_bucket_t *headers_bucket,
+    const char *header);
+
+/**
+ * @param baton opaque baton as passed to @see serf_bucket_headers_do
+ * @param key The header key from this iteration through the table
+ * @param value The header value from this iteration through the table
+ */
+typedef int (serf_bucket_headers_do_callback_fn_t)(
+    void *baton,
+    const char *key,
+    const char *value);
+
+/**
+ * Iterates over all headers of the message and invokes the callback 
+ * function with header key and value. Stop iterating when no more
+ * headers are available or when the callback function returned a 
+ * non-0 value.
+ *
+ * @param headers_bucket headers to iterate over
+ * @param func callback routine to invoke for every header in the bucket
+ * @param baton baton to pass on each invocation to func
+ */
+void serf_bucket_headers_do(
+    serf_bucket_t *headers_bucket,
+    serf_bucket_headers_do_callback_fn_t func,
+    void *baton);
+
+
+/* ==================================================================== */
+
+
+extern const serf_bucket_type_t serf_bucket_type_chunk;
+#define SERF_BUCKET_IS_CHUNK(b) SERF_BUCKET_CHECK((b), chunk)
+
+serf_bucket_t *serf_bucket_chunk_create(
+    serf_bucket_t *stream,
+    serf_bucket_alloc_t *allocator);
+
+
+/* ==================================================================== */
+
+
+extern const serf_bucket_type_t serf_bucket_type_dechunk;
+#define SERF_BUCKET_IS_DECHUNK(b) SERF_BUCKET_CHECK((b), dechunk)
+
+serf_bucket_t *serf_bucket_dechunk_create(
+    serf_bucket_t *stream,
+    serf_bucket_alloc_t *allocator);
+
+
+/* ==================================================================== */
+
+
+extern const serf_bucket_type_t serf_bucket_type_deflate;
+#define SERF_BUCKET_IS_DEFLATE(b) SERF_BUCKET_CHECK((b), deflate)
+
+#define SERF_DEFLATE_GZIP 0
+#define SERF_DEFLATE_DEFLATE 1
+
+serf_bucket_t *serf_bucket_deflate_create(
+    serf_bucket_t *stream,
+    serf_bucket_alloc_t *allocator,
+    int format);
+
+
+/* ==================================================================== */
+
+
+extern const serf_bucket_type_t serf_bucket_type_limit;
+#define SERF_BUCKET_IS_LIMIT(b) SERF_BUCKET_CHECK((b), limit)
+
+serf_bucket_t *serf_bucket_limit_create(
+    serf_bucket_t *stream,
+    apr_uint64_t limit,
+    serf_bucket_alloc_t *allocator);
+
+
+/* ==================================================================== */
+#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
+#define SERF_SSL_CERT_REVOKED          32
+
+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);
+
+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);
+
+typedef apr_status_t (*serf_ssl_server_cert_chain_cb_t)(
+    void *data,
+    int failures,
+    int error_depth,
+    const serf_ssl_certificate_t * const * certs,
+    apr_size_t certs_len);
+
+void serf_ssl_client_cert_provider_set(
+    serf_ssl_context_t *context,
+    serf_ssl_need_client_cert_t callback,
+    void *data,
+    void *cache_pool);
+
+void 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.
+ */
+void serf_ssl_server_cert_callback_set(
+    serf_ssl_context_t *context,
+    serf_ssl_need_server_cert_t callback,
+    void *data);
+
+/**
+ * Set callbacks to override the default SSL server certificate validation 
+ * algorithm for the current certificate or the entire certificate chain. 
+ */
+void serf_ssl_server_cert_chain_callback_set(
+    serf_ssl_context_t *context,
+    serf_ssl_need_server_cert_t cert_callback,
+    serf_ssl_server_cert_chain_cb_t cert_chain_callback,
+    void *data);
+
+/**
+ * Use the default root CA certificates as included with the OpenSSL library.
+ */
+apr_status_t serf_ssl_use_default_certificates(
+    serf_ssl_context_t *context);
+
+/**
+ * Allow SNI indicators to be sent to the server.
+ */
+apr_status_t serf_ssl_set_hostname(
+    serf_ssl_context_t *context, const char *hostname);
+
+/**
+ * Return the depth of the certificate.
+ */
+int serf_ssl_cert_depth(
+    const serf_ssl_certificate_t *cert);
+
+/**
+ * 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.
+ */
+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.
+ */
+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, subjectAltName). The returned table will be allocated in @a pool.
+ */
+apr_hash_t *serf_ssl_cert_certificate(
+    const serf_ssl_certificate_t *cert,
+    apr_pool_t *pool);
+
+/**
+ * Export a certificate to base64-encoded, zero-terminated string.
+ * The returned string is allocated in @a pool. Returns NULL on failure.
+ */
+const char *serf_ssl_cert_export(
+    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.
+ */
+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.
+ */
+apr_status_t serf_ssl_trust_cert(
+    serf_ssl_context_t *ssl_ctx,
+    serf_ssl_certificate_t *cert);
+
+/**
+ * Enable or disable SSL compression on a SSL session.
+ * @a enabled = 1 to enable compression, 0 to disable compression.
+ * Default = disabled.
+ */
+apr_status_t serf_ssl_use_compression(
+    serf_ssl_context_t *ssl_ctx,
+    int enabled);
+
+serf_bucket_t *serf_bucket_ssl_encrypt_create(
+    serf_bucket_t *stream,
+    serf_ssl_context_t *ssl_context,
+    serf_bucket_alloc_t *allocator);
+
+serf_ssl_context_t *serf_bucket_ssl_encrypt_context_get(
+    serf_bucket_t *bucket);
+
+/* ==================================================================== */
+
+
+extern const serf_bucket_type_t serf_bucket_type_ssl_decrypt;
+#define SERF_BUCKET_IS_SSL_DECRYPT(b) SERF_BUCKET_CHECK((b), ssl_decrypt)
+
+serf_bucket_t *serf_bucket_ssl_decrypt_create(
+    serf_bucket_t *stream,
+    serf_ssl_context_t *ssl_context,
+    serf_bucket_alloc_t *allocator);
+
+serf_ssl_context_t *serf_bucket_ssl_decrypt_context_get(
+    serf_bucket_t *bucket);
+
+
+/* ==================================================================== */
+
+
+extern const serf_bucket_type_t serf_bucket_type_barrier;
+#define SERF_BUCKET_IS_BARRIER(b) SERF_BUCKET_CHECK((b), barrier)
+
+serf_bucket_t *serf_bucket_barrier_create(
+    serf_bucket_t *stream,
+    serf_bucket_alloc_t *allocator);
+
+
+/* ==================================================================== */
+
+extern const serf_bucket_type_t serf_bucket_type_iovec;
+#define SERF_BUCKET_IS_IOVEC(b) SERF_BUCKET_CHECK((b), iovec)
+
+serf_bucket_t *serf_bucket_iovec_create(
+    struct iovec vecs[],
+    int len,
+    serf_bucket_alloc_t *allocator);
+
+
+/* ==================================================================== */
+
+/* ### do we need a PIPE bucket type? they are simple apr_file_t objects */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* !SERF_BUCKET_TYPES_H */

Deleted: vendor/serf/1.3.9/serf_bucket_util.h
===================================================================
--- vendor/serf/dist/serf_bucket_util.h	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/serf_bucket_util.h	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,294 +0,0 @@
-/* Copyright 2002-2004 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 SERF_BUCKET_UTIL_H
-#define SERF_BUCKET_UTIL_H
-
-/**
- * @file serf_bucket_util.h
- * @brief This header defines a set of functions and other utilities
- * for implementing buckets. It is not needed by users of the bucket
- * system.
- */
-
-#include "serf.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/**
- * Basic bucket creation function.
- *
- * This function will create a bucket of @a type, allocating the necessary
- * memory from @a allocator. The @a data bucket-private information will
- * be stored into the bucket.
- */
-serf_bucket_t *serf_bucket_create(
-    const serf_bucket_type_t *type,
-    serf_bucket_alloc_t *allocator,
-    void *data);
-
-/**
- * Default implementation of the @see read_iovec functionality.
- *
- * This function will use the @see read function to get a block of memory,
- * then return it in the iovec.
- */
-apr_status_t serf_default_read_iovec(
-    serf_bucket_t *bucket,
-    apr_size_t requested,
-    int vecs_size,
-    struct iovec *vecs,
-    int *vecs_used);
-
-/**
- * Default implementation of the @see read_for_sendfile functionality.
- *
- * This function will use the @see read function to get a block of memory,
- * then return it as a header. No file will be returned.
- */
-apr_status_t serf_default_read_for_sendfile(
-    serf_bucket_t *bucket,
-    apr_size_t requested,
-    apr_hdtr_t *hdtr,
-    apr_file_t **file,
-    apr_off_t *offset,
-    apr_size_t *len);
-
-/**
- * Default implementation of the @see read_bucket functionality.
- *
- * This function will always return NULL, indicating that the @a type
- * of bucket cannot be found within @a bucket.
- */
-serf_bucket_t *serf_default_read_bucket(
-    serf_bucket_t *bucket,
-    const serf_bucket_type_t *type);
-
-/**
- * Default implementation of the @see destroy functionality.
- *
- * This function will return the @a bucket to its allcoator.
- */
-void serf_default_destroy(
-    serf_bucket_t *bucket);
-
-
-/**
- * Default implementation of the @see destroy functionality.
- *
- * This function will return the @a bucket, and the data member to its
- * allocator.
- */
-void serf_default_destroy_and_data(
-    serf_bucket_t *bucket);
-
-
-/**
- * Allocate @a size bytes of memory using @a allocator.
- *
- * Returns NULL of the requested memory size could not be allocated.
- */
-void *serf_bucket_mem_alloc(
-    serf_bucket_alloc_t *allocator,
-    apr_size_t size);
-
-/**
- * Allocate @a size bytes of memory using @a allocator and set all of the
- * memory to 0.
- *
- * Returns NULL of the requested memory size could not be allocated.
- */
-void *serf_bucket_mem_calloc(
-    serf_bucket_alloc_t *allocator,
-    apr_size_t size);
-
-/**
- * Free the memory at @a block, returning it to @a allocator.
- */
-void serf_bucket_mem_free(
-    serf_bucket_alloc_t *allocator,
-    void *block);
-
-
-/**
- * Analogous to apr_pstrmemdup, using a bucket allocator instead.
- */
-char *serf_bstrmemdup(
-    serf_bucket_alloc_t *allocator,
-    const char *str,
-    apr_size_t size);
-
-/**
- * Analogous to apr_pmemdup, using a bucket allocator instead.
- */
-void * serf_bmemdup(
-    serf_bucket_alloc_t *allocator,
-    const void *mem,
-    apr_size_t size);
-
-/**
- * Analogous to apr_pstrdup, using a bucket allocator instead.
- */
-char * serf_bstrdup(
-    serf_bucket_alloc_t *allocator,
-    const char *str);
-
-/**
- * Analogous to apr_pstrcatv, using a bucket allocator instead.
- */
-char * serf_bstrcatv(
-    serf_bucket_alloc_t *allocator,
-    struct iovec *vec,
-    int vecs,
-    apr_size_t *bytes_written);
-
-/**
- * Read data up to a newline.
- *
- * @a acceptable contains the allowed forms of a newline, and @a found
- * will return the particular newline type that was found. If a newline
- * is not found, then SERF_NEWLINE_NONE will be placed in @a found.
- *
- * @a data should contain a pointer to the data to be scanned. @a len
- * should specify the length of that data buffer. On exit, @a data will
- * be advanced past the newline, and @a len will specify the remaining
- * amount of data in the buffer.
- *
- * Given this pattern of behavior, the caller should store the initial
- * value of @a data as the line start. The difference between the
- * returned value of @a data and the saved start is the length of the
- * line.
- *
- * Note that the newline character(s) will remain within the buffer.
- * This function scans at a byte level for the newline characters. Thus,
- * the data buffer may contain NUL characters. As a corollary, this
- * function only works on 8-bit character encodings.
- *
- * If the data is fully consumed (@a len gets set to zero) and a CR
- * character is found at the end and the CRLF sequence is allowed, then
- * this function may store SERF_NEWLINE_CRLF_SPLIT into @a found. The
- * caller should take particular consideration for the CRLF sequence
- * that may be split across data buffer boundaries.
- */
-void serf_util_readline(
-    const char **data,
-    apr_size_t *len,
-    int acceptable,
-    int *found);
-
-
-/** The buffer size used within @see serf_databuf_t. */
-#define SERF_DATABUF_BUFSIZE 8000
-
-/** Callback function which is used to refill the data buffer.
- *
- * The function takes @a baton, which is the @see read_baton value
- * from the serf_databuf_t structure. Data should be placed into
- * a buffer specified by @a buf, which is @a bufsize bytes long.
- * The amount of data read should be returned in @a len.
- *
- * APR_EOF should be returned if no more data is available. APR_EAGAIN
- * should be returned, rather than blocking. In both cases, @a buf
- * should be filled in and @a len set, as appropriate.
- */
-typedef apr_status_t (*serf_databuf_reader_t)(
-    void *baton,
-    apr_size_t bufsize,
-    char *buf,
-    apr_size_t *len);
-
-/**
- * This structure is used as an intermediate data buffer for some "external"
- * source of data. It works as a scratch pad area for incoming data to be
- * stored, and then returned as a ptr/len pair by the bucket read functions.
- *
- * This structure should be initialized by calling @see serf_databuf_init.
- * Users should not bother to zero the structure beforehand.
- */
-typedef struct {
-    /** The current data position within the buffer. */
-    const char *current;
-
-    /** Amount of data remaining in the buffer. */
-    apr_size_t remaining;
-
-    /** Callback function. */
-    serf_databuf_reader_t read;
-
-    /** A baton to hold context-specific data. */
-    void *read_baton;
-
-    /** Records the status from the last @see read operation. */
-    apr_status_t status;
-
-    /** Holds the data until it can be returned. */
-    char buf[SERF_DATABUF_BUFSIZE];
-
-} serf_databuf_t;
-
-/**
- * Initialize the @see serf_databuf_t structure specified by @a databuf.
- */
-void serf_databuf_init(
-    serf_databuf_t *databuf);
-
-/**
- * Implement a bucket-style read function from the @see serf_databuf_t
- * structure given by @a databuf.
- *
- * The @a requested, @a data, and @a len fields are interpreted and used
- * as in the read function of @see serf_bucket_t.
- */
-apr_status_t serf_databuf_read(
-    serf_databuf_t *databuf,
-    apr_size_t requested,
-    const char **data,
-    apr_size_t *len);
-
-/**
- * Implement a bucket-style readline function from the @see serf_databuf_t
- * structure given by @a databuf.
- *
- * The @a acceptable, @a found, @a data, and @a len fields are interpreted
- * and used as in the read function of @see serf_bucket_t.
- */
-apr_status_t serf_databuf_readline(
-    serf_databuf_t *databuf,
-    int acceptable,
-    int *found,
-    const char **data,
-    apr_size_t *len);
-
-/**
- * Implement a bucket-style peek function from the @see serf_databuf_t
- * structure given by @a databuf.
- *
- * The @a data, and @a len fields are interpreted and used as in the
- * peek function of @see serf_bucket_t.
- */
-apr_status_t serf_databuf_peek(
-    serf_databuf_t *databuf,
-    const char **data,
-    apr_size_t *len);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif	/* !SERF_BUCKET_UTIL_H */

Copied: vendor/serf/1.3.9/serf_bucket_util.h (from rev 9259, vendor/serf/dist/serf_bucket_util.h)
===================================================================
--- vendor/serf/1.3.9/serf_bucket_util.h	                        (rev 0)
+++ vendor/serf/1.3.9/serf_bucket_util.h	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,299 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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 SERF_BUCKET_UTIL_H
+#define SERF_BUCKET_UTIL_H
+
+/**
+ * @file serf_bucket_util.h
+ * @brief This header defines a set of functions and other utilities
+ * for implementing buckets. It is not needed by users of the bucket
+ * system.
+ */
+
+#include "serf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * Basic bucket creation function.
+ *
+ * This function will create a bucket of @a type, allocating the necessary
+ * memory from @a allocator. The @a data bucket-private information will
+ * be stored into the bucket.
+ */
+serf_bucket_t *serf_bucket_create(
+    const serf_bucket_type_t *type,
+    serf_bucket_alloc_t *allocator,
+    void *data);
+
+/**
+ * Default implementation of the @see read_iovec functionality.
+ *
+ * This function will use the @see read function to get a block of memory,
+ * then return it in the iovec.
+ */
+apr_status_t serf_default_read_iovec(
+    serf_bucket_t *bucket,
+    apr_size_t requested,
+    int vecs_size,
+    struct iovec *vecs,
+    int *vecs_used);
+
+/**
+ * Default implementation of the @see read_for_sendfile functionality.
+ *
+ * This function will use the @see read function to get a block of memory,
+ * then return it as a header. No file will be returned.
+ */
+apr_status_t serf_default_read_for_sendfile(
+    serf_bucket_t *bucket,
+    apr_size_t requested,
+    apr_hdtr_t *hdtr,
+    apr_file_t **file,
+    apr_off_t *offset,
+    apr_size_t *len);
+
+/**
+ * Default implementation of the @see read_bucket functionality.
+ *
+ * This function will always return NULL, indicating that the @a type
+ * of bucket cannot be found within @a bucket.
+ */
+serf_bucket_t *serf_default_read_bucket(
+    serf_bucket_t *bucket,
+    const serf_bucket_type_t *type);
+
+/**
+ * Default implementation of the @see destroy functionality.
+ *
+ * This function will return the @a bucket to its allcoator.
+ */
+void serf_default_destroy(
+    serf_bucket_t *bucket);
+
+
+/**
+ * Default implementation of the @see destroy functionality.
+ *
+ * This function will return the @a bucket, and the data member to its
+ * allocator.
+ */
+void serf_default_destroy_and_data(
+    serf_bucket_t *bucket);
+
+
+/**
+ * Allocate @a size bytes of memory using @a allocator.
+ *
+ * Returns NULL of the requested memory size could not be allocated.
+ */
+void *serf_bucket_mem_alloc(
+    serf_bucket_alloc_t *allocator,
+    apr_size_t size);
+
+/**
+ * Allocate @a size bytes of memory using @a allocator and set all of the
+ * memory to 0.
+ *
+ * Returns NULL of the requested memory size could not be allocated.
+ */
+void *serf_bucket_mem_calloc(
+    serf_bucket_alloc_t *allocator,
+    apr_size_t size);
+
+/**
+ * Free the memory at @a block, returning it to @a allocator.
+ */
+void serf_bucket_mem_free(
+    serf_bucket_alloc_t *allocator,
+    void *block);
+
+
+/**
+ * Analogous to apr_pstrmemdup, using a bucket allocator instead.
+ */
+char *serf_bstrmemdup(
+    serf_bucket_alloc_t *allocator,
+    const char *str,
+    apr_size_t size);
+
+/**
+ * Analogous to apr_pmemdup, using a bucket allocator instead.
+ */
+void * serf_bmemdup(
+    serf_bucket_alloc_t *allocator,
+    const void *mem,
+    apr_size_t size);
+
+/**
+ * Analogous to apr_pstrdup, using a bucket allocator instead.
+ */
+char * serf_bstrdup(
+    serf_bucket_alloc_t *allocator,
+    const char *str);
+
+/**
+ * Analogous to apr_pstrcatv, using a bucket allocator instead.
+ */
+char * serf_bstrcatv(
+    serf_bucket_alloc_t *allocator,
+    struct iovec *vec,
+    int vecs,
+    apr_size_t *bytes_written);
+
+/**
+ * Read data up to a newline.
+ *
+ * @a acceptable contains the allowed forms of a newline, and @a found
+ * will return the particular newline type that was found. If a newline
+ * is not found, then SERF_NEWLINE_NONE will be placed in @a found.
+ *
+ * @a data should contain a pointer to the data to be scanned. @a len
+ * should specify the length of that data buffer. On exit, @a data will
+ * be advanced past the newline, and @a len will specify the remaining
+ * amount of data in the buffer.
+ *
+ * Given this pattern of behavior, the caller should store the initial
+ * value of @a data as the line start. The difference between the
+ * returned value of @a data and the saved start is the length of the
+ * line.
+ *
+ * Note that the newline character(s) will remain within the buffer.
+ * This function scans at a byte level for the newline characters. Thus,
+ * the data buffer may contain NUL characters. As a corollary, this
+ * function only works on 8-bit character encodings.
+ *
+ * If the data is fully consumed (@a len gets set to zero) and a CR
+ * character is found at the end and the CRLF sequence is allowed, then
+ * this function may store SERF_NEWLINE_CRLF_SPLIT into @a found. The
+ * caller should take particular consideration for the CRLF sequence
+ * that may be split across data buffer boundaries.
+ */
+void serf_util_readline(
+    const char **data,
+    apr_size_t *len,
+    int acceptable,
+    int *found);
+
+
+/** The buffer size used within @see serf_databuf_t. */
+#define SERF_DATABUF_BUFSIZE 8000
+
+/** Callback function which is used to refill the data buffer.
+ *
+ * The function takes @a baton, which is the @see read_baton value
+ * from the serf_databuf_t structure. Data should be placed into
+ * a buffer specified by @a buf, which is @a bufsize bytes long.
+ * The amount of data read should be returned in @a len.
+ *
+ * APR_EOF should be returned if no more data is available. APR_EAGAIN
+ * should be returned, rather than blocking. In both cases, @a buf
+ * should be filled in and @a len set, as appropriate.
+ */
+typedef apr_status_t (*serf_databuf_reader_t)(
+    void *baton,
+    apr_size_t bufsize,
+    char *buf,
+    apr_size_t *len);
+
+/**
+ * This structure is used as an intermediate data buffer for some "external"
+ * source of data. It works as a scratch pad area for incoming data to be
+ * stored, and then returned as a ptr/len pair by the bucket read functions.
+ *
+ * This structure should be initialized by calling @see serf_databuf_init.
+ * Users should not bother to zero the structure beforehand.
+ */
+typedef struct {
+    /** The current data position within the buffer. */
+    const char *current;
+
+    /** Amount of data remaining in the buffer. */
+    apr_size_t remaining;
+
+    /** Callback function. */
+    serf_databuf_reader_t read;
+
+    /** A baton to hold context-specific data. */
+    void *read_baton;
+
+    /** Records the status from the last @see read operation. */
+    apr_status_t status;
+
+    /** Holds the data until it can be returned. */
+    char buf[SERF_DATABUF_BUFSIZE];
+
+} serf_databuf_t;
+
+/**
+ * Initialize the @see serf_databuf_t structure specified by @a databuf.
+ */
+void serf_databuf_init(
+    serf_databuf_t *databuf);
+
+/**
+ * Implement a bucket-style read function from the @see serf_databuf_t
+ * structure given by @a databuf.
+ *
+ * The @a requested, @a data, and @a len fields are interpreted and used
+ * as in the read function of @see serf_bucket_t.
+ */
+apr_status_t serf_databuf_read(
+    serf_databuf_t *databuf,
+    apr_size_t requested,
+    const char **data,
+    apr_size_t *len);
+
+/**
+ * Implement a bucket-style readline function from the @see serf_databuf_t
+ * structure given by @a databuf.
+ *
+ * The @a acceptable, @a found, @a data, and @a len fields are interpreted
+ * and used as in the read function of @see serf_bucket_t.
+ */
+apr_status_t serf_databuf_readline(
+    serf_databuf_t *databuf,
+    int acceptable,
+    int *found,
+    const char **data,
+    apr_size_t *len);
+
+/**
+ * Implement a bucket-style peek function from the @see serf_databuf_t
+ * structure given by @a databuf.
+ *
+ * The @a data, and @a len fields are interpreted and used as in the
+ * peek function of @see serf_bucket_t.
+ */
+apr_status_t serf_databuf_peek(
+    serf_databuf_t *databuf,
+    const char **data,
+    apr_size_t *len);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* !SERF_BUCKET_UTIL_H */

Deleted: vendor/serf/1.3.9/serf_private.h
===================================================================
--- vendor/serf/dist/serf_private.h	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/serf_private.h	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,465 +0,0 @@
-/* Copyright 2002-2004 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 _SERF_PRIVATE_H_
-#define _SERF_PRIVATE_H_
-
-/* ### what the hell? why does the APR interface have a "size" ??
-   ### the implication is that, if we bust this limit, we'd need to
-   ### stop, rebuild a pollset, and repopulate it. what suckage.  */
-#define MAX_CONN 16
-
-/* Windows does not define IOV_MAX, so we need to ensure it is defined. */
-#ifndef IOV_MAX
-/* There is no limit for iovec count on Windows, but apr_socket_sendv
-   allocates WSABUF structures on stack if vecs_count <= 50. */
-#define IOV_MAX 50
-#endif
-
-/* Older versions of APR do not have this macro.  */
-#ifdef APR_SIZE_MAX
-#define REQUESTED_MAX APR_SIZE_MAX
-#else
-#define REQUESTED_MAX (~((apr_size_t)0))
-#endif
-
-#define SERF_IO_CLIENT (1)
-#define SERF_IO_CONN (2)
-#define SERF_IO_LISTENER (3)
-
-/* Internal logging facilities, set flag to 1 to enable console logging for
-   the selected component. */
-#define SSL_VERBOSE 0
-#define SSL_MSG_VERBOSE 0  /* logs decrypted requests and responses. */
-#define SOCK_VERBOSE 0
-#define SOCK_MSG_VERBOSE 0 /* logs bytes received from or written to a socket. */
-#define CONN_VERBOSE 0
-#define AUTH_VERBOSE 0
-
-/* Older versions of APR do not have the APR_VERSION_AT_LEAST macro. Those
-   implementations are safe.
-
-   If the macro *is* defined, and we're on WIN32, and APR is version 1.4.0+,
-   then we have a broken WSAPoll() implementation.
-
-   See serf_context_create_ex() below.  */
-#if defined(APR_VERSION_AT_LEAST) && defined(WIN32)
-#if APR_VERSION_AT_LEAST(1,4,0)
-#define BROKEN_WSAPOLL
-#endif
-#endif
-
-typedef struct serf__authn_scheme_t serf__authn_scheme_t;
-
-typedef struct serf_io_baton_t {
-    int type;
-    union {
-        serf_incoming_t *client;
-        serf_connection_t *conn;
-        serf_listener_t *listener;
-    } u;
-} serf_io_baton_t;
-
-/* Holds all the information corresponding to a request/response pair. */
-struct serf_request_t {
-    serf_connection_t *conn;
-
-    apr_pool_t *respool;
-    serf_bucket_alloc_t *allocator;
-
-    /* The bucket corresponding to the request. Will be NULL once the
-     * bucket has been emptied (for delivery into the socket).
-     */
-    serf_bucket_t *req_bkt;
-
-    serf_request_setup_t setup;
-    void *setup_baton;
-
-    serf_response_acceptor_t acceptor;
-    void *acceptor_baton;
-
-    serf_response_handler_t handler;
-    void *handler_baton;
-
-    serf_bucket_t *resp_bkt;
-
-    int writing_started;
-    int priority;
-    /* 1 if this is a request to setup a SSL tunnel, 0 for normal requests. */
-    int ssltunnel;
-
-    /* This baton is currently only used for digest authentication, which
-       needs access to the uri of the request in the response handler.
-       If serf_request_t is replaced by a serf_http_request_t in the future,
-       which knows about uri and method and such, this baton won't be needed
-       anymore. */
-    void *auth_baton;
-
-    struct serf_request_t *next;
-};
-
-typedef struct serf_pollset_t {
-    /* the set of connections to poll */
-    apr_pollset_t *pollset;
-} serf_pollset_t;
-
-typedef struct serf__authn_info_t {
-    const serf__authn_scheme_t *scheme;
-
-    void *baton;
-
-    int failed_authn_types;
-} serf__authn_info_t;
-
-struct serf_context_t {
-    /* the pool used for self and for other allocations */
-    apr_pool_t *pool;
-
-    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;
-
-    /* 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;
-
-    /* authentication info for the servers used in this context. Shared by all
-       connections to the same server.
-       Structure of the hashtable:  key: host url, e.g. https://localhost:80
-                                  value: serf__authn_info_t *
-     */
-    apr_hash_t *server_authn_info;
-
-    /* authentication info for the proxy configured in this context, shared by
-       all connections. */
-    serf__authn_info_t proxy_authn_info;
-
-    /* List of authn types supported by the client.*/
-    int authn_types;
-    /* Callback function used to get credentials for a realm. */
-    serf_credentials_callback_t cred_cb; 
-};
-
-struct serf_listener_t {
-    serf_context_t *ctx;
-    serf_io_baton_t baton;
-    apr_socket_t *skt;
-    apr_pool_t *pool;
-    apr_pollfd_t desc;
-    void *accept_baton;
-    serf_accept_client_t accept_func;
-};
-
-struct serf_incoming_t {
-    serf_context_t *ctx;
-    serf_io_baton_t baton;
-    void *request_baton;
-    serf_incoming_request_cb_t request;
-    apr_socket_t *skt;
-    apr_pollfd_t desc;
-};
-
-/* States for the different stages in the lifecyle of a connection. */
-typedef enum {
-    SERF_CONN_INIT,             /* no socket created yet */
-    SERF_CONN_SETUP_SSLTUNNEL,  /* ssl tunnel being setup, no requests sent */
-    SERF_CONN_CONNECTED,        /* conn is ready to send requests */
-    SERF_CONN_CLOSING           /* conn is closing, no more requests,
-                                   start a new socket */
-} serf__connection_state_t;
-
-struct serf_connection_t {
-    serf_context_t *ctx;
-
-    apr_status_t status;
-    serf_io_baton_t baton;
-
-    apr_pool_t *pool;
-    serf_bucket_alloc_t *allocator;
-
-    apr_sockaddr_t *address;
-
-    apr_socket_t *skt;
-    apr_pool_t *skt_pool;
-
-    /* the last reqevents we gave to pollset_add */
-    apr_int16_t reqevents;
-
-    /* the events we've seen for this connection in our returned pollset */
-    apr_int16_t seen_in_pollset;
-
-    /* are we a dirty connection that needs its poll status updated? */
-    int dirty_conn;
-
-    /* number of completed requests we've sent */
-    unsigned int completed_requests;
-
-    /* number of completed responses we've got */
-    unsigned int completed_responses;
-
-    /* keepalive */
-    unsigned int probable_keepalive_limit;
-
-    /* Current state of the connection (whether or not it is connected). */
-    serf__connection_state_t state;
-
-    /* This connection may have responses without a request! */
-    int async_responses;
-    serf_bucket_t *current_async_response;
-    serf_response_acceptor_t async_acceptor;
-    void *async_acceptor_baton;
-    serf_response_handler_t async_handler;
-    void *async_handler_baton;
-
-    /* A bucket wrapped around our socket (for reading responses). */
-    serf_bucket_t *stream;
-    /* A reference to the aggregate bucket that provides the boundary between
-     * request level buckets and connection level buckets.
-     */
-    serf_bucket_t *ostream_head;
-    serf_bucket_t *ostream_tail;
-
-    /* Aggregate bucket used to send the CONNECT request. */
-    serf_bucket_t *ssltunnel_ostream;
-
-    /* The list of active requests. */
-    serf_request_t *requests;
-    serf_request_t *requests_tail;
-
-    struct iovec vec[IOV_MAX];
-    int vec_len;
-
-    serf_connection_setup_t setup;
-    void *setup_baton;
-    serf_connection_closed_t closed;
-    void *closed_baton;
-
-    /* Max. number of outstanding requests. */
-    unsigned int max_outstanding_requests;
-
-    int hit_eof;
-
-    /* Host url, path ommitted, syntax: https://svn.apache.org . */
-    const char *host_url;
-    
-    /* Exploded host url, path ommitted. Only scheme, hostinfo, hostname &
-       port values are filled in. */
-    apr_uri_t host_info;
-
-    /* authentication info for this connection. */
-    serf__authn_info_t authn_info;
-
-    /* Time marker when connection begins. */
-    apr_time_t connect_time;
-
-    /* Calculated connection latency. Negative value if latency is unknown. */
-    apr_interval_time_t latency;
-
-    /* Needs to read first before we can write again. */
-    int stop_writing;
-};
-
-/*** Internal bucket functions ***/
-
-/** Transform a response_bucket in-place into an aggregate bucket. Restore the
-    status line and all headers, not just the body.
- 
-    This can only be used when we haven't started reading the body of the
-    response yet.
- 
-    Keep internal for now, probably only useful within serf.
- */
-apr_status_t serf_response_full_become_aggregate(serf_bucket_t *bucket);
-
-/**
- * Remove the header from the list, do nothing if the header wasn't added.
- */
-void serf__bucket_headers_remove(serf_bucket_t *headers_bucket,
-                                 const char *header);
-
-/*** Authentication handler declarations ***/
-
-typedef enum { PROXY, HOST } peer_t;
-
-/**
- * For each authentication scheme we need a handler function of type
- * serf__auth_handler_func_t. This function will be called when an
- * authentication challenge is received in a session.
- */
-typedef apr_status_t
-(*serf__auth_handler_func_t)(int code,
-                             serf_request_t *request,
-                             serf_bucket_t *response,
-                             const char *auth_hdr,
-                             const char *auth_attr,
-                             void *baton,
-                             apr_pool_t *pool);
-
-/**
- * For each authentication scheme we need an initialization function of type
- * serf__init_context_func_t. This function will be called the first time
- * serf tries a specific authentication scheme handler.
- */
-typedef apr_status_t
-(*serf__init_context_func_t)(int code,
-                             serf_context_t *conn,
-                             apr_pool_t *pool);
-
-/**
- * For each authentication scheme we need an initialization function of type
- * serf__init_conn_func_t. This function will be called when a new
- * connection is opened.
- */
-typedef apr_status_t
-(*serf__init_conn_func_t)(const serf__authn_scheme_t *scheme,
-                          int code,
-                          serf_connection_t *conn,
-                          apr_pool_t *pool);
-
-/**
- * For each authentication scheme we need a setup_request function of type
- * serf__setup_request_func_t. This function will be called when a
- * new serf_request_t object is created and should fill in the correct
- * authentication headers (if needed).
- */
-typedef apr_status_t
-(*serf__setup_request_func_t)(peer_t peer,
-                              int code,
-                              serf_connection_t *conn,
-                              serf_request_t *request,
-                              const char *method,
-                              const char *uri,
-                              serf_bucket_t *hdrs_bkt);
-
-/**
- * This function will be called when a response is received, so that the 
- * scheme handler can validate the Authentication related response headers
- * (if needed).
- */
-typedef apr_status_t
-(*serf__validate_response_func_t)(const serf__authn_scheme_t *scheme,
-                                  peer_t peer,
-                                  int code,
-                                  serf_connection_t *conn,
-                                  serf_request_t *request,
-                                  serf_bucket_t *response,
-                                  apr_pool_t *pool);
-
-/**
- * serf__authn_scheme_t: vtable for an authn scheme provider.
- */
-struct serf__authn_scheme_t {
-    /* The name of this authentication scheme. Used in headers of requests and
-       for logging. */
-    const char *name;
-
-    /* Key is the name of the authentication scheme in lower case, to
-       facilitate case insensitive matching of the response headers. */
-    const char *key;
-
-    /* Internal code used for this authn type. */
-    int type;
-
-    /* The context initialization function if any; otherwise, NULL */
-    serf__init_context_func_t init_ctx_func;
-
-    /* The connection initialization function if any; otherwise, NULL */
-    serf__init_conn_func_t init_conn_func;
-
-    /* The authentication handler function */
-    serf__auth_handler_func_t handle_func;
-
-    /* Function to set up the authentication header of a request */
-    serf__setup_request_func_t setup_request_func;
-
-    /* Function to validate the authentication header of a response */
-    serf__validate_response_func_t validate_response_func;
-};
-
-/**
- * Handles a 401 or 407 response, tries the different available authentication
- * handlers.
- */
-apr_status_t serf__handle_auth_response(int *consumed_response,
-                                        serf_request_t *request,
-                                        serf_bucket_t *response,
-                                        void *baton,
-                                        apr_pool_t *pool);
-
-/* Get the cached serf__authn_info_t object for the target server, or create one
-   when this is the first connection to the server.
-   TODO: The serf__authn_info_t objects are allocated in the context pool, so
-   a context that's used to connect to many different servers using Basic or 
-   Digest authencation will hold on to many objects indefinitely. We should be
-   able to cleanup stale objects from time to time. */
-serf__authn_info_t *serf__get_authn_info_for_server(serf_connection_t *conn);
-
-/* fromt context.c */
-void serf__context_progress_delta(void *progress_baton, apr_off_t read,
-                                  apr_off_t written);
-
-/* from incoming.c */
-apr_status_t serf__process_client(serf_incoming_t *l, apr_int16_t events);
-apr_status_t serf__process_listener(serf_listener_t *l);
-
-/* from outgoing.c */
-apr_status_t serf__open_connections(serf_context_t *ctx);
-apr_status_t serf__process_connection(serf_connection_t *conn,
-                                       apr_int16_t events);
-apr_status_t serf__conn_update_pollset(serf_connection_t *conn);
-serf_request_t *serf__ssltunnel_request_create(serf_connection_t *conn,
-                                               serf_request_setup_t setup,
-                                               void *setup_baton);
-apr_status_t serf__provide_credentials(serf_context_t *ctx,
-                                       char **username,
-                                       char **password,
-                                       serf_request_t *request,
-                                       void *baton,
-                                       int code, const char *authn_type,
-                                       const char *realm,
-                                       apr_pool_t *pool);
-
-/* from ssltunnel.c */
-apr_status_t serf__ssltunnel_connect(serf_connection_t *conn);
-
-
-/** Logging functions. Use one of the [COMP]_VERBOSE flags to enable specific
-    logging. 
- **/
-
-/* Logs a standard event, with filename & timestamp header */
-void serf__log(int verbose_flag, const char *filename, const char *fmt, ...);
-
-/* Logs a standard event, but without prefix. This is useful to build up
- log lines in parts. */
-void serf__log_nopref(int verbose_flag, const char *fmt, ...);
-
-/* Logs a socket event, add local and remote ip address:port */
-void serf__log_skt(int verbose_flag, const char *filename, apr_socket_t *skt,
-                   const char *fmt, ...);
-
-#endif

Copied: vendor/serf/1.3.9/serf_private.h (from rev 9259, vendor/serf/dist/serf_private.h)
===================================================================
--- vendor/serf/1.3.9/serf_private.h	                        (rev 0)
+++ vendor/serf/1.3.9/serf_private.h	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,470 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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 _SERF_PRIVATE_H_
+#define _SERF_PRIVATE_H_
+
+/* ### what the hell? why does the APR interface have a "size" ??
+   ### the implication is that, if we bust this limit, we'd need to
+   ### stop, rebuild a pollset, and repopulate it. what suckage.  */
+#define MAX_CONN 16
+
+/* Windows does not define IOV_MAX, so we need to ensure it is defined. */
+#ifndef IOV_MAX
+/* There is no limit for iovec count on Windows, but apr_socket_sendv
+   allocates WSABUF structures on stack if vecs_count <= 50. */
+#define IOV_MAX 50
+#endif
+
+/* Older versions of APR do not have this macro.  */
+#ifdef APR_SIZE_MAX
+#define REQUESTED_MAX APR_SIZE_MAX
+#else
+#define REQUESTED_MAX (~((apr_size_t)0))
+#endif
+
+#define SERF_IO_CLIENT (1)
+#define SERF_IO_CONN (2)
+#define SERF_IO_LISTENER (3)
+
+/* Internal logging facilities, set flag to 1 to enable console logging for
+   the selected component. */
+#define SSL_VERBOSE 0
+#define SSL_MSG_VERBOSE 0  /* logs decrypted requests and responses. */
+#define SOCK_VERBOSE 0
+#define SOCK_MSG_VERBOSE 0 /* logs bytes received from or written to a socket. */
+#define CONN_VERBOSE 0
+#define AUTH_VERBOSE 0
+
+/* Older versions of APR do not have the APR_VERSION_AT_LEAST macro. Those
+   implementations are safe.
+
+   If the macro *is* defined, and we're on WIN32, and APR is version 1.4.0+,
+   then we have a broken WSAPoll() implementation.
+
+   See serf_context_create_ex() below.  */
+#if defined(APR_VERSION_AT_LEAST) && defined(WIN32)
+#if APR_VERSION_AT_LEAST(1,4,0)
+#define BROKEN_WSAPOLL
+#endif
+#endif
+
+typedef struct serf__authn_scheme_t serf__authn_scheme_t;
+
+typedef struct serf_io_baton_t {
+    int type;
+    union {
+        serf_incoming_t *client;
+        serf_connection_t *conn;
+        serf_listener_t *listener;
+    } u;
+} serf_io_baton_t;
+
+/* Holds all the information corresponding to a request/response pair. */
+struct serf_request_t {
+    serf_connection_t *conn;
+
+    apr_pool_t *respool;
+    serf_bucket_alloc_t *allocator;
+
+    /* The bucket corresponding to the request. Will be NULL once the
+     * bucket has been emptied (for delivery into the socket).
+     */
+    serf_bucket_t *req_bkt;
+
+    serf_request_setup_t setup;
+    void *setup_baton;
+
+    serf_response_acceptor_t acceptor;
+    void *acceptor_baton;
+
+    serf_response_handler_t handler;
+    void *handler_baton;
+
+    serf_bucket_t *resp_bkt;
+
+    int writing_started;
+    int priority;
+    /* 1 if this is a request to setup a SSL tunnel, 0 for normal requests. */
+    int ssltunnel;
+
+    /* This baton is currently only used for digest authentication, which
+       needs access to the uri of the request in the response handler.
+       If serf_request_t is replaced by a serf_http_request_t in the future,
+       which knows about uri and method and such, this baton won't be needed
+       anymore. */
+    void *auth_baton;
+
+    struct serf_request_t *next;
+};
+
+typedef struct serf_pollset_t {
+    /* the set of connections to poll */
+    apr_pollset_t *pollset;
+} serf_pollset_t;
+
+typedef struct serf__authn_info_t {
+    const serf__authn_scheme_t *scheme;
+
+    void *baton;
+
+    int failed_authn_types;
+} serf__authn_info_t;
+
+struct serf_context_t {
+    /* the pool used for self and for other allocations */
+    apr_pool_t *pool;
+
+    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;
+
+    /* 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;
+
+    /* authentication info for the servers used in this context. Shared by all
+       connections to the same server.
+       Structure of the hashtable:  key: host url, e.g. https://localhost:80
+                                  value: serf__authn_info_t *
+     */
+    apr_hash_t *server_authn_info;
+
+    /* authentication info for the proxy configured in this context, shared by
+       all connections. */
+    serf__authn_info_t proxy_authn_info;
+
+    /* List of authn types supported by the client.*/
+    int authn_types;
+    /* Callback function used to get credentials for a realm. */
+    serf_credentials_callback_t cred_cb; 
+};
+
+struct serf_listener_t {
+    serf_context_t *ctx;
+    serf_io_baton_t baton;
+    apr_socket_t *skt;
+    apr_pool_t *pool;
+    apr_pollfd_t desc;
+    void *accept_baton;
+    serf_accept_client_t accept_func;
+};
+
+struct serf_incoming_t {
+    serf_context_t *ctx;
+    serf_io_baton_t baton;
+    void *request_baton;
+    serf_incoming_request_cb_t request;
+    apr_socket_t *skt;
+    apr_pollfd_t desc;
+};
+
+/* States for the different stages in the lifecyle of a connection. */
+typedef enum {
+    SERF_CONN_INIT,             /* no socket created yet */
+    SERF_CONN_SETUP_SSLTUNNEL,  /* ssl tunnel being setup, no requests sent */
+    SERF_CONN_CONNECTED,        /* conn is ready to send requests */
+    SERF_CONN_CLOSING           /* conn is closing, no more requests,
+                                   start a new socket */
+} serf__connection_state_t;
+
+struct serf_connection_t {
+    serf_context_t *ctx;
+
+    apr_status_t status;
+    serf_io_baton_t baton;
+
+    apr_pool_t *pool;
+    serf_bucket_alloc_t *allocator;
+
+    apr_sockaddr_t *address;
+
+    apr_socket_t *skt;
+    apr_pool_t *skt_pool;
+
+    /* the last reqevents we gave to pollset_add */
+    apr_int16_t reqevents;
+
+    /* the events we've seen for this connection in our returned pollset */
+    apr_int16_t seen_in_pollset;
+
+    /* are we a dirty connection that needs its poll status updated? */
+    int dirty_conn;
+
+    /* number of completed requests we've sent */
+    unsigned int completed_requests;
+
+    /* number of completed responses we've got */
+    unsigned int completed_responses;
+
+    /* keepalive */
+    unsigned int probable_keepalive_limit;
+
+    /* Current state of the connection (whether or not it is connected). */
+    serf__connection_state_t state;
+
+    /* This connection may have responses without a request! */
+    int async_responses;
+    serf_bucket_t *current_async_response;
+    serf_response_acceptor_t async_acceptor;
+    void *async_acceptor_baton;
+    serf_response_handler_t async_handler;
+    void *async_handler_baton;
+
+    /* A bucket wrapped around our socket (for reading responses). */
+    serf_bucket_t *stream;
+    /* A reference to the aggregate bucket that provides the boundary between
+     * request level buckets and connection level buckets.
+     */
+    serf_bucket_t *ostream_head;
+    serf_bucket_t *ostream_tail;
+
+    /* Aggregate bucket used to send the CONNECT request. */
+    serf_bucket_t *ssltunnel_ostream;
+
+    /* The list of active requests. */
+    serf_request_t *requests;
+    serf_request_t *requests_tail;
+
+    struct iovec vec[IOV_MAX];
+    int vec_len;
+
+    serf_connection_setup_t setup;
+    void *setup_baton;
+    serf_connection_closed_t closed;
+    void *closed_baton;
+
+    /* Max. number of outstanding requests. */
+    unsigned int max_outstanding_requests;
+
+    int hit_eof;
+
+    /* Host url, path ommitted, syntax: https://svn.apache.org . */
+    const char *host_url;
+    
+    /* Exploded host url, path ommitted. Only scheme, hostinfo, hostname &
+       port values are filled in. */
+    apr_uri_t host_info;
+
+    /* authentication info for this connection. */
+    serf__authn_info_t authn_info;
+
+    /* Time marker when connection begins. */
+    apr_time_t connect_time;
+
+    /* Calculated connection latency. Negative value if latency is unknown. */
+    apr_interval_time_t latency;
+
+    /* Needs to read first before we can write again. */
+    int stop_writing;
+};
+
+/*** Internal bucket functions ***/
+
+/** Transform a response_bucket in-place into an aggregate bucket. Restore the
+    status line and all headers, not just the body.
+ 
+    This can only be used when we haven't started reading the body of the
+    response yet.
+ 
+    Keep internal for now, probably only useful within serf.
+ */
+apr_status_t serf_response_full_become_aggregate(serf_bucket_t *bucket);
+
+/**
+ * Remove the header from the list, do nothing if the header wasn't added.
+ */
+void serf__bucket_headers_remove(serf_bucket_t *headers_bucket,
+                                 const char *header);
+
+/*** Authentication handler declarations ***/
+
+typedef enum { PROXY, HOST } peer_t;
+
+/**
+ * For each authentication scheme we need a handler function of type
+ * serf__auth_handler_func_t. This function will be called when an
+ * authentication challenge is received in a session.
+ */
+typedef apr_status_t
+(*serf__auth_handler_func_t)(int code,
+                             serf_request_t *request,
+                             serf_bucket_t *response,
+                             const char *auth_hdr,
+                             const char *auth_attr,
+                             void *baton,
+                             apr_pool_t *pool);
+
+/**
+ * For each authentication scheme we need an initialization function of type
+ * serf__init_context_func_t. This function will be called the first time
+ * serf tries a specific authentication scheme handler.
+ */
+typedef apr_status_t
+(*serf__init_context_func_t)(int code,
+                             serf_context_t *conn,
+                             apr_pool_t *pool);
+
+/**
+ * For each authentication scheme we need an initialization function of type
+ * serf__init_conn_func_t. This function will be called when a new
+ * connection is opened.
+ */
+typedef apr_status_t
+(*serf__init_conn_func_t)(const serf__authn_scheme_t *scheme,
+                          int code,
+                          serf_connection_t *conn,
+                          apr_pool_t *pool);
+
+/**
+ * For each authentication scheme we need a setup_request function of type
+ * serf__setup_request_func_t. This function will be called when a
+ * new serf_request_t object is created and should fill in the correct
+ * authentication headers (if needed).
+ */
+typedef apr_status_t
+(*serf__setup_request_func_t)(peer_t peer,
+                              int code,
+                              serf_connection_t *conn,
+                              serf_request_t *request,
+                              const char *method,
+                              const char *uri,
+                              serf_bucket_t *hdrs_bkt);
+
+/**
+ * This function will be called when a response is received, so that the 
+ * scheme handler can validate the Authentication related response headers
+ * (if needed).
+ */
+typedef apr_status_t
+(*serf__validate_response_func_t)(const serf__authn_scheme_t *scheme,
+                                  peer_t peer,
+                                  int code,
+                                  serf_connection_t *conn,
+                                  serf_request_t *request,
+                                  serf_bucket_t *response,
+                                  apr_pool_t *pool);
+
+/**
+ * serf__authn_scheme_t: vtable for an authn scheme provider.
+ */
+struct serf__authn_scheme_t {
+    /* The name of this authentication scheme. Used in headers of requests and
+       for logging. */
+    const char *name;
+
+    /* Key is the name of the authentication scheme in lower case, to
+       facilitate case insensitive matching of the response headers. */
+    const char *key;
+
+    /* Internal code used for this authn type. */
+    int type;
+
+    /* The context initialization function if any; otherwise, NULL */
+    serf__init_context_func_t init_ctx_func;
+
+    /* The connection initialization function if any; otherwise, NULL */
+    serf__init_conn_func_t init_conn_func;
+
+    /* The authentication handler function */
+    serf__auth_handler_func_t handle_func;
+
+    /* Function to set up the authentication header of a request */
+    serf__setup_request_func_t setup_request_func;
+
+    /* Function to validate the authentication header of a response */
+    serf__validate_response_func_t validate_response_func;
+};
+
+/**
+ * Handles a 401 or 407 response, tries the different available authentication
+ * handlers.
+ */
+apr_status_t serf__handle_auth_response(int *consumed_response,
+                                        serf_request_t *request,
+                                        serf_bucket_t *response,
+                                        void *baton,
+                                        apr_pool_t *pool);
+
+/* Get the cached serf__authn_info_t object for the target server, or create one
+   when this is the first connection to the server.
+   TODO: The serf__authn_info_t objects are allocated in the context pool, so
+   a context that's used to connect to many different servers using Basic or 
+   Digest authencation will hold on to many objects indefinitely. We should be
+   able to cleanup stale objects from time to time. */
+serf__authn_info_t *serf__get_authn_info_for_server(serf_connection_t *conn);
+
+/* fromt context.c */
+void serf__context_progress_delta(void *progress_baton, apr_off_t read,
+                                  apr_off_t written);
+
+/* from incoming.c */
+apr_status_t serf__process_client(serf_incoming_t *l, apr_int16_t events);
+apr_status_t serf__process_listener(serf_listener_t *l);
+
+/* from outgoing.c */
+apr_status_t serf__open_connections(serf_context_t *ctx);
+apr_status_t serf__process_connection(serf_connection_t *conn,
+                                       apr_int16_t events);
+apr_status_t serf__conn_update_pollset(serf_connection_t *conn);
+serf_request_t *serf__ssltunnel_request_create(serf_connection_t *conn,
+                                               serf_request_setup_t setup,
+                                               void *setup_baton);
+apr_status_t serf__provide_credentials(serf_context_t *ctx,
+                                       char **username,
+                                       char **password,
+                                       serf_request_t *request,
+                                       void *baton,
+                                       int code, const char *authn_type,
+                                       const char *realm,
+                                       apr_pool_t *pool);
+
+/* from ssltunnel.c */
+apr_status_t serf__ssltunnel_connect(serf_connection_t *conn);
+
+
+/** Logging functions. Use one of the [COMP]_VERBOSE flags to enable specific
+    logging. 
+ **/
+
+/* Logs a standard event, with filename & timestamp header */
+void serf__log(int verbose_flag, const char *filename, const char *fmt, ...);
+
+/* Logs a standard event, but without prefix. This is useful to build up
+ log lines in parts. */
+void serf__log_nopref(int verbose_flag, const char *fmt, ...);
+
+/* Logs a socket event, add local and remote ip address:port */
+void serf__log_skt(int verbose_flag, const char *filename, apr_socket_t *skt,
+                   const char *fmt, ...);
+
+#endif

Deleted: vendor/serf/1.3.9/ssltunnel.c
===================================================================
--- vendor/serf/dist/ssltunnel.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/ssltunnel.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,195 +0,0 @@
-/* Copyright 2011 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.
- */
-
-/*** Setup a SSL tunnel over a HTTP proxy, according to RFC 2817. ***/
-
-#include <apr_pools.h>
-#include <apr_strings.h>
-
-#include "serf.h"
-#include "serf_private.h"
-
-
-/* Structure passed around as baton for the CONNECT request and respone. */
-typedef struct {
-    apr_pool_t *pool;
-    const char *uri;
-} req_ctx_t;
-
-/* forward declaration. */
-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);
-
-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;
-#if 0
-    req_ctx_t *ctx = acceptor_baton;
-#endif
-
-    /* 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);
-
-    return serf_bucket_response_create(c, bkt_alloc);
-}
-
-/* If a 200 OK was received for the CONNECT request, consider the connection
-   as ready for use. */
-static apr_status_t handle_response(serf_request_t *request,
-                                    serf_bucket_t *response,
-                                    void *handler_baton,
-                                    apr_pool_t *pool)
-{
-    apr_status_t status;
-    serf_status_line sl;
-    req_ctx_t *ctx = handler_baton;
-    serf_connection_t *conn = request->conn;
-
-    /* CONNECT request was cancelled. Assuming that this is during connection
-       reset, we can safely discard the request as a new one will be created
-       when setting up the next connection. */
-    if (!response)
-        return APR_SUCCESS;
-
-    status = serf_bucket_response_status(response, &sl);
-    if (SERF_BUCKET_READ_ERROR(status)) {
-        return status;
-    }
-    if (!sl.version && (APR_STATUS_IS_EOF(status) ||
-                      APR_STATUS_IS_EAGAIN(status)))
-    {
-        return status;
-    }
-
-    status = serf_bucket_response_wait_for_headers(response);
-    if (status && !APR_STATUS_IS_EOF(status)) {
-        return status;
-    }
-
-    /* RFC 2817:  Any successful (2xx) response to a CONNECT request indicates
-       that the proxy has established a connection to the requested host and
-       port, and has switched to tunneling the current connection to that server
-       connection.
-    */
-    if (sl.code >= 200 && sl.code < 300) {
-        serf_bucket_t *hdrs;
-        const char *val;
-
-        conn->state = SERF_CONN_CONNECTED;
-
-        /* Body is supposed to be empty. */
-        apr_pool_destroy(ctx->pool);
-        serf_bucket_destroy(conn->ssltunnel_ostream);
-        serf_bucket_destroy(conn->stream);
-        conn->stream = NULL;
-        ctx = NULL;
-
-        serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt,
-                      "successfully set up ssl tunnel.\n");
-
-        /* Fix for issue #123: ignore the "Connection: close" header here,
-           leaving the header in place would make the serf's main context
-           loop close this connection immediately after reading the 200 OK
-           response. */
-
-        hdrs = serf_bucket_response_get_headers(response);
-        val = serf_bucket_headers_get(hdrs, "Connection");
-        if (val && strcasecmp("close", val) == 0) {
-            serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt,
-                      "Ignore Connection: close header on this reponse, don't "
-                      "close the connection now that the tunnel is set up.\n");
-            serf__bucket_headers_remove(hdrs, "Connection");
-        }
-
-        return APR_EOF;
-    }
-
-    /* Authentication failure and 2xx Ok are handled at this point,
-       the rest are errors. */
-    return SERF_ERROR_SSLTUNNEL_SETUP_FAILED;
-}
-
-/* Prepare the CONNECT 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_handler_t *handler,
-                                  void **handler_baton,
-                                  apr_pool_t *pool)
-{
-    req_ctx_t *ctx = setup_baton;
-
-    *req_bkt =
-        serf_request_bucket_request_create(request,
-                                           "CONNECT", ctx->uri,
-                                           NULL,
-                                           serf_request_get_alloc(request));
-    *acceptor = accept_response;
-    *acceptor_baton = ctx;
-    *handler = handle_response;
-    *handler_baton = ctx;
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t detect_eof(void *baton, serf_bucket_t *aggregate_bucket)
-{
-    serf_connection_t *conn = baton;
-    conn->hit_eof = 1;
-    return APR_EAGAIN;
-}
-
-/* SSL tunnel is needed, push a CONNECT request on the connection. */
-apr_status_t serf__ssltunnel_connect(serf_connection_t *conn)
-{
-    req_ctx_t *ctx;
-    apr_pool_t *ssltunnel_pool;
-
-    apr_pool_create(&ssltunnel_pool, conn->pool);
-
-    ctx = apr_palloc(ssltunnel_pool, sizeof(*ctx));
-    ctx->pool = ssltunnel_pool;
-    ctx->uri = apr_psprintf(ctx->pool, "%s:%d", conn->host_info.hostname,
-                            conn->host_info.port);
-
-    conn->ssltunnel_ostream = serf__bucket_stream_create(conn->allocator,
-                                                         detect_eof,
-                                                         conn);
-
-    serf__ssltunnel_request_create(conn,
-                                   setup_request,
-                                   ctx);
-
-    conn->state = SERF_CONN_SETUP_SSLTUNNEL;
-    serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt,
-                  "setting up ssl tunnel on connection.\n");
-
-    return APR_SUCCESS;
-}

Copied: vendor/serf/1.3.9/ssltunnel.c (from rev 9259, vendor/serf/dist/ssltunnel.c)
===================================================================
--- vendor/serf/1.3.9/ssltunnel.c	                        (rev 0)
+++ vendor/serf/1.3.9/ssltunnel.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,200 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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.
+ * ====================================================================
+ */
+
+/*** Setup a SSL tunnel over a HTTP proxy, according to RFC 2817. ***/
+
+#include <apr_pools.h>
+#include <apr_strings.h>
+
+#include "serf.h"
+#include "serf_private.h"
+
+
+/* Structure passed around as baton for the CONNECT request and respone. */
+typedef struct {
+    apr_pool_t *pool;
+    const char *uri;
+} req_ctx_t;
+
+/* forward declaration. */
+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);
+
+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;
+#if 0
+    req_ctx_t *ctx = acceptor_baton;
+#endif
+
+    /* 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);
+
+    return serf_bucket_response_create(c, bkt_alloc);
+}
+
+/* If a 200 OK was received for the CONNECT request, consider the connection
+   as ready for use. */
+static apr_status_t handle_response(serf_request_t *request,
+                                    serf_bucket_t *response,
+                                    void *handler_baton,
+                                    apr_pool_t *pool)
+{
+    apr_status_t status;
+    serf_status_line sl;
+    req_ctx_t *ctx = handler_baton;
+    serf_connection_t *conn = request->conn;
+
+    /* CONNECT request was cancelled. Assuming that this is during connection
+       reset, we can safely discard the request as a new one will be created
+       when setting up the next connection. */
+    if (!response)
+        return APR_SUCCESS;
+
+    status = serf_bucket_response_status(response, &sl);
+    if (SERF_BUCKET_READ_ERROR(status)) {
+        return status;
+    }
+    if (!sl.version && (APR_STATUS_IS_EOF(status) ||
+                      APR_STATUS_IS_EAGAIN(status)))
+    {
+        return status;
+    }
+
+    status = serf_bucket_response_wait_for_headers(response);
+    if (status && !APR_STATUS_IS_EOF(status)) {
+        return status;
+    }
+
+    /* RFC 2817:  Any successful (2xx) response to a CONNECT request indicates
+       that the proxy has established a connection to the requested host and
+       port, and has switched to tunneling the current connection to that server
+       connection.
+    */
+    if (sl.code >= 200 && sl.code < 300) {
+        serf_bucket_t *hdrs;
+        const char *val;
+
+        conn->state = SERF_CONN_CONNECTED;
+
+        /* Body is supposed to be empty. */
+        apr_pool_destroy(ctx->pool);
+        serf_bucket_destroy(conn->ssltunnel_ostream);
+        serf_bucket_destroy(conn->stream);
+        conn->stream = NULL;
+        ctx = NULL;
+
+        serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt,
+                      "successfully set up ssl tunnel.\n");
+
+        /* Fix for issue #123: ignore the "Connection: close" header here,
+           leaving the header in place would make the serf's main context
+           loop close this connection immediately after reading the 200 OK
+           response. */
+
+        hdrs = serf_bucket_response_get_headers(response);
+        val = serf_bucket_headers_get(hdrs, "Connection");
+        if (val && strcasecmp("close", val) == 0) {
+            serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt,
+                      "Ignore Connection: close header on this reponse, don't "
+                      "close the connection now that the tunnel is set up.\n");
+            serf__bucket_headers_remove(hdrs, "Connection");
+        }
+
+        return APR_EOF;
+    }
+
+    /* Authentication failure and 2xx Ok are handled at this point,
+       the rest are errors. */
+    return SERF_ERROR_SSLTUNNEL_SETUP_FAILED;
+}
+
+/* Prepare the CONNECT 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_handler_t *handler,
+                                  void **handler_baton,
+                                  apr_pool_t *pool)
+{
+    req_ctx_t *ctx = setup_baton;
+
+    *req_bkt =
+        serf_request_bucket_request_create(request,
+                                           "CONNECT", ctx->uri,
+                                           NULL,
+                                           serf_request_get_alloc(request));
+    *acceptor = accept_response;
+    *acceptor_baton = ctx;
+    *handler = handle_response;
+    *handler_baton = ctx;
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t detect_eof(void *baton, serf_bucket_t *aggregate_bucket)
+{
+    serf_connection_t *conn = baton;
+    conn->hit_eof = 1;
+    return APR_EAGAIN;
+}
+
+/* SSL tunnel is needed, push a CONNECT request on the connection. */
+apr_status_t serf__ssltunnel_connect(serf_connection_t *conn)
+{
+    req_ctx_t *ctx;
+    apr_pool_t *ssltunnel_pool;
+
+    apr_pool_create(&ssltunnel_pool, conn->pool);
+
+    ctx = apr_palloc(ssltunnel_pool, sizeof(*ctx));
+    ctx->pool = ssltunnel_pool;
+    ctx->uri = apr_psprintf(ctx->pool, "%s:%d", conn->host_info.hostname,
+                            conn->host_info.port);
+
+    conn->ssltunnel_ostream = serf__bucket_stream_create(conn->allocator,
+                                                         detect_eof,
+                                                         conn);
+
+    serf__ssltunnel_request_create(conn,
+                                   setup_request,
+                                   ctx);
+
+    conn->state = SERF_CONN_SETUP_SSLTUNNEL;
+    serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt,
+                  "setting up ssl tunnel on connection.\n");
+
+    return APR_SUCCESS;
+}

Deleted: vendor/serf/1.3.9/test/mock_buckets.c
===================================================================
--- vendor/serf/dist/test/mock_buckets.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/test/mock_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,334 +0,0 @@
-/* Copyright 2013 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_pools.h>
-
-#include "serf.h"
-#include "serf_bucket_util.h"
-#include "test_serf.h"
-
-/* This bucket uses a list of count - data/len - status actions (provided by the
-   test case), to control the read / read_iovec operations. */
-typedef struct {
-    mockbkt_action *actions;
-    int len;
-    const char *current_data;
-    int remaining_data;
-    int current_action;
-    int remaining_times;
-} mockbkt_context_t;
-
-serf_bucket_t *serf_bucket_mock_create(mockbkt_action *actions,
-                                       int len,
-                                       serf_bucket_alloc_t *allocator)
-{
-    mockbkt_context_t *ctx;
-
-    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
-    ctx->actions = actions;
-    ctx->len = len;
-    ctx->current_data = 0l;
-    ctx->remaining_data = -1;
-    ctx->current_action = 0;
-    ctx->remaining_times = -1;
-
-    return serf_bucket_create(&serf_bucket_type_mock, allocator, ctx);
-}
-
-static apr_status_t next_action(mockbkt_context_t *ctx)
-{
-    mockbkt_action *action;
-
-    while (1)
-    {
-        if (ctx->current_action >= ctx->len)
-            return APR_EOF;
-
-        action = &ctx->actions[ctx->current_action];
-
-        if (ctx->remaining_times == 0) {
-            ctx->current_action++;
-            ctx->remaining_times = -1;
-            ctx->remaining_data = -1;
-            continue;
-        }
-
-        if (ctx->remaining_data <= 0) {
-            ctx->current_data = action->data;
-            ctx->remaining_times = action->times;
-            ctx->remaining_data = strlen(action->data);
-        }
-
-        return APR_SUCCESS;
-    }
-}
-
-static apr_status_t serf_mock_readline(serf_bucket_t *bucket,
-                                       int acceptable, int *found,
-                                       const char **data, apr_size_t *len)
-{
-    mockbkt_context_t *ctx = bucket->data;
-    mockbkt_action *action;
-    apr_status_t status;
-    const char *start_line;
-
-    status = next_action(ctx);
-    if (status) {
-        *len = 0;
-        return status;
-    }
-
-    action = &ctx->actions[ctx->current_action];
-    start_line = *data = ctx->current_data;
-    *len = ctx->remaining_data;
-
-    serf_util_readline(&start_line, len, acceptable, found);
-
-    /* See how much ctx->current moved forward. */
-    *len = start_line - ctx->current_data;
-    ctx->remaining_data -= *len;
-    ctx->current_data += *len;
-    if (ctx->remaining_data == 0)
-        ctx->remaining_times--;
-
-    return ctx->remaining_data ? APR_SUCCESS : action->status;
-}
-
-static apr_status_t serf_mock_read(serf_bucket_t *bucket,
-                                   apr_size_t requested,
-                                   const char **data, apr_size_t *len)
-{
-    mockbkt_context_t *ctx = bucket->data;
-    mockbkt_action *action;
-    apr_status_t status;
-
-    status = next_action(ctx);
-    if (status) {
-        *len = 0;
-        return status;
-    }
-
-    action = &ctx->actions[ctx->current_action];
-    *len = requested < ctx->remaining_data ? requested : ctx->remaining_data;
-    *data = ctx->current_data;
-
-    ctx->remaining_data -= *len;
-    ctx->current_data += *len;
-
-    if (ctx->remaining_data == 0)
-        ctx->remaining_times--;
-
-    return ctx->remaining_data ? APR_SUCCESS : action->status;
-}
-
-static apr_status_t serf_mock_peek(serf_bucket_t *bucket,
-                                   const char **data,
-                                   apr_size_t *len)
-{
-    mockbkt_context_t *ctx = bucket->data;
-    mockbkt_action *action;
-    apr_status_t status;
-
-    status = next_action(ctx);
-    if (status)
-        return status;
-
-    action = &ctx->actions[ctx->current_action];
-    *len = ctx->remaining_data;
-    *data = ctx->current_data;
-
-    /* peek only returns an error, APR_EOF or APR_SUCCESS.
-       APR_EAGAIN is returned as APR_SUCCESS. */
-    if (SERF_BUCKET_READ_ERROR(action->status))
-        return status;
-
-    return action->status == APR_EOF ? APR_EOF : APR_SUCCESS;
-}
-
-/* An action { "", 0, APR_EAGAIN } means that serf should exit serf_context_run
-   and pass the buck back to the application. As long as no new data arrives,
-   this action remains active.
- 
-   This function allows the 'application' to trigger the arrival of more data.
-   If the current action is { "", 0, APR_EAGAIN }, reduce the number of times
-   the action should run by one, and proceed with the next action if needed.
- */
-apr_status_t serf_bucket_mock_more_data_arrived(serf_bucket_t *bucket)
-{
-    mockbkt_context_t *ctx = bucket->data;
-    mockbkt_action *action;
-    apr_status_t status;
-
-    status = next_action(ctx);
-    if (status)
-        return status;
-
-    action = &ctx->actions[ctx->current_action];
-    if (ctx->remaining_data == 0 && action->status == APR_EAGAIN) {
-        ctx->remaining_times--;
-        action->times--;
-    }
-
-    return APR_SUCCESS;
-}
-
-const serf_bucket_type_t serf_bucket_type_mock = {
-    "MOCK",
-    serf_mock_read,
-    serf_mock_readline,
-    serf_default_read_iovec,
-    serf_default_read_for_sendfile,
-    serf_default_read_bucket,
-    serf_mock_peek,
-    serf_default_destroy_and_data,
-};
-
-
-/* internal test for the mock buckets */
-static void test_basic_mock_bucket(CuTest *tc)
-{
-    serf_bucket_t *mock_bkt;
-    apr_pool_t *test_pool = tc->testBaton;
-    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
-                                                              NULL);
-    /* read one line */
-    {
-        mockbkt_action actions[]= {
-            { 1, "HTTP/1.1 200 OK" CRLF, APR_EOF },
-        };
-        mock_bkt = serf_bucket_mock_create(actions, 1, alloc);
-        read_and_check_bucket(tc, mock_bkt,
-                              "HTTP/1.1 200 OK" CRLF);
-
-        mock_bkt = serf_bucket_mock_create(actions, 1, alloc);
-        readlines_and_check_bucket(tc, mock_bkt, SERF_NEWLINE_CRLF,
-                                   "HTTP/1.1 200 OK" CRLF, 1);
-    }
-    /* read one line, character per character */
-    {
-        apr_status_t status;
-        const char *expected = "HTTP/1.1 200 OK" CRLF;
-        mockbkt_action actions[]= {
-            { 1, "HTTP/1.1 200 OK" CRLF, APR_EOF },
-        };
-        mock_bkt = serf_bucket_mock_create(actions, 1, alloc);
-        do
-        {
-            const char *data;
-            apr_size_t len;
-
-            status = serf_bucket_read(mock_bkt, 1, &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);
-            CuAssert(tc, "Read more data than requested.",
-                     len <= 1);
-
-            expected += len;
-        } while(!APR_STATUS_IS_EOF(status));
-        
-        CuAssert(tc, "Read less data than expected.", strlen(expected) == 0);
-    }
-    /* read multiple lines */
-    {
-        mockbkt_action actions[]= {
-            { 1, "HTTP/1.1 200 OK" CRLF, APR_SUCCESS },
-            { 1, "Content-Type: text/plain" CRLF, APR_EOF },
-        };
-        mock_bkt = serf_bucket_mock_create(actions, 2, alloc);
-        readlines_and_check_bucket(tc, mock_bkt, SERF_NEWLINE_CRLF,
-                                   "HTTP/1.1 200 OK" CRLF
-                                   "Content-Type: text/plain" CRLF, 2);
-    }
-    /* read empty line */
-    {
-        mockbkt_action actions[]= {
-            { 1, "HTTP/1.1 200 OK" CRLF, APR_SUCCESS },
-            { 1, "", APR_EAGAIN },
-            { 1, "Content-Type: text/plain" CRLF, APR_EOF },
-        };
-        mock_bkt = serf_bucket_mock_create(actions, 3, alloc);
-        read_and_check_bucket(tc, mock_bkt,
-                              "HTTP/1.1 200 OK" CRLF
-                              "Content-Type: text/plain" CRLF);
-        mock_bkt = serf_bucket_mock_create(actions, 3, alloc);
-        readlines_and_check_bucket(tc, mock_bkt, SERF_NEWLINE_CRLF,
-                                   "HTTP/1.1 200 OK" CRLF
-                                   "Content-Type: text/plain" CRLF, 2);
-    }
-    /* read empty line */
-    {
-        mockbkt_action actions[]= {
-            { 1, "HTTP/1.1 200 OK" CR, APR_SUCCESS },
-            { 1, "", APR_EAGAIN },
-            { 1, LF, APR_EOF },
-        };
-        mock_bkt = serf_bucket_mock_create(actions,
-                                           sizeof(actions)/sizeof(actions[0]),
-                                           alloc);
-        read_and_check_bucket(tc, mock_bkt,
-                              "HTTP/1.1 200 OK" CRLF);
-
-        mock_bkt = serf_bucket_mock_create(actions,
-                                           sizeof(actions)/sizeof(actions[0]),
-                                           alloc);
-        readlines_and_check_bucket(tc, mock_bkt, SERF_NEWLINE_CRLF,
-                                   "HTTP/1.1 200 OK" CRLF, 1);
-    }
-    /* test more_data_arrived */
-    {
-        apr_status_t status;
-        const char *data;
-        apr_size_t len;
-        int i;
-
-        mockbkt_action actions[]= {
-            { 1, "", APR_EAGAIN },
-            { 1, "blabla", APR_EOF },
-        };
-        mock_bkt = serf_bucket_mock_create(actions,
-                                           sizeof(actions)/sizeof(actions[0]),
-                                           alloc);
-
-        for (i = 0; i < 5; i++) {
-            status = serf_bucket_peek(mock_bkt, &data, &len);
-            CuAssertIntEquals(tc, APR_SUCCESS, status);
-            CuAssertIntEquals(tc, 0, len);
-            CuAssertIntEquals(tc, '\0', *data);
-        }
-
-        serf_bucket_mock_more_data_arrived(mock_bkt);
-
-        status = serf_bucket_peek(mock_bkt, &data, &len);
-        CuAssertIntEquals(tc, APR_EOF, status);
-        CuAssertIntEquals(tc, 6, len);
-        CuAssert(tc, "Read data is not equal to expected.",
-                 strncmp("blabla", data, len) == 0);
-    }
-}
-
-CuSuite *test_mock_bucket(void)
-{
-    CuSuite *suite = CuSuiteNew();
-
-    CuSuiteSetSetupTeardownCallbacks(suite, test_setup, test_teardown);
-
-    SUITE_ADD_TEST(suite, test_basic_mock_bucket);
-
-    return suite;
-}

Copied: vendor/serf/1.3.9/test/mock_buckets.c (from rev 9259, vendor/serf/dist/test/mock_buckets.c)
===================================================================
--- vendor/serf/1.3.9/test/mock_buckets.c	                        (rev 0)
+++ vendor/serf/1.3.9/test/mock_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,339 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_pools.h>
+
+#include "serf.h"
+#include "serf_bucket_util.h"
+#include "test_serf.h"
+
+/* This bucket uses a list of count - data/len - status actions (provided by the
+   test case), to control the read / read_iovec operations. */
+typedef struct {
+    mockbkt_action *actions;
+    int len;
+    const char *current_data;
+    int remaining_data;
+    int current_action;
+    int remaining_times;
+} mockbkt_context_t;
+
+serf_bucket_t *serf_bucket_mock_create(mockbkt_action *actions,
+                                       int len,
+                                       serf_bucket_alloc_t *allocator)
+{
+    mockbkt_context_t *ctx;
+
+    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
+    ctx->actions = actions;
+    ctx->len = len;
+    ctx->current_data = 0l;
+    ctx->remaining_data = -1;
+    ctx->current_action = 0;
+    ctx->remaining_times = -1;
+
+    return serf_bucket_create(&serf_bucket_type_mock, allocator, ctx);
+}
+
+static apr_status_t next_action(mockbkt_context_t *ctx)
+{
+    mockbkt_action *action;
+
+    while (1)
+    {
+        if (ctx->current_action >= ctx->len)
+            return APR_EOF;
+
+        action = &ctx->actions[ctx->current_action];
+
+        if (ctx->remaining_times == 0) {
+            ctx->current_action++;
+            ctx->remaining_times = -1;
+            ctx->remaining_data = -1;
+            continue;
+        }
+
+        if (ctx->remaining_data <= 0) {
+            ctx->current_data = action->data;
+            ctx->remaining_times = action->times;
+            ctx->remaining_data = strlen(action->data);
+        }
+
+        return APR_SUCCESS;
+    }
+}
+
+static apr_status_t serf_mock_readline(serf_bucket_t *bucket,
+                                       int acceptable, int *found,
+                                       const char **data, apr_size_t *len)
+{
+    mockbkt_context_t *ctx = bucket->data;
+    mockbkt_action *action;
+    apr_status_t status;
+    const char *start_line;
+
+    status = next_action(ctx);
+    if (status) {
+        *len = 0;
+        return status;
+    }
+
+    action = &ctx->actions[ctx->current_action];
+    start_line = *data = ctx->current_data;
+    *len = ctx->remaining_data;
+
+    serf_util_readline(&start_line, len, acceptable, found);
+
+    /* See how much ctx->current moved forward. */
+    *len = start_line - ctx->current_data;
+    ctx->remaining_data -= *len;
+    ctx->current_data += *len;
+    if (ctx->remaining_data == 0)
+        ctx->remaining_times--;
+
+    return ctx->remaining_data ? APR_SUCCESS : action->status;
+}
+
+static apr_status_t serf_mock_read(serf_bucket_t *bucket,
+                                   apr_size_t requested,
+                                   const char **data, apr_size_t *len)
+{
+    mockbkt_context_t *ctx = bucket->data;
+    mockbkt_action *action;
+    apr_status_t status;
+
+    status = next_action(ctx);
+    if (status) {
+        *len = 0;
+        return status;
+    }
+
+    action = &ctx->actions[ctx->current_action];
+    *len = requested < ctx->remaining_data ? requested : ctx->remaining_data;
+    *data = ctx->current_data;
+
+    ctx->remaining_data -= *len;
+    ctx->current_data += *len;
+
+    if (ctx->remaining_data == 0)
+        ctx->remaining_times--;
+
+    return ctx->remaining_data ? APR_SUCCESS : action->status;
+}
+
+static apr_status_t serf_mock_peek(serf_bucket_t *bucket,
+                                   const char **data,
+                                   apr_size_t *len)
+{
+    mockbkt_context_t *ctx = bucket->data;
+    mockbkt_action *action;
+    apr_status_t status;
+
+    status = next_action(ctx);
+    if (status)
+        return status;
+
+    action = &ctx->actions[ctx->current_action];
+    *len = ctx->remaining_data;
+    *data = ctx->current_data;
+
+    /* peek only returns an error, APR_EOF or APR_SUCCESS.
+       APR_EAGAIN is returned as APR_SUCCESS. */
+    if (SERF_BUCKET_READ_ERROR(action->status))
+        return status;
+
+    return action->status == APR_EOF ? APR_EOF : APR_SUCCESS;
+}
+
+/* An action { "", 0, APR_EAGAIN } means that serf should exit serf_context_run
+   and pass the buck back to the application. As long as no new data arrives,
+   this action remains active.
+ 
+   This function allows the 'application' to trigger the arrival of more data.
+   If the current action is { "", 0, APR_EAGAIN }, reduce the number of times
+   the action should run by one, and proceed with the next action if needed.
+ */
+apr_status_t serf_bucket_mock_more_data_arrived(serf_bucket_t *bucket)
+{
+    mockbkt_context_t *ctx = bucket->data;
+    mockbkt_action *action;
+    apr_status_t status;
+
+    status = next_action(ctx);
+    if (status)
+        return status;
+
+    action = &ctx->actions[ctx->current_action];
+    if (ctx->remaining_data == 0 && action->status == APR_EAGAIN) {
+        ctx->remaining_times--;
+        action->times--;
+    }
+
+    return APR_SUCCESS;
+}
+
+const serf_bucket_type_t serf_bucket_type_mock = {
+    "MOCK",
+    serf_mock_read,
+    serf_mock_readline,
+    serf_default_read_iovec,
+    serf_default_read_for_sendfile,
+    serf_default_read_bucket,
+    serf_mock_peek,
+    serf_default_destroy_and_data,
+};
+
+
+/* internal test for the mock buckets */
+static void test_basic_mock_bucket(CuTest *tc)
+{
+    serf_bucket_t *mock_bkt;
+    apr_pool_t *test_pool = tc->testBaton;
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+                                                              NULL);
+    /* read one line */
+    {
+        mockbkt_action actions[]= {
+            { 1, "HTTP/1.1 200 OK" CRLF, APR_EOF },
+        };
+        mock_bkt = serf_bucket_mock_create(actions, 1, alloc);
+        read_and_check_bucket(tc, mock_bkt,
+                              "HTTP/1.1 200 OK" CRLF);
+
+        mock_bkt = serf_bucket_mock_create(actions, 1, alloc);
+        readlines_and_check_bucket(tc, mock_bkt, SERF_NEWLINE_CRLF,
+                                   "HTTP/1.1 200 OK" CRLF, 1);
+    }
+    /* read one line, character per character */
+    {
+        apr_status_t status;
+        const char *expected = "HTTP/1.1 200 OK" CRLF;
+        mockbkt_action actions[]= {
+            { 1, "HTTP/1.1 200 OK" CRLF, APR_EOF },
+        };
+        mock_bkt = serf_bucket_mock_create(actions, 1, alloc);
+        do
+        {
+            const char *data;
+            apr_size_t len;
+
+            status = serf_bucket_read(mock_bkt, 1, &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);
+            CuAssert(tc, "Read more data than requested.",
+                     len <= 1);
+
+            expected += len;
+        } while(!APR_STATUS_IS_EOF(status));
+        
+        CuAssert(tc, "Read less data than expected.", strlen(expected) == 0);
+    }
+    /* read multiple lines */
+    {
+        mockbkt_action actions[]= {
+            { 1, "HTTP/1.1 200 OK" CRLF, APR_SUCCESS },
+            { 1, "Content-Type: text/plain" CRLF, APR_EOF },
+        };
+        mock_bkt = serf_bucket_mock_create(actions, 2, alloc);
+        readlines_and_check_bucket(tc, mock_bkt, SERF_NEWLINE_CRLF,
+                                   "HTTP/1.1 200 OK" CRLF
+                                   "Content-Type: text/plain" CRLF, 2);
+    }
+    /* read empty line */
+    {
+        mockbkt_action actions[]= {
+            { 1, "HTTP/1.1 200 OK" CRLF, APR_SUCCESS },
+            { 1, "", APR_EAGAIN },
+            { 1, "Content-Type: text/plain" CRLF, APR_EOF },
+        };
+        mock_bkt = serf_bucket_mock_create(actions, 3, alloc);
+        read_and_check_bucket(tc, mock_bkt,
+                              "HTTP/1.1 200 OK" CRLF
+                              "Content-Type: text/plain" CRLF);
+        mock_bkt = serf_bucket_mock_create(actions, 3, alloc);
+        readlines_and_check_bucket(tc, mock_bkt, SERF_NEWLINE_CRLF,
+                                   "HTTP/1.1 200 OK" CRLF
+                                   "Content-Type: text/plain" CRLF, 2);
+    }
+    /* read empty line */
+    {
+        mockbkt_action actions[]= {
+            { 1, "HTTP/1.1 200 OK" CR, APR_SUCCESS },
+            { 1, "", APR_EAGAIN },
+            { 1, LF, APR_EOF },
+        };
+        mock_bkt = serf_bucket_mock_create(actions,
+                                           sizeof(actions)/sizeof(actions[0]),
+                                           alloc);
+        read_and_check_bucket(tc, mock_bkt,
+                              "HTTP/1.1 200 OK" CRLF);
+
+        mock_bkt = serf_bucket_mock_create(actions,
+                                           sizeof(actions)/sizeof(actions[0]),
+                                           alloc);
+        readlines_and_check_bucket(tc, mock_bkt, SERF_NEWLINE_CRLF,
+                                   "HTTP/1.1 200 OK" CRLF, 1);
+    }
+    /* test more_data_arrived */
+    {
+        apr_status_t status;
+        const char *data;
+        apr_size_t len;
+        int i;
+
+        mockbkt_action actions[]= {
+            { 1, "", APR_EAGAIN },
+            { 1, "blabla", APR_EOF },
+        };
+        mock_bkt = serf_bucket_mock_create(actions,
+                                           sizeof(actions)/sizeof(actions[0]),
+                                           alloc);
+
+        for (i = 0; i < 5; i++) {
+            status = serf_bucket_peek(mock_bkt, &data, &len);
+            CuAssertIntEquals(tc, APR_SUCCESS, status);
+            CuAssertIntEquals(tc, 0, len);
+            CuAssertIntEquals(tc, '\0', *data);
+        }
+
+        serf_bucket_mock_more_data_arrived(mock_bkt);
+
+        status = serf_bucket_peek(mock_bkt, &data, &len);
+        CuAssertIntEquals(tc, APR_EOF, status);
+        CuAssertIntEquals(tc, 6, len);
+        CuAssert(tc, "Read data is not equal to expected.",
+                 strncmp("blabla", data, len) == 0);
+    }
+}
+
+CuSuite *test_mock_bucket(void)
+{
+    CuSuite *suite = CuSuiteNew();
+
+    CuSuiteSetSetupTeardownCallbacks(suite, test_setup, test_teardown);
+
+    SUITE_ADD_TEST(suite, test_basic_mock_bucket);
+
+    return suite;
+}

Deleted: vendor/serf/1.3.9/test/serf_bwtp.c
===================================================================
--- vendor/serf/dist/test/serf_bwtp.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/test/serf_bwtp.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,635 +0,0 @@
-/* Copyright 2002-2004 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_uri.h>
-#include <apr_strings.h>
-#include <apr_atomic.h>
-#include <apr_base64.h>
-#include <apr_getopt.h>
-#include <apr_version.h>
-
-#include "serf.h"
-
-typedef struct {
-    int count;
-    int using_ssl;
-    serf_ssl_context_t *ssl_ctx;
-    serf_bucket_alloc_t *bkt_alloc;
-} app_baton_t;
-
-typedef struct {
-#if APR_MAJOR_VERSION > 0
-    apr_uint32_t requests_outstanding;
-#else
-    apr_atomic_t requests_outstanding;
-#endif
-    int print_headers;
-
-    serf_response_acceptor_t acceptor;
-    app_baton_t *acceptor_baton;
-
-    serf_response_handler_t handler;
-
-    const char *host;
-    const char *method;
-    const char *path;
-    const char *req_body_path;
-    const char *authn;
-} handler_baton_t;
-
-/* Kludges for APR 0.9 support. */
-#if APR_MAJOR_VERSION == 0
-#define apr_atomic_inc32 apr_atomic_inc
-#define apr_atomic_dec32 apr_atomic_dec
-#define apr_atomic_read32 apr_atomic_read
-#endif
-
-static void closed_connection(serf_connection_t *conn,
-                              void *closed_baton,
-                              apr_status_t why,
-                              apr_pool_t *pool)
-{
-    if (why) {
-        abort();
-    }
-}
-
-static apr_status_t ignore_all_cert_errors(void *data, int failures,
-                                           const serf_ssl_certificate_t *cert)
-{
-    /* In a real application, you would normally would not want to do this */
-    return APR_SUCCESS;
-}
-
-static apr_status_t conn_setup(apr_socket_t *skt,
-                                serf_bucket_t **input_bkt,
-                                serf_bucket_t **output_bkt,
-                                void *setup_baton,
-                                apr_pool_t *pool)
-{
-    serf_bucket_t *c;
-    app_baton_t *ctx = setup_baton;
-
-    c = serf_bucket_socket_create(skt, ctx->bkt_alloc);
-    if (ctx->using_ssl) {
-        c = serf_bucket_ssl_decrypt_create(c, ctx->ssl_ctx, ctx->bkt_alloc);
-        if (!ctx->ssl_ctx) {
-            ctx->ssl_ctx = serf_bucket_ssl_decrypt_context_get(c);
-        }
-        serf_ssl_server_cert_callback_set(ctx->ssl_ctx, ignore_all_cert_errors, NULL);
-
-        *output_bkt = serf_bucket_ssl_encrypt_create(*output_bkt, ctx->ssl_ctx,
-                                                    ctx->bkt_alloc);
-    }
-
-    *input_bkt = c;
-
-    return APR_SUCCESS;
-}
-
-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;
-
-    /* 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);
-
-    return serf_bucket_response_create(c, bkt_alloc);
-}
-
-static serf_bucket_t* accept_bwtp(serf_request_t *request,
-                                  serf_bucket_t *stream,
-                                  void *acceptor_baton,
-                                  apr_pool_t *pool)
-{
-    serf_bucket_t *c;
-    app_baton_t *app_ctx = acceptor_baton;
-
-    /* Create a barrier so the response doesn't eat us! */
-    c = serf_bucket_barrier_create(stream, app_ctx->bkt_alloc);
-
-    return serf_bucket_bwtp_incoming_frame_create(c, app_ctx->bkt_alloc);
-}
-
-/* fwd declare */
-static apr_status_t handle_bwtp_upgrade(serf_request_t *request,
-                                        serf_bucket_t *response,
-                                        void *handler_baton,
-                                        apr_pool_t *pool);
-
-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 *hdrs_bkt;
-    serf_bucket_t *body_bkt;
-
-    if (ctx->req_body_path) {
-        apr_file_t *file;
-        apr_status_t status;
-
-        status = apr_file_open(&file, ctx->req_body_path, APR_READ,
-                               APR_OS_DEFAULT, pool);
-
-        if (status) {
-            printf("Error opening file (%s)\n", ctx->req_body_path);
-            return status;
-        }
-
-        body_bkt = serf_bucket_file_create(file,
-                                           serf_request_get_alloc(request));
-    }
-    else {
-        body_bkt = NULL;
-    }
-
-    /*
-    *req_bkt = serf_bucket_bwtp_message_create(0, body_bkt,
-                                               serf_request_get_alloc(request));
-    */
-
-    *req_bkt = serf_bucket_bwtp_header_create(0, "MESSAGE",
-                                              serf_request_get_alloc(request));
-
-    hdrs_bkt = serf_bucket_bwtp_frame_get_headers(*req_bkt);
-
-    /* FIXME: Shouldn't we be able to figure out the host ourselves? */
-    serf_bucket_headers_setn(hdrs_bkt, "Host", ctx->host);
-    serf_bucket_headers_setn(hdrs_bkt, "User-Agent",
-                             "Serf/" SERF_VERSION_STRING);
-    /* Shouldn't serf do this for us? */
-    serf_bucket_headers_setn(hdrs_bkt, "Accept-Encoding", "gzip");
-
-    if (ctx->authn != NULL) {
-        serf_bucket_headers_setn(hdrs_bkt, "Authorization", ctx->authn);
-    }
-
-    *acceptor = ctx->acceptor;
-    *acceptor_baton = ctx->acceptor_baton;
-    *handler = ctx->handler;
-    *handler_baton = ctx;
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t setup_bwtp_upgrade(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)
-{
-    serf_bucket_t *hdrs_bkt;
-    handler_baton_t *ctx = setup_baton;
-
-    *req_bkt = serf_bucket_request_create("OPTIONS", "*", NULL,
-                                          serf_request_get_alloc(request));
-
-    hdrs_bkt = serf_bucket_request_get_headers(*req_bkt);
-
-    serf_bucket_headers_setn(hdrs_bkt, "Upgrade", "BWTP/1.0");
-    serf_bucket_headers_setn(hdrs_bkt, "Connection", "Upgrade");
-
-    *acceptor = ctx->acceptor;
-    *acceptor_baton = ctx->acceptor_baton;
-    *handler = handle_bwtp_upgrade;
-    *handler_baton = ctx;
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t setup_channel(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 *hdrs_bkt;
-
-    *req_bkt = serf_bucket_bwtp_channel_open(0, ctx->path,
-                                             serf_request_get_alloc(request));
-
-    hdrs_bkt = serf_bucket_bwtp_frame_get_headers(*req_bkt);
-
-    /* FIXME: Shouldn't we be able to figure out the host ourselves? */
-    serf_bucket_headers_setn(hdrs_bkt, "Host", ctx->host);
-    serf_bucket_headers_setn(hdrs_bkt, "User-Agent",
-                             "Serf/" SERF_VERSION_STRING);
-    /* Shouldn't serf do this for us? */
-    serf_bucket_headers_setn(hdrs_bkt, "Accept-Encoding", "gzip");
-
-    if (ctx->authn != NULL) {
-        serf_bucket_headers_setn(hdrs_bkt, "Authorization", ctx->authn);
-    }
-
-    *acceptor = ctx->acceptor;
-    *acceptor_baton = ctx->acceptor_baton;
-    *handler = ctx->handler;
-    *handler_baton = ctx;
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t setup_close(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;
-
-    *req_bkt = serf_bucket_bwtp_channel_close(0, serf_request_get_alloc(request));
-
-    *acceptor = ctx->acceptor;
-    *acceptor_baton = ctx->acceptor_baton;
-    *handler = ctx->handler;
-    *handler_baton = ctx;
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t handle_bwtp(serf_request_t *request,
-                                serf_bucket_t *response,
-                                void *handler_baton,
-                                apr_pool_t *pool)
-{
-    const char *data;
-    apr_size_t len;
-    apr_status_t status;
-
-    if (!response) {
-        /* A NULL response can come back if the request failed completely */
-        return APR_EGENERAL;
-    }
-    status = serf_bucket_bwtp_incoming_frame_wait_for_headers(response);
-    if (SERF_BUCKET_READ_ERROR(status) || APR_STATUS_IS_EAGAIN(status)) {
-        return status;
-    }
-    printf("BWTP %p frame: %d %d %s\n",
-           response, serf_bucket_bwtp_frame_get_channel(response),
-           serf_bucket_bwtp_frame_get_type(response),
-           serf_bucket_bwtp_frame_get_phrase(response));
-
-
-    while (1) {
-        status = serf_bucket_read(response, 2048, &data, &len);
-        if (SERF_BUCKET_READ_ERROR(status))
-            return status;
-
-        /* got some data. print it out. */
-        if (len) {
-            puts("BWTP body:\n---");
-            fwrite(data, 1, len, stdout);
-            puts("\n---");
-        }
-
-        /* are we done yet? */
-        if (APR_STATUS_IS_EOF(status)) {
-            return APR_EOF;
-        }
-
-        /* have we drained the response so far? */
-        if (APR_STATUS_IS_EAGAIN(status))
-            return status;
-
-        /* loop to read some more. */
-    }
-    /* NOTREACHED */
-}
-
-static apr_status_t handle_bwtp_upgrade(serf_request_t *request,
-                                        serf_bucket_t *response,
-                                        void *handler_baton,
-                                        apr_pool_t *pool)
-{
-    const char *data;
-    apr_size_t len;
-    serf_status_line sl;
-    apr_status_t status;
-    handler_baton_t *ctx = handler_baton;
-
-    if (!response) {
-        /* A NULL response can come back if the request failed completely */
-        return APR_EGENERAL;
-    }
-    status = serf_bucket_response_status(response, &sl);
-    if (status) {
-        return status;
-    }
-
-    while (1) {
-        status = serf_bucket_read(response, 2048, &data, &len);
-        if (SERF_BUCKET_READ_ERROR(status))
-            return status;
-
-        /* got some data. print it out. */
-        fwrite(data, 1, len, stdout);
-
-        /* are we done yet? */
-        if (APR_STATUS_IS_EOF(status)) {
-            int i;
-            serf_connection_t *conn;
-            serf_request_t *new_req;
-
-            conn = serf_request_get_conn(request);
-
-            serf_connection_set_async_responses(conn,
-                accept_bwtp, ctx->acceptor_baton, handle_bwtp, NULL);
-
-            new_req = serf_connection_request_create(conn, setup_channel, ctx);
-            for (i = 0; i < ctx->acceptor_baton->count; i++) {
-                new_req = serf_connection_request_create(conn,
-                                                         setup_request,
-                                                         ctx);
-            }
-
-            return APR_EOF;
-        }
-
-        /* have we drained the response so far? */
-        if (APR_STATUS_IS_EAGAIN(status))
-            return status;
-
-        /* loop to read some more. */
-    }
-    /* NOTREACHED */
-}
-
-static apr_status_t handle_response(serf_request_t *request,
-                                    serf_bucket_t *response,
-                                    void *handler_baton,
-                                    apr_pool_t *pool)
-{
-    const char *data;
-    apr_size_t len;
-    serf_status_line sl;
-    apr_status_t status;
-    handler_baton_t *ctx = handler_baton;
-
-    if (!response) {
-        /* A NULL response can come back if the request failed completely */
-        return APR_EGENERAL;
-    }
-    status = serf_bucket_response_status(response, &sl);
-    if (status) {
-        return status;
-    }
-
-    while (1) {
-        status = serf_bucket_read(response, 2048, &data, &len);
-        if (SERF_BUCKET_READ_ERROR(status))
-            return status;
-
-        /* got some data. print it out. */
-        fwrite(data, 1, len, stdout);
-
-        /* are we done yet? */
-        if (APR_STATUS_IS_EOF(status)) {
-            if (ctx->print_headers) {
-                serf_bucket_t *hdrs;
-                hdrs = serf_bucket_response_get_headers(response);
-                while (1) {
-                    status = serf_bucket_read(hdrs, 2048, &data, &len);
-                    if (SERF_BUCKET_READ_ERROR(status))
-                        return status;
-
-                    fwrite(data, 1, len, stdout);
-                    if (APR_STATUS_IS_EOF(status)) {
-                        break;
-                    }
-                }
-            }
-
-            apr_atomic_dec32(&ctx->requests_outstanding);
-            if (!ctx->requests_outstanding) {
-                serf_connection_t *conn;
-                serf_request_t *new_req;
-
-                conn = serf_request_get_conn(request);
-                new_req =
-                    serf_connection_request_create(conn, setup_close, ctx);
-            }
-            return APR_EOF;
-        }
-
-        /* have we drained the response so far? */
-        if (APR_STATUS_IS_EAGAIN(status))
-            return status;
-
-        /* loop to read some more. */
-    }
-    /* NOTREACHED */
-}
-
-static void print_usage(apr_pool_t *pool)
-{
-    puts("serf_get [options] URL");
-    puts("-h\tDisplay this help");
-    puts("-v\tDisplay version");
-    puts("-H\tPrint response headers");
-    puts("-n <count> Fetch URL <count> times");
-    puts("-a <user:password> Present Basic authentication credentials");
-    puts("-m <method> Use the <method> HTTP Method");
-    puts("-f <file> Use the <file> as the request body");
-}
-
-int main(int argc, const char **argv)
-{
-    apr_status_t status;
-    apr_pool_t *pool;
-    apr_sockaddr_t *address;
-    serf_context_t *context;
-    serf_connection_t *connection;
-    serf_request_t *request;
-    app_baton_t app_ctx;
-    handler_baton_t handler_ctx;
-    apr_uri_t url;
-    const char *raw_url, *method, *req_body_path = NULL;
-    int i;
-    int print_headers;
-    char *authn = NULL;
-    apr_getopt_t *opt;
-    char opt_c;
-    const char *opt_arg;
-
-    apr_initialize();
-    atexit(apr_terminate);
-
-    apr_pool_create(&pool, NULL);
-    /* serf_initialize(); */
-
-    /* Default to one round of fetching. */
-    app_ctx.count = 1;
-    /* Default to GET. */
-    method = "GET";
-    /* Do not print headers by default. */
-    print_headers = 0;
-
-    apr_getopt_init(&opt, pool, argc, argv);
-
-    while ((status = apr_getopt(opt, "a:f:hHm:n:v", &opt_c, &opt_arg)) ==
-           APR_SUCCESS) {
-        int srclen, enclen;
-
-        switch (opt_c) {
-        case 'a':
-            srclen = strlen(opt_arg);
-            enclen = apr_base64_encode_len(srclen);
-            authn = apr_palloc(pool, enclen + 6);
-            strcpy(authn, "Basic ");
-            (void) apr_base64_encode(&authn[6], opt_arg, srclen);
-            break;
-        case 'f':
-            req_body_path = opt_arg;
-            break;
-        case 'h':
-            print_usage(pool);
-            exit(0);
-            break;
-        case 'H':
-            print_headers = 1;
-            break;
-        case 'm':
-            method = opt_arg;
-            break;
-        case 'n':
-            errno = 0;
-            app_ctx.count = apr_strtoi64(opt_arg, NULL, 10);
-            if (errno) {
-                printf("Problem converting number of times to fetch URL (%d)\n",
-                       errno);
-                return errno;
-            }
-            break;
-        case 'v':
-            puts("Serf version: " SERF_VERSION_STRING);
-            exit(0);
-        default:
-            break;
-        }
-    }
-
-    if (opt->ind != opt->argc - 1) {
-        print_usage(pool);
-        exit(-1);
-    }
-
-    raw_url = argv[opt->ind];
-
-    apr_uri_parse(pool, raw_url, &url);
-    if (!url.port) {
-        url.port = apr_uri_port_of_scheme(url.scheme);
-    }
-    if (!url.path) {
-        url.path = "/";
-    }
-
-    if (strcasecmp(url.scheme, "https") == 0) {
-        app_ctx.using_ssl = 1;
-    }
-    else {
-        app_ctx.using_ssl = 0;
-    }
-
-    status = apr_sockaddr_info_get(&address,
-                                   url.hostname, APR_UNSPEC, url.port, 0,
-                                   pool);
-    if (status) {
-        printf("Error creating address: %d\n", status);
-        apr_pool_destroy(pool);
-        exit(1);
-    }
-
-    context = serf_context_create(pool);
-
-    /* ### Connection or Context should have an allocator? */
-    app_ctx.bkt_alloc = serf_bucket_allocator_create(pool, NULL, NULL);
-    app_ctx.ssl_ctx = NULL;
-
-    connection = serf_connection_create(context, address,
-                                        conn_setup, &app_ctx,
-                                        closed_connection, &app_ctx,
-                                        pool);
-
-    handler_ctx.requests_outstanding = 0;
-    handler_ctx.print_headers = print_headers;
-
-    handler_ctx.host = url.hostinfo;
-    handler_ctx.method = method;
-    handler_ctx.path = url.path;
-    handler_ctx.authn = authn;
-
-    handler_ctx.req_body_path = req_body_path;
-
-    handler_ctx.acceptor = accept_response;
-    handler_ctx.acceptor_baton = &app_ctx;
-    handler_ctx.handler = handle_response;
-
-    request = serf_connection_request_create(connection, setup_bwtp_upgrade,
-                                             &handler_ctx);
-
-    for (i = 0; i < app_ctx.count; i++) {
-        apr_atomic_inc32(&handler_ctx.requests_outstanding);
-    }
-
-    while (1) {
-        status = serf_context_run(context, SERF_DURATION_FOREVER, pool);
-        if (APR_STATUS_IS_TIMEUP(status))
-            continue;
-        if (status) {
-            char buf[200];
-
-            printf("Error running context: (%d) %s\n", status,
-                   apr_strerror(status, buf, sizeof(buf)));
-            apr_pool_destroy(pool);
-            exit(1);
-        }
-        if (!apr_atomic_read32(&handler_ctx.requests_outstanding)) {
-            break;
-        }
-        /* Debugging purposes only! */
-        serf_debug__closed_conn(app_ctx.bkt_alloc);
-    }
-
-    serf_connection_close(connection);
-
-    apr_pool_destroy(pool);
-    return 0;
-}

Copied: vendor/serf/1.3.9/test/serf_bwtp.c (from rev 9259, vendor/serf/dist/test/serf_bwtp.c)
===================================================================
--- vendor/serf/1.3.9/test/serf_bwtp.c	                        (rev 0)
+++ vendor/serf/1.3.9/test/serf_bwtp.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,640 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_uri.h>
+#include <apr_strings.h>
+#include <apr_atomic.h>
+#include <apr_base64.h>
+#include <apr_getopt.h>
+#include <apr_version.h>
+
+#include "serf.h"
+
+typedef struct {
+    int count;
+    int using_ssl;
+    serf_ssl_context_t *ssl_ctx;
+    serf_bucket_alloc_t *bkt_alloc;
+} app_baton_t;
+
+typedef struct {
+#if APR_MAJOR_VERSION > 0
+    apr_uint32_t requests_outstanding;
+#else
+    apr_atomic_t requests_outstanding;
+#endif
+    int print_headers;
+
+    serf_response_acceptor_t acceptor;
+    app_baton_t *acceptor_baton;
+
+    serf_response_handler_t handler;
+
+    const char *host;
+    const char *method;
+    const char *path;
+    const char *req_body_path;
+    const char *authn;
+} handler_baton_t;
+
+/* Kludges for APR 0.9 support. */
+#if APR_MAJOR_VERSION == 0
+#define apr_atomic_inc32 apr_atomic_inc
+#define apr_atomic_dec32 apr_atomic_dec
+#define apr_atomic_read32 apr_atomic_read
+#endif
+
+static void closed_connection(serf_connection_t *conn,
+                              void *closed_baton,
+                              apr_status_t why,
+                              apr_pool_t *pool)
+{
+    if (why) {
+        abort();
+    }
+}
+
+static apr_status_t ignore_all_cert_errors(void *data, int failures,
+                                           const serf_ssl_certificate_t *cert)
+{
+    /* In a real application, you would normally would not want to do this */
+    return APR_SUCCESS;
+}
+
+static apr_status_t conn_setup(apr_socket_t *skt,
+                                serf_bucket_t **input_bkt,
+                                serf_bucket_t **output_bkt,
+                                void *setup_baton,
+                                apr_pool_t *pool)
+{
+    serf_bucket_t *c;
+    app_baton_t *ctx = setup_baton;
+
+    c = serf_bucket_socket_create(skt, ctx->bkt_alloc);
+    if (ctx->using_ssl) {
+        c = serf_bucket_ssl_decrypt_create(c, ctx->ssl_ctx, ctx->bkt_alloc);
+        if (!ctx->ssl_ctx) {
+            ctx->ssl_ctx = serf_bucket_ssl_decrypt_context_get(c);
+        }
+        serf_ssl_server_cert_callback_set(ctx->ssl_ctx, ignore_all_cert_errors, NULL);
+
+        *output_bkt = serf_bucket_ssl_encrypt_create(*output_bkt, ctx->ssl_ctx,
+                                                    ctx->bkt_alloc);
+    }
+
+    *input_bkt = c;
+
+    return APR_SUCCESS;
+}
+
+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;
+
+    /* 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);
+
+    return serf_bucket_response_create(c, bkt_alloc);
+}
+
+static serf_bucket_t* accept_bwtp(serf_request_t *request,
+                                  serf_bucket_t *stream,
+                                  void *acceptor_baton,
+                                  apr_pool_t *pool)
+{
+    serf_bucket_t *c;
+    app_baton_t *app_ctx = acceptor_baton;
+
+    /* Create a barrier so the response doesn't eat us! */
+    c = serf_bucket_barrier_create(stream, app_ctx->bkt_alloc);
+
+    return serf_bucket_bwtp_incoming_frame_create(c, app_ctx->bkt_alloc);
+}
+
+/* fwd declare */
+static apr_status_t handle_bwtp_upgrade(serf_request_t *request,
+                                        serf_bucket_t *response,
+                                        void *handler_baton,
+                                        apr_pool_t *pool);
+
+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 *hdrs_bkt;
+    serf_bucket_t *body_bkt;
+
+    if (ctx->req_body_path) {
+        apr_file_t *file;
+        apr_status_t status;
+
+        status = apr_file_open(&file, ctx->req_body_path, APR_READ,
+                               APR_OS_DEFAULT, pool);
+
+        if (status) {
+            printf("Error opening file (%s)\n", ctx->req_body_path);
+            return status;
+        }
+
+        body_bkt = serf_bucket_file_create(file,
+                                           serf_request_get_alloc(request));
+    }
+    else {
+        body_bkt = NULL;
+    }
+
+    /*
+    *req_bkt = serf_bucket_bwtp_message_create(0, body_bkt,
+                                               serf_request_get_alloc(request));
+    */
+
+    *req_bkt = serf_bucket_bwtp_header_create(0, "MESSAGE",
+                                              serf_request_get_alloc(request));
+
+    hdrs_bkt = serf_bucket_bwtp_frame_get_headers(*req_bkt);
+
+    /* FIXME: Shouldn't we be able to figure out the host ourselves? */
+    serf_bucket_headers_setn(hdrs_bkt, "Host", ctx->host);
+    serf_bucket_headers_setn(hdrs_bkt, "User-Agent",
+                             "Serf/" SERF_VERSION_STRING);
+    /* Shouldn't serf do this for us? */
+    serf_bucket_headers_setn(hdrs_bkt, "Accept-Encoding", "gzip");
+
+    if (ctx->authn != NULL) {
+        serf_bucket_headers_setn(hdrs_bkt, "Authorization", ctx->authn);
+    }
+
+    *acceptor = ctx->acceptor;
+    *acceptor_baton = ctx->acceptor_baton;
+    *handler = ctx->handler;
+    *handler_baton = ctx;
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t setup_bwtp_upgrade(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)
+{
+    serf_bucket_t *hdrs_bkt;
+    handler_baton_t *ctx = setup_baton;
+
+    *req_bkt = serf_bucket_request_create("OPTIONS", "*", NULL,
+                                          serf_request_get_alloc(request));
+
+    hdrs_bkt = serf_bucket_request_get_headers(*req_bkt);
+
+    serf_bucket_headers_setn(hdrs_bkt, "Upgrade", "BWTP/1.0");
+    serf_bucket_headers_setn(hdrs_bkt, "Connection", "Upgrade");
+
+    *acceptor = ctx->acceptor;
+    *acceptor_baton = ctx->acceptor_baton;
+    *handler = handle_bwtp_upgrade;
+    *handler_baton = ctx;
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t setup_channel(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 *hdrs_bkt;
+
+    *req_bkt = serf_bucket_bwtp_channel_open(0, ctx->path,
+                                             serf_request_get_alloc(request));
+
+    hdrs_bkt = serf_bucket_bwtp_frame_get_headers(*req_bkt);
+
+    /* FIXME: Shouldn't we be able to figure out the host ourselves? */
+    serf_bucket_headers_setn(hdrs_bkt, "Host", ctx->host);
+    serf_bucket_headers_setn(hdrs_bkt, "User-Agent",
+                             "Serf/" SERF_VERSION_STRING);
+    /* Shouldn't serf do this for us? */
+    serf_bucket_headers_setn(hdrs_bkt, "Accept-Encoding", "gzip");
+
+    if (ctx->authn != NULL) {
+        serf_bucket_headers_setn(hdrs_bkt, "Authorization", ctx->authn);
+    }
+
+    *acceptor = ctx->acceptor;
+    *acceptor_baton = ctx->acceptor_baton;
+    *handler = ctx->handler;
+    *handler_baton = ctx;
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t setup_close(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;
+
+    *req_bkt = serf_bucket_bwtp_channel_close(0, serf_request_get_alloc(request));
+
+    *acceptor = ctx->acceptor;
+    *acceptor_baton = ctx->acceptor_baton;
+    *handler = ctx->handler;
+    *handler_baton = ctx;
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t handle_bwtp(serf_request_t *request,
+                                serf_bucket_t *response,
+                                void *handler_baton,
+                                apr_pool_t *pool)
+{
+    const char *data;
+    apr_size_t len;
+    apr_status_t status;
+
+    if (!response) {
+        /* A NULL response can come back if the request failed completely */
+        return APR_EGENERAL;
+    }
+    status = serf_bucket_bwtp_incoming_frame_wait_for_headers(response);
+    if (SERF_BUCKET_READ_ERROR(status) || APR_STATUS_IS_EAGAIN(status)) {
+        return status;
+    }
+    printf("BWTP %p frame: %d %d %s\n",
+           response, serf_bucket_bwtp_frame_get_channel(response),
+           serf_bucket_bwtp_frame_get_type(response),
+           serf_bucket_bwtp_frame_get_phrase(response));
+
+
+    while (1) {
+        status = serf_bucket_read(response, 2048, &data, &len);
+        if (SERF_BUCKET_READ_ERROR(status))
+            return status;
+
+        /* got some data. print it out. */
+        if (len) {
+            puts("BWTP body:\n---");
+            fwrite(data, 1, len, stdout);
+            puts("\n---");
+        }
+
+        /* are we done yet? */
+        if (APR_STATUS_IS_EOF(status)) {
+            return APR_EOF;
+        }
+
+        /* have we drained the response so far? */
+        if (APR_STATUS_IS_EAGAIN(status))
+            return status;
+
+        /* loop to read some more. */
+    }
+    /* NOTREACHED */
+}
+
+static apr_status_t handle_bwtp_upgrade(serf_request_t *request,
+                                        serf_bucket_t *response,
+                                        void *handler_baton,
+                                        apr_pool_t *pool)
+{
+    const char *data;
+    apr_size_t len;
+    serf_status_line sl;
+    apr_status_t status;
+    handler_baton_t *ctx = handler_baton;
+
+    if (!response) {
+        /* A NULL response can come back if the request failed completely */
+        return APR_EGENERAL;
+    }
+    status = serf_bucket_response_status(response, &sl);
+    if (status) {
+        return status;
+    }
+
+    while (1) {
+        status = serf_bucket_read(response, 2048, &data, &len);
+        if (SERF_BUCKET_READ_ERROR(status))
+            return status;
+
+        /* got some data. print it out. */
+        fwrite(data, 1, len, stdout);
+
+        /* are we done yet? */
+        if (APR_STATUS_IS_EOF(status)) {
+            int i;
+            serf_connection_t *conn;
+            serf_request_t *new_req;
+
+            conn = serf_request_get_conn(request);
+
+            serf_connection_set_async_responses(conn,
+                accept_bwtp, ctx->acceptor_baton, handle_bwtp, NULL);
+
+            new_req = serf_connection_request_create(conn, setup_channel, ctx);
+            for (i = 0; i < ctx->acceptor_baton->count; i++) {
+                new_req = serf_connection_request_create(conn,
+                                                         setup_request,
+                                                         ctx);
+            }
+
+            return APR_EOF;
+        }
+
+        /* have we drained the response so far? */
+        if (APR_STATUS_IS_EAGAIN(status))
+            return status;
+
+        /* loop to read some more. */
+    }
+    /* NOTREACHED */
+}
+
+static apr_status_t handle_response(serf_request_t *request,
+                                    serf_bucket_t *response,
+                                    void *handler_baton,
+                                    apr_pool_t *pool)
+{
+    const char *data;
+    apr_size_t len;
+    serf_status_line sl;
+    apr_status_t status;
+    handler_baton_t *ctx = handler_baton;
+
+    if (!response) {
+        /* A NULL response can come back if the request failed completely */
+        return APR_EGENERAL;
+    }
+    status = serf_bucket_response_status(response, &sl);
+    if (status) {
+        return status;
+    }
+
+    while (1) {
+        status = serf_bucket_read(response, 2048, &data, &len);
+        if (SERF_BUCKET_READ_ERROR(status))
+            return status;
+
+        /* got some data. print it out. */
+        fwrite(data, 1, len, stdout);
+
+        /* are we done yet? */
+        if (APR_STATUS_IS_EOF(status)) {
+            if (ctx->print_headers) {
+                serf_bucket_t *hdrs;
+                hdrs = serf_bucket_response_get_headers(response);
+                while (1) {
+                    status = serf_bucket_read(hdrs, 2048, &data, &len);
+                    if (SERF_BUCKET_READ_ERROR(status))
+                        return status;
+
+                    fwrite(data, 1, len, stdout);
+                    if (APR_STATUS_IS_EOF(status)) {
+                        break;
+                    }
+                }
+            }
+
+            apr_atomic_dec32(&ctx->requests_outstanding);
+            if (!ctx->requests_outstanding) {
+                serf_connection_t *conn;
+                serf_request_t *new_req;
+
+                conn = serf_request_get_conn(request);
+                new_req =
+                    serf_connection_request_create(conn, setup_close, ctx);
+            }
+            return APR_EOF;
+        }
+
+        /* have we drained the response so far? */
+        if (APR_STATUS_IS_EAGAIN(status))
+            return status;
+
+        /* loop to read some more. */
+    }
+    /* NOTREACHED */
+}
+
+static void print_usage(apr_pool_t *pool)
+{
+    puts("serf_get [options] URL");
+    puts("-h\tDisplay this help");
+    puts("-v\tDisplay version");
+    puts("-H\tPrint response headers");
+    puts("-n <count> Fetch URL <count> times");
+    puts("-a <user:password> Present Basic authentication credentials");
+    puts("-m <method> Use the <method> HTTP Method");
+    puts("-f <file> Use the <file> as the request body");
+}
+
+int main(int argc, const char **argv)
+{
+    apr_status_t status;
+    apr_pool_t *pool;
+    apr_sockaddr_t *address;
+    serf_context_t *context;
+    serf_connection_t *connection;
+    serf_request_t *request;
+    app_baton_t app_ctx;
+    handler_baton_t handler_ctx;
+    apr_uri_t url;
+    const char *raw_url, *method, *req_body_path = NULL;
+    int i;
+    int print_headers;
+    char *authn = NULL;
+    apr_getopt_t *opt;
+    char opt_c;
+    const char *opt_arg;
+
+    apr_initialize();
+    atexit(apr_terminate);
+
+    apr_pool_create(&pool, NULL);
+    /* serf_initialize(); */
+
+    /* Default to one round of fetching. */
+    app_ctx.count = 1;
+    /* Default to GET. */
+    method = "GET";
+    /* Do not print headers by default. */
+    print_headers = 0;
+
+    apr_getopt_init(&opt, pool, argc, argv);
+
+    while ((status = apr_getopt(opt, "a:f:hHm:n:v", &opt_c, &opt_arg)) ==
+           APR_SUCCESS) {
+        int srclen, enclen;
+
+        switch (opt_c) {
+        case 'a':
+            srclen = strlen(opt_arg);
+            enclen = apr_base64_encode_len(srclen);
+            authn = apr_palloc(pool, enclen + 6);
+            strcpy(authn, "Basic ");
+            (void) apr_base64_encode(&authn[6], opt_arg, srclen);
+            break;
+        case 'f':
+            req_body_path = opt_arg;
+            break;
+        case 'h':
+            print_usage(pool);
+            exit(0);
+            break;
+        case 'H':
+            print_headers = 1;
+            break;
+        case 'm':
+            method = opt_arg;
+            break;
+        case 'n':
+            errno = 0;
+            app_ctx.count = apr_strtoi64(opt_arg, NULL, 10);
+            if (errno) {
+                printf("Problem converting number of times to fetch URL (%d)\n",
+                       errno);
+                return errno;
+            }
+            break;
+        case 'v':
+            puts("Serf version: " SERF_VERSION_STRING);
+            exit(0);
+        default:
+            break;
+        }
+    }
+
+    if (opt->ind != opt->argc - 1) {
+        print_usage(pool);
+        exit(-1);
+    }
+
+    raw_url = argv[opt->ind];
+
+    apr_uri_parse(pool, raw_url, &url);
+    if (!url.port) {
+        url.port = apr_uri_port_of_scheme(url.scheme);
+    }
+    if (!url.path) {
+        url.path = "/";
+    }
+
+    if (strcasecmp(url.scheme, "https") == 0) {
+        app_ctx.using_ssl = 1;
+    }
+    else {
+        app_ctx.using_ssl = 0;
+    }
+
+    status = apr_sockaddr_info_get(&address,
+                                   url.hostname, APR_UNSPEC, url.port, 0,
+                                   pool);
+    if (status) {
+        printf("Error creating address: %d\n", status);
+        apr_pool_destroy(pool);
+        exit(1);
+    }
+
+    context = serf_context_create(pool);
+
+    /* ### Connection or Context should have an allocator? */
+    app_ctx.bkt_alloc = serf_bucket_allocator_create(pool, NULL, NULL);
+    app_ctx.ssl_ctx = NULL;
+
+    connection = serf_connection_create(context, address,
+                                        conn_setup, &app_ctx,
+                                        closed_connection, &app_ctx,
+                                        pool);
+
+    handler_ctx.requests_outstanding = 0;
+    handler_ctx.print_headers = print_headers;
+
+    handler_ctx.host = url.hostinfo;
+    handler_ctx.method = method;
+    handler_ctx.path = url.path;
+    handler_ctx.authn = authn;
+
+    handler_ctx.req_body_path = req_body_path;
+
+    handler_ctx.acceptor = accept_response;
+    handler_ctx.acceptor_baton = &app_ctx;
+    handler_ctx.handler = handle_response;
+
+    request = serf_connection_request_create(connection, setup_bwtp_upgrade,
+                                             &handler_ctx);
+
+    for (i = 0; i < app_ctx.count; i++) {
+        apr_atomic_inc32(&handler_ctx.requests_outstanding);
+    }
+
+    while (1) {
+        status = serf_context_run(context, SERF_DURATION_FOREVER, pool);
+        if (APR_STATUS_IS_TIMEUP(status))
+            continue;
+        if (status) {
+            char buf[200];
+
+            printf("Error running context: (%d) %s\n", status,
+                   apr_strerror(status, buf, sizeof(buf)));
+            apr_pool_destroy(pool);
+            exit(1);
+        }
+        if (!apr_atomic_read32(&handler_ctx.requests_outstanding)) {
+            break;
+        }
+        /* Debugging purposes only! */
+        serf_debug__closed_conn(app_ctx.bkt_alloc);
+    }
+
+    serf_connection_close(connection);
+
+    apr_pool_destroy(pool);
+    return 0;
+}

Deleted: vendor/serf/1.3.9/test/serf_get.c
===================================================================
--- vendor/serf/dist/test/serf_get.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/test/serf_get.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,681 +0,0 @@
-/* Copyright 2002-2004 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_uri.h>
-#include <apr_strings.h>
-#include <apr_atomic.h>
-#include <apr_base64.h>
-#include <apr_getopt.h>
-#include <apr_version.h>
-
-#include "serf.h"
-
-/* Add Connection: close header to each request. */
-/* #define CONNECTION_CLOSE_HDR */
-
-typedef struct {
-    const char *hostinfo;
-    int using_ssl;
-    int head_request;
-    serf_ssl_context_t *ssl_ctx;
-    serf_bucket_alloc_t *bkt_alloc;
-} app_baton_t;
-
-static void closed_connection(serf_connection_t *conn,
-                              void *closed_baton,
-                              apr_status_t why,
-                              apr_pool_t *pool)
-{
-    app_baton_t *ctx = closed_baton;
-
-    ctx->ssl_ctx = NULL;
-
-    if (why) {
-        abort();
-    }
-}
-
-static void print_ssl_cert_errors(int failures)
-{
-    if (failures) {
-        fprintf(stderr, "INVALID CERTIFICATE:\n");
-        if (failures & SERF_SSL_CERT_NOTYETVALID)
-            fprintf(stderr, "* The certificate is not yet valid.\n");
-        if (failures & SERF_SSL_CERT_EXPIRED)
-            fprintf(stderr, "* The certificate expired.\n");
-        if (failures & SERF_SSL_CERT_SELF_SIGNED)
-            fprintf(stderr, "* The certificate is self-signed.\n");
-        if (failures & SERF_SSL_CERT_UNKNOWNCA)
-            fprintf(stderr, "* The CA is unknown.\n");
-        if (failures & SERF_SSL_CERT_UNKNOWN_FAILURE)
-            fprintf(stderr, "* Unknown failure.\n");
-    }
-}
-
-static apr_status_t ignore_all_cert_errors(void *data, int failures,
-                                           const serf_ssl_certificate_t *cert)
-{
-    print_ssl_cert_errors(failures);
-
-     /* In a real application, you would normally would not want to do this */
-    return APR_SUCCESS;
-}
-
-static char *
-convert_organisation_to_str(apr_hash_t *org, apr_pool_t *pool)
-{
-    return apr_psprintf(pool, "%s, %s, %s, %s, %s (%s)",
-                        (char*)apr_hash_get(org, "OU", APR_HASH_KEY_STRING),
-                        (char*)apr_hash_get(org, "O", APR_HASH_KEY_STRING),
-                        (char*)apr_hash_get(org, "L", APR_HASH_KEY_STRING),
-                        (char*)apr_hash_get(org, "ST", APR_HASH_KEY_STRING),
-                        (char*)apr_hash_get(org, "C", APR_HASH_KEY_STRING),
-                        (char*)apr_hash_get(org, "E", APR_HASH_KEY_STRING));
-}
-
-static apr_status_t print_certs(void *data, int failures, int error_depth,
-                                const serf_ssl_certificate_t * const * certs,
-                                apr_size_t certs_len)
-{
-    apr_pool_t *pool;
-    const serf_ssl_certificate_t *current;
-
-    apr_pool_create(&pool, NULL);
-
-    fprintf(stderr, "Received certificate chain with length %d\n",
-            (int)certs_len);
-    print_ssl_cert_errors(failures);
-    if (failures)
-        fprintf(stderr, "Error at depth=%d\n", error_depth);
-    else
-        fprintf(stderr, "Chain provided with depth=%d\n", error_depth);
-
-    while ((current = *certs) != NULL)
-    {
-        apr_hash_t *issuer, *subject, *serf_cert;
-        apr_array_header_t *san;
-
-        subject = serf_ssl_cert_subject(current, pool);
-        issuer = serf_ssl_cert_issuer(current, pool);
-        serf_cert = serf_ssl_cert_certificate(current, pool);
-
-        fprintf(stderr, "\n-----BEGIN CERTIFICATE-----\n");
-        fprintf(stderr, "Hostname: %s\n",
-                (const char *)apr_hash_get(subject, "CN", APR_HASH_KEY_STRING));
-        fprintf(stderr, "Sha1: %s\n",
-                (const char *)apr_hash_get(serf_cert, "sha1", APR_HASH_KEY_STRING));
-        fprintf(stderr, "Valid from: %s\n",
-                (const char *)apr_hash_get(serf_cert, "notBefore", APR_HASH_KEY_STRING));
-        fprintf(stderr, "Valid until: %s\n",
-                (const char *)apr_hash_get(serf_cert, "notAfter", APR_HASH_KEY_STRING));
-        fprintf(stderr, "Issuer: %s\n", convert_organisation_to_str(issuer, pool));
-
-        san = apr_hash_get(serf_cert, "subjectAltName", APR_HASH_KEY_STRING);
-        if (san) {
-            int i;
-            for (i = 0; i < san->nelts; i++) {
-                char *s = APR_ARRAY_IDX(san, i, char*);
-                fprintf(stderr, "SubjectAltName: %s\n", s);
-            }
-        }
-
-        fprintf(stderr, "%s\n", serf_ssl_cert_export(current, pool));
-        fprintf(stderr, "-----END CERTIFICATE-----\n");
-        ++certs;
-    }
-
-    apr_pool_destroy(pool);
-    return APR_SUCCESS;
-}
-
-static apr_status_t conn_setup(apr_socket_t *skt,
-                                serf_bucket_t **input_bkt,
-                                serf_bucket_t **output_bkt,
-                                void *setup_baton,
-                                apr_pool_t *pool)
-{
-    serf_bucket_t *c;
-    app_baton_t *ctx = setup_baton;
-
-    c = serf_bucket_socket_create(skt, ctx->bkt_alloc);
-    if (ctx->using_ssl) {
-        c = serf_bucket_ssl_decrypt_create(c, ctx->ssl_ctx, ctx->bkt_alloc);
-        if (!ctx->ssl_ctx) {
-            ctx->ssl_ctx = serf_bucket_ssl_decrypt_context_get(c);
-        }
-        serf_ssl_server_cert_chain_callback_set(ctx->ssl_ctx, 
-                                                ignore_all_cert_errors, 
-                                                print_certs, NULL);
-        serf_ssl_set_hostname(ctx->ssl_ctx, ctx->hostinfo);
-
-        *output_bkt = serf_bucket_ssl_encrypt_create(*output_bkt, ctx->ssl_ctx,
-                                                    ctx->bkt_alloc);
-    }
-
-    *input_bkt = c;
-
-    return APR_SUCCESS;
-}
-
-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_t *response;
-    serf_bucket_alloc_t *bkt_alloc;
-    app_baton_t *app_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);
-
-    response = serf_bucket_response_create(c, bkt_alloc);
-
-    if (app_ctx->head_request)
-      serf_bucket_response_set_head(response);
-
-    return response;
-}
-
-typedef struct {
-#if APR_MAJOR_VERSION > 0
-    apr_uint32_t completed_requests;
-#else
-    apr_atomic_t completed_requests;
-#endif
-    int print_headers;
-    apr_file_t *output_file;
-
-    serf_response_acceptor_t acceptor;
-    app_baton_t *acceptor_baton;
-
-    serf_response_handler_t handler;
-
-    const char *host;
-    const char *method;
-    const char *path;
-    const char *req_body_path;
-    const char *username;
-    const char *password;
-    int auth_attempts;
-    serf_bucket_t *req_hdrs;
-} handler_baton_t;
-
-/* Kludges for APR 0.9 support. */
-#if APR_MAJOR_VERSION == 0
-#define apr_atomic_inc32 apr_atomic_inc
-#define apr_atomic_dec32 apr_atomic_dec
-#define apr_atomic_read32 apr_atomic_read
-#endif
-
-
-static int append_request_headers(void *baton,
-                                  const char *key,
-                                  const char *value)
-{
-    serf_bucket_t *hdrs_bkt = baton;
-    serf_bucket_headers_setc(hdrs_bkt, key, value);
-    return 0;
-}
-
-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 *hdrs_bkt;
-    serf_bucket_t *body_bkt;
-
-    if (ctx->req_body_path) {
-        apr_file_t *file;
-        apr_status_t status;
-
-        status = apr_file_open(&file, ctx->req_body_path, APR_READ,
-                               APR_OS_DEFAULT, pool);
-
-        if (status) {
-            printf("Error opening file (%s)\n", ctx->req_body_path);
-            return status;
-        }
-
-        body_bkt = serf_bucket_file_create(file,
-                                           serf_request_get_alloc(request));
-    }
-    else {
-        body_bkt = NULL;
-    }
-
-    *req_bkt = serf_request_bucket_request_create(request, ctx->method,
-                                                  ctx->path, body_bkt,
-                                                  serf_request_get_alloc(request));
-
-    hdrs_bkt = serf_bucket_request_get_headers(*req_bkt);
-
-    serf_bucket_headers_setn(hdrs_bkt, "User-Agent",
-                             "Serf/" SERF_VERSION_STRING);
-    /* Shouldn't serf do this for us? */
-    serf_bucket_headers_setn(hdrs_bkt, "Accept-Encoding", "gzip");
-#ifdef CONNECTION_CLOSE_HDR
-    serf_bucket_headers_setn(hdrs_bkt, "Connection", "close");
-#endif
-
-    /* Add the extra headers from the command line */
-    if (ctx->req_hdrs != NULL) {
-        serf_bucket_headers_do(ctx->req_hdrs, append_request_headers, hdrs_bkt);
-    }
-
-    *acceptor = ctx->acceptor;
-    *acceptor_baton = ctx->acceptor_baton;
-    *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)
-{
-    serf_status_line sl;
-    apr_status_t status;
-    handler_baton_t *ctx = handler_baton;
-
-    if (!response) {
-        /* A NULL response probably means that the connection was closed while
-           this request was already written. Just requeue it. */
-        serf_connection_t *conn = serf_request_get_conn(request);
-
-        serf_connection_request_create(conn, setup_request, handler_baton);
-        return APR_SUCCESS;
-    }
-
-    status = serf_bucket_response_status(response, &sl);
-    if (status) {
-        return status;
-    }
-
-    while (1) {
-        struct iovec vecs[64];
-        int vecs_read;
-        apr_size_t bytes_written;
-
-        status = serf_bucket_read_iovec(response, 8000, 64, vecs, &vecs_read);
-        if (SERF_BUCKET_READ_ERROR(status))
-            return status;
-
-        /* got some data. print it out. */
-        if (vecs_read) {
-            apr_file_writev(ctx->output_file, vecs, vecs_read, &bytes_written);
-        }
-
-        /* are we done yet? */
-        if (APR_STATUS_IS_EOF(status)) {
-            if (ctx->print_headers) {
-                serf_bucket_t *hdrs;
-                hdrs = serf_bucket_response_get_headers(response);
-                while (1) {
-                    status = serf_bucket_read_iovec(hdrs, 8000, 64, vecs,
-                                                    &vecs_read);
-
-                    if (SERF_BUCKET_READ_ERROR(status))
-                        return status;
-
-                    if (vecs_read) {
-                        apr_file_writev(ctx->output_file, vecs, vecs_read,
-                                        &bytes_written);
-                    }
-                    if (APR_STATUS_IS_EOF(status)) {
-                        break;
-                    }
-                }
-            }
-
-            apr_atomic_inc32(&ctx->completed_requests);
-            return APR_EOF;
-        }
-
-        /* have we drained the response so far? */
-        if (APR_STATUS_IS_EAGAIN(status))
-            return status;
-
-        /* loop to read some more. */
-    }
-    /* NOTREACHED */
-}
-
-static apr_status_t
-credentials_callback(char **username,
-                     char **password,
-                     serf_request_t *request, void *baton,
-                     int code, const char *authn_type,
-                     const char *realm,
-                     apr_pool_t *pool)
-{
-    handler_baton_t *ctx = baton;
-
-    if (ctx->auth_attempts > 0)
-    {
-        return SERF_ERROR_AUTHN_FAILED;
-    }
-    else
-    {
-        *username = (char*)ctx->username;
-        *password = (char*)ctx->password;
-        ctx->auth_attempts++;
-
-        return APR_SUCCESS;
-    }
-}
-
-static void print_usage(apr_pool_t *pool)
-{
-    puts("serf_get [options] URL");
-    puts("-h\tDisplay this help");
-    puts("-v\tDisplay version");
-    puts("-H\tPrint response headers");
-    puts("-n <count> Fetch URL <count> times");
-    puts("-x <count> Number of maximum outstanding requests inflight");
-    puts("-U <user> Username for Basic/Digest authentication");
-    puts("-P <password> Password for Basic/Digest authentication");
-    puts("-m <method> Use the <method> HTTP Method");
-    puts("-f <file> Use the <file> as the request body");
-    puts("-p <hostname:port> Use the <host:port> as proxy server");
-    puts("-r <header:value> Use <header:value> as request header");
-}
-
-int main(int argc, const char **argv)
-{
-    apr_status_t status;
-    apr_pool_t *pool;
-    serf_bucket_alloc_t *bkt_alloc;
-    serf_context_t *context;
-    serf_connection_t *connection;
-    serf_request_t *request;
-    app_baton_t app_ctx;
-    handler_baton_t handler_ctx;
-    serf_bucket_t *req_hdrs = NULL;
-    apr_uri_t url;
-    const char *proxy = NULL;
-    const char *raw_url, *method, *req_body_path = NULL;
-    int count, inflight;
-    int i;
-    int print_headers;
-    const char *username = NULL;
-    const char *password = "";
-    apr_getopt_t *opt;
-    char opt_c;
-    const char *opt_arg;
-
-    apr_initialize();
-    atexit(apr_terminate);
-
-    apr_pool_create(&pool, NULL);
-    /* serf_initialize(); */
-    bkt_alloc = serf_bucket_allocator_create(pool, NULL, NULL);
-
-    /* Default to one round of fetching with no limit to max inflight reqs. */
-    count = 1;
-    inflight = 0;
-    /* Default to GET. */
-    method = "GET";
-    /* Do not print headers by default. */
-    print_headers = 0;
-
-    apr_getopt_init(&opt, pool, argc, argv);
-
-    while ((status = apr_getopt(opt, "U:P:f:hHm:n:vp:x:r:", &opt_c, &opt_arg)) ==
-           APR_SUCCESS) {
-
-        switch (opt_c) {
-        case 'U':
-            username = opt_arg;
-            break;
-        case 'P':
-            password = opt_arg;
-            break;
-        case 'f':
-            req_body_path = opt_arg;
-            break;
-        case 'h':
-            print_usage(pool);
-            exit(0);
-            break;
-        case 'H':
-            print_headers = 1;
-            break;
-        case 'm':
-            method = opt_arg;
-            break;
-        case 'n':
-            errno = 0;
-            count = apr_strtoi64(opt_arg, NULL, 10);
-            if (errno) {
-                printf("Problem converting number of times to fetch URL (%d)\n",
-                       errno);
-                return errno;
-            }
-            break;
-        case 'x':
-            errno = 0;
-            inflight = apr_strtoi64(opt_arg, NULL, 10);
-            if (errno) {
-                printf("Problem converting number of requests to have outstanding (%d)\n",
-                       errno);
-                return errno;
-            }
-            break;
-        case 'p':
-            proxy = opt_arg;
-            break;
-        case 'r':
-            {
-                char *sep;
-                char *hdr_val;
-
-                if (req_hdrs == NULL) {
-                    /* first request header, allocate bucket */
-                    req_hdrs = serf_bucket_headers_create(bkt_alloc);
-                }
-                sep = strchr(opt_arg, ':');
-                if ((sep == NULL) || (sep == opt_arg) || (strlen(sep) <= 1)) {
-                    printf("Invalid request header string (%s)\n", opt_arg);
-                    return EINVAL;
-                }
-                hdr_val = sep + 1;
-                while (*hdr_val == ' ') {
-                    hdr_val++;
-                }
-                serf_bucket_headers_setx(req_hdrs, opt_arg, (sep - opt_arg), 1,
-                                         hdr_val, strlen(hdr_val), 1);
-            }
-            break;
-        case 'v':
-            puts("Serf version: " SERF_VERSION_STRING);
-            exit(0);
-        default:
-            break;
-        }
-    }
-
-    if (opt->ind != opt->argc - 1) {
-        print_usage(pool);
-        exit(-1);
-    }
-
-    raw_url = argv[opt->ind];
-
-    apr_uri_parse(pool, raw_url, &url);
-    if (!url.port) {
-        url.port = apr_uri_port_of_scheme(url.scheme);
-    }
-    if (!url.path) {
-        url.path = "/";
-    }
-
-    if (strcasecmp(url.scheme, "https") == 0) {
-        app_ctx.using_ssl = 1;
-    }
-    else {
-        app_ctx.using_ssl = 0;
-    }
-
-    if (strcasecmp(method, "HEAD") == 0) {
-        app_ctx.head_request = 1;
-    }
-    else {
-        app_ctx.head_request = 0;
-    }
-
-    app_ctx.hostinfo = url.hostinfo;
-
-    context = serf_context_create(pool);
-
-    if (proxy)
-    {
-        apr_sockaddr_t *proxy_address = NULL;
-        apr_port_t proxy_port;
-        char *proxy_host;
-        char *proxy_scope;
-
-        status = apr_parse_addr_port(&proxy_host, &proxy_scope, &proxy_port, proxy, pool);
-        if (status)
-        {
-            printf("Cannot parse proxy hostname/port: %d\n", status);
-            apr_pool_destroy(pool);
-            exit(1);
-        }
-
-        if (!proxy_host)
-        {
-            printf("Proxy hostname must be specified\n");
-            apr_pool_destroy(pool);
-            exit(1);
-        }
-
-        if (!proxy_port)
-        {
-            printf("Proxy port must be specified\n");
-            apr_pool_destroy(pool);
-            exit(1);
-        }
-
-        status = apr_sockaddr_info_get(&proxy_address, proxy_host, APR_UNSPEC,
-                                       proxy_port, 0, pool);
-
-        if (status)
-        {
-            printf("Cannot resolve proxy address '%s': %d\n", proxy_host, status);
-            apr_pool_destroy(pool);
-            exit(1);
-        }
-
-        serf_config_proxy(context, proxy_address);
-    }
-
-    if (username)
-    {
-        serf_config_authn_types(context, SERF_AUTHN_ALL);
-    }
-    else
-    {
-        serf_config_authn_types(context, SERF_AUTHN_NTLM | SERF_AUTHN_NEGOTIATE);
-    }
-
-    serf_config_credentials_callback(context, credentials_callback);
-
-    /* ### Connection or Context should have an allocator? */
-    app_ctx.bkt_alloc = bkt_alloc;
-    app_ctx.ssl_ctx = NULL;
-
-    status = serf_connection_create2(&connection, context, url,
-                                     conn_setup, &app_ctx,
-                                     closed_connection, &app_ctx,
-                                     pool);
-    if (status) {
-        printf("Error creating connection: %d\n", status);
-        apr_pool_destroy(pool);
-        exit(1);
-    }
-
-    handler_ctx.completed_requests = 0;
-    handler_ctx.print_headers = print_headers;
-    apr_file_open_stdout(&handler_ctx.output_file, pool);
-
-    handler_ctx.host = url.hostinfo;
-    handler_ctx.method = method;
-    handler_ctx.path = apr_pstrcat(pool,
-                                   url.path,
-                                   url.query ? "?" : "",
-                                   url.query ? url.query : "",
-                                   NULL);
-    handler_ctx.username = username;
-    handler_ctx.password = password;
-    handler_ctx.auth_attempts = 0;
-
-    handler_ctx.req_body_path = req_body_path;
-
-    handler_ctx.acceptor = accept_response;
-    handler_ctx.acceptor_baton = &app_ctx;
-    handler_ctx.handler = handle_response;
-    handler_ctx.req_hdrs = req_hdrs;
-
-    serf_connection_set_max_outstanding_requests(connection, inflight);
-
-    for (i = 0; i < count; i++) {
-        request = serf_connection_request_create(connection, setup_request,
-                                                 &handler_ctx);
-    }
-
-    while (1) {
-        status = serf_context_run(context, SERF_DURATION_FOREVER, pool);
-        if (APR_STATUS_IS_TIMEUP(status))
-            continue;
-        if (status) {
-            char buf[200];
-            const char *err_string;
-            err_string = serf_error_string(status);
-            if (!err_string) {
-                err_string = apr_strerror(status, buf, sizeof(buf));
-            }
-
-            printf("Error running context: (%d) %s\n", status, err_string);
-            apr_pool_destroy(pool);
-            exit(1);
-        }
-        if (apr_atomic_read32(&handler_ctx.completed_requests) >= count) {
-            break;
-        }
-        /* Debugging purposes only! */
-        serf_debug__closed_conn(app_ctx.bkt_alloc);
-    }
-
-    serf_connection_close(connection);
-
-    apr_pool_destroy(pool);
-    return 0;
-}

Copied: vendor/serf/1.3.9/test/serf_get.c (from rev 9259, vendor/serf/dist/test/serf_get.c)
===================================================================
--- vendor/serf/1.3.9/test/serf_get.c	                        (rev 0)
+++ vendor/serf/1.3.9/test/serf_get.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,686 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_uri.h>
+#include <apr_strings.h>
+#include <apr_atomic.h>
+#include <apr_base64.h>
+#include <apr_getopt.h>
+#include <apr_version.h>
+
+#include "serf.h"
+
+/* Add Connection: close header to each request. */
+/* #define CONNECTION_CLOSE_HDR */
+
+typedef struct {
+    const char *hostinfo;
+    int using_ssl;
+    int head_request;
+    serf_ssl_context_t *ssl_ctx;
+    serf_bucket_alloc_t *bkt_alloc;
+} app_baton_t;
+
+static void closed_connection(serf_connection_t *conn,
+                              void *closed_baton,
+                              apr_status_t why,
+                              apr_pool_t *pool)
+{
+    app_baton_t *ctx = closed_baton;
+
+    ctx->ssl_ctx = NULL;
+
+    if (why) {
+        abort();
+    }
+}
+
+static void print_ssl_cert_errors(int failures)
+{
+    if (failures) {
+        fprintf(stderr, "INVALID CERTIFICATE:\n");
+        if (failures & SERF_SSL_CERT_NOTYETVALID)
+            fprintf(stderr, "* The certificate is not yet valid.\n");
+        if (failures & SERF_SSL_CERT_EXPIRED)
+            fprintf(stderr, "* The certificate expired.\n");
+        if (failures & SERF_SSL_CERT_SELF_SIGNED)
+            fprintf(stderr, "* The certificate is self-signed.\n");
+        if (failures & SERF_SSL_CERT_UNKNOWNCA)
+            fprintf(stderr, "* The CA is unknown.\n");
+        if (failures & SERF_SSL_CERT_UNKNOWN_FAILURE)
+            fprintf(stderr, "* Unknown failure.\n");
+    }
+}
+
+static apr_status_t ignore_all_cert_errors(void *data, int failures,
+                                           const serf_ssl_certificate_t *cert)
+{
+    print_ssl_cert_errors(failures);
+
+     /* In a real application, you would normally would not want to do this */
+    return APR_SUCCESS;
+}
+
+static char *
+convert_organisation_to_str(apr_hash_t *org, apr_pool_t *pool)
+{
+    return apr_psprintf(pool, "%s, %s, %s, %s, %s (%s)",
+                        (char*)apr_hash_get(org, "OU", APR_HASH_KEY_STRING),
+                        (char*)apr_hash_get(org, "O", APR_HASH_KEY_STRING),
+                        (char*)apr_hash_get(org, "L", APR_HASH_KEY_STRING),
+                        (char*)apr_hash_get(org, "ST", APR_HASH_KEY_STRING),
+                        (char*)apr_hash_get(org, "C", APR_HASH_KEY_STRING),
+                        (char*)apr_hash_get(org, "E", APR_HASH_KEY_STRING));
+}
+
+static apr_status_t print_certs(void *data, int failures, int error_depth,
+                                const serf_ssl_certificate_t * const * certs,
+                                apr_size_t certs_len)
+{
+    apr_pool_t *pool;
+    const serf_ssl_certificate_t *current;
+
+    apr_pool_create(&pool, NULL);
+
+    fprintf(stderr, "Received certificate chain with length %d\n",
+            (int)certs_len);
+    print_ssl_cert_errors(failures);
+    if (failures)
+        fprintf(stderr, "Error at depth=%d\n", error_depth);
+    else
+        fprintf(stderr, "Chain provided with depth=%d\n", error_depth);
+
+    while ((current = *certs) != NULL)
+    {
+        apr_hash_t *issuer, *subject, *serf_cert;
+        apr_array_header_t *san;
+
+        subject = serf_ssl_cert_subject(current, pool);
+        issuer = serf_ssl_cert_issuer(current, pool);
+        serf_cert = serf_ssl_cert_certificate(current, pool);
+
+        fprintf(stderr, "\n-----BEGIN CERTIFICATE-----\n");
+        fprintf(stderr, "Hostname: %s\n",
+                (const char *)apr_hash_get(subject, "CN", APR_HASH_KEY_STRING));
+        fprintf(stderr, "Sha1: %s\n",
+                (const char *)apr_hash_get(serf_cert, "sha1", APR_HASH_KEY_STRING));
+        fprintf(stderr, "Valid from: %s\n",
+                (const char *)apr_hash_get(serf_cert, "notBefore", APR_HASH_KEY_STRING));
+        fprintf(stderr, "Valid until: %s\n",
+                (const char *)apr_hash_get(serf_cert, "notAfter", APR_HASH_KEY_STRING));
+        fprintf(stderr, "Issuer: %s\n", convert_organisation_to_str(issuer, pool));
+
+        san = apr_hash_get(serf_cert, "subjectAltName", APR_HASH_KEY_STRING);
+        if (san) {
+            int i;
+            for (i = 0; i < san->nelts; i++) {
+                char *s = APR_ARRAY_IDX(san, i, char*);
+                fprintf(stderr, "SubjectAltName: %s\n", s);
+            }
+        }
+
+        fprintf(stderr, "%s\n", serf_ssl_cert_export(current, pool));
+        fprintf(stderr, "-----END CERTIFICATE-----\n");
+        ++certs;
+    }
+
+    apr_pool_destroy(pool);
+    return APR_SUCCESS;
+}
+
+static apr_status_t conn_setup(apr_socket_t *skt,
+                                serf_bucket_t **input_bkt,
+                                serf_bucket_t **output_bkt,
+                                void *setup_baton,
+                                apr_pool_t *pool)
+{
+    serf_bucket_t *c;
+    app_baton_t *ctx = setup_baton;
+
+    c = serf_bucket_socket_create(skt, ctx->bkt_alloc);
+    if (ctx->using_ssl) {
+        c = serf_bucket_ssl_decrypt_create(c, ctx->ssl_ctx, ctx->bkt_alloc);
+        if (!ctx->ssl_ctx) {
+            ctx->ssl_ctx = serf_bucket_ssl_decrypt_context_get(c);
+        }
+        serf_ssl_server_cert_chain_callback_set(ctx->ssl_ctx, 
+                                                ignore_all_cert_errors, 
+                                                print_certs, NULL);
+        serf_ssl_set_hostname(ctx->ssl_ctx, ctx->hostinfo);
+
+        *output_bkt = serf_bucket_ssl_encrypt_create(*output_bkt, ctx->ssl_ctx,
+                                                    ctx->bkt_alloc);
+    }
+
+    *input_bkt = c;
+
+    return APR_SUCCESS;
+}
+
+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_t *response;
+    serf_bucket_alloc_t *bkt_alloc;
+    app_baton_t *app_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);
+
+    response = serf_bucket_response_create(c, bkt_alloc);
+
+    if (app_ctx->head_request)
+      serf_bucket_response_set_head(response);
+
+    return response;
+}
+
+typedef struct {
+#if APR_MAJOR_VERSION > 0
+    apr_uint32_t completed_requests;
+#else
+    apr_atomic_t completed_requests;
+#endif
+    int print_headers;
+    apr_file_t *output_file;
+
+    serf_response_acceptor_t acceptor;
+    app_baton_t *acceptor_baton;
+
+    serf_response_handler_t handler;
+
+    const char *host;
+    const char *method;
+    const char *path;
+    const char *req_body_path;
+    const char *username;
+    const char *password;
+    int auth_attempts;
+    serf_bucket_t *req_hdrs;
+} handler_baton_t;
+
+/* Kludges for APR 0.9 support. */
+#if APR_MAJOR_VERSION == 0
+#define apr_atomic_inc32 apr_atomic_inc
+#define apr_atomic_dec32 apr_atomic_dec
+#define apr_atomic_read32 apr_atomic_read
+#endif
+
+
+static int append_request_headers(void *baton,
+                                  const char *key,
+                                  const char *value)
+{
+    serf_bucket_t *hdrs_bkt = baton;
+    serf_bucket_headers_setc(hdrs_bkt, key, value);
+    return 0;
+}
+
+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 *hdrs_bkt;
+    serf_bucket_t *body_bkt;
+
+    if (ctx->req_body_path) {
+        apr_file_t *file;
+        apr_status_t status;
+
+        status = apr_file_open(&file, ctx->req_body_path, APR_READ,
+                               APR_OS_DEFAULT, pool);
+
+        if (status) {
+            printf("Error opening file (%s)\n", ctx->req_body_path);
+            return status;
+        }
+
+        body_bkt = serf_bucket_file_create(file,
+                                           serf_request_get_alloc(request));
+    }
+    else {
+        body_bkt = NULL;
+    }
+
+    *req_bkt = serf_request_bucket_request_create(request, ctx->method,
+                                                  ctx->path, body_bkt,
+                                                  serf_request_get_alloc(request));
+
+    hdrs_bkt = serf_bucket_request_get_headers(*req_bkt);
+
+    serf_bucket_headers_setn(hdrs_bkt, "User-Agent",
+                             "Serf/" SERF_VERSION_STRING);
+    /* Shouldn't serf do this for us? */
+    serf_bucket_headers_setn(hdrs_bkt, "Accept-Encoding", "gzip");
+#ifdef CONNECTION_CLOSE_HDR
+    serf_bucket_headers_setn(hdrs_bkt, "Connection", "close");
+#endif
+
+    /* Add the extra headers from the command line */
+    if (ctx->req_hdrs != NULL) {
+        serf_bucket_headers_do(ctx->req_hdrs, append_request_headers, hdrs_bkt);
+    }
+
+    *acceptor = ctx->acceptor;
+    *acceptor_baton = ctx->acceptor_baton;
+    *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)
+{
+    serf_status_line sl;
+    apr_status_t status;
+    handler_baton_t *ctx = handler_baton;
+
+    if (!response) {
+        /* A NULL response probably means that the connection was closed while
+           this request was already written. Just requeue it. */
+        serf_connection_t *conn = serf_request_get_conn(request);
+
+        serf_connection_request_create(conn, setup_request, handler_baton);
+        return APR_SUCCESS;
+    }
+
+    status = serf_bucket_response_status(response, &sl);
+    if (status) {
+        return status;
+    }
+
+    while (1) {
+        struct iovec vecs[64];
+        int vecs_read;
+        apr_size_t bytes_written;
+
+        status = serf_bucket_read_iovec(response, 8000, 64, vecs, &vecs_read);
+        if (SERF_BUCKET_READ_ERROR(status))
+            return status;
+
+        /* got some data. print it out. */
+        if (vecs_read) {
+            apr_file_writev(ctx->output_file, vecs, vecs_read, &bytes_written);
+        }
+
+        /* are we done yet? */
+        if (APR_STATUS_IS_EOF(status)) {
+            if (ctx->print_headers) {
+                serf_bucket_t *hdrs;
+                hdrs = serf_bucket_response_get_headers(response);
+                while (1) {
+                    status = serf_bucket_read_iovec(hdrs, 8000, 64, vecs,
+                                                    &vecs_read);
+
+                    if (SERF_BUCKET_READ_ERROR(status))
+                        return status;
+
+                    if (vecs_read) {
+                        apr_file_writev(ctx->output_file, vecs, vecs_read,
+                                        &bytes_written);
+                    }
+                    if (APR_STATUS_IS_EOF(status)) {
+                        break;
+                    }
+                }
+            }
+
+            apr_atomic_inc32(&ctx->completed_requests);
+            return APR_EOF;
+        }
+
+        /* have we drained the response so far? */
+        if (APR_STATUS_IS_EAGAIN(status))
+            return status;
+
+        /* loop to read some more. */
+    }
+    /* NOTREACHED */
+}
+
+static apr_status_t
+credentials_callback(char **username,
+                     char **password,
+                     serf_request_t *request, void *baton,
+                     int code, const char *authn_type,
+                     const char *realm,
+                     apr_pool_t *pool)
+{
+    handler_baton_t *ctx = baton;
+
+    if (ctx->auth_attempts > 0)
+    {
+        return SERF_ERROR_AUTHN_FAILED;
+    }
+    else
+    {
+        *username = (char*)ctx->username;
+        *password = (char*)ctx->password;
+        ctx->auth_attempts++;
+
+        return APR_SUCCESS;
+    }
+}
+
+static void print_usage(apr_pool_t *pool)
+{
+    puts("serf_get [options] URL");
+    puts("-h\tDisplay this help");
+    puts("-v\tDisplay version");
+    puts("-H\tPrint response headers");
+    puts("-n <count> Fetch URL <count> times");
+    puts("-x <count> Number of maximum outstanding requests inflight");
+    puts("-U <user> Username for Basic/Digest authentication");
+    puts("-P <password> Password for Basic/Digest authentication");
+    puts("-m <method> Use the <method> HTTP Method");
+    puts("-f <file> Use the <file> as the request body");
+    puts("-p <hostname:port> Use the <host:port> as proxy server");
+    puts("-r <header:value> Use <header:value> as request header");
+}
+
+int main(int argc, const char **argv)
+{
+    apr_status_t status;
+    apr_pool_t *pool;
+    serf_bucket_alloc_t *bkt_alloc;
+    serf_context_t *context;
+    serf_connection_t *connection;
+    serf_request_t *request;
+    app_baton_t app_ctx;
+    handler_baton_t handler_ctx;
+    serf_bucket_t *req_hdrs = NULL;
+    apr_uri_t url;
+    const char *proxy = NULL;
+    const char *raw_url, *method, *req_body_path = NULL;
+    int count, inflight;
+    int i;
+    int print_headers;
+    const char *username = NULL;
+    const char *password = "";
+    apr_getopt_t *opt;
+    char opt_c;
+    const char *opt_arg;
+
+    apr_initialize();
+    atexit(apr_terminate);
+
+    apr_pool_create(&pool, NULL);
+    /* serf_initialize(); */
+    bkt_alloc = serf_bucket_allocator_create(pool, NULL, NULL);
+
+    /* Default to one round of fetching with no limit to max inflight reqs. */
+    count = 1;
+    inflight = 0;
+    /* Default to GET. */
+    method = "GET";
+    /* Do not print headers by default. */
+    print_headers = 0;
+
+    apr_getopt_init(&opt, pool, argc, argv);
+
+    while ((status = apr_getopt(opt, "U:P:f:hHm:n:vp:x:r:", &opt_c, &opt_arg)) ==
+           APR_SUCCESS) {
+
+        switch (opt_c) {
+        case 'U':
+            username = opt_arg;
+            break;
+        case 'P':
+            password = opt_arg;
+            break;
+        case 'f':
+            req_body_path = opt_arg;
+            break;
+        case 'h':
+            print_usage(pool);
+            exit(0);
+            break;
+        case 'H':
+            print_headers = 1;
+            break;
+        case 'm':
+            method = opt_arg;
+            break;
+        case 'n':
+            errno = 0;
+            count = apr_strtoi64(opt_arg, NULL, 10);
+            if (errno) {
+                printf("Problem converting number of times to fetch URL (%d)\n",
+                       errno);
+                return errno;
+            }
+            break;
+        case 'x':
+            errno = 0;
+            inflight = apr_strtoi64(opt_arg, NULL, 10);
+            if (errno) {
+                printf("Problem converting number of requests to have outstanding (%d)\n",
+                       errno);
+                return errno;
+            }
+            break;
+        case 'p':
+            proxy = opt_arg;
+            break;
+        case 'r':
+            {
+                char *sep;
+                char *hdr_val;
+
+                if (req_hdrs == NULL) {
+                    /* first request header, allocate bucket */
+                    req_hdrs = serf_bucket_headers_create(bkt_alloc);
+                }
+                sep = strchr(opt_arg, ':');
+                if ((sep == NULL) || (sep == opt_arg) || (strlen(sep) <= 1)) {
+                    printf("Invalid request header string (%s)\n", opt_arg);
+                    return EINVAL;
+                }
+                hdr_val = sep + 1;
+                while (*hdr_val == ' ') {
+                    hdr_val++;
+                }
+                serf_bucket_headers_setx(req_hdrs, opt_arg, (sep - opt_arg), 1,
+                                         hdr_val, strlen(hdr_val), 1);
+            }
+            break;
+        case 'v':
+            puts("Serf version: " SERF_VERSION_STRING);
+            exit(0);
+        default:
+            break;
+        }
+    }
+
+    if (opt->ind != opt->argc - 1) {
+        print_usage(pool);
+        exit(-1);
+    }
+
+    raw_url = argv[opt->ind];
+
+    apr_uri_parse(pool, raw_url, &url);
+    if (!url.port) {
+        url.port = apr_uri_port_of_scheme(url.scheme);
+    }
+    if (!url.path) {
+        url.path = "/";
+    }
+
+    if (strcasecmp(url.scheme, "https") == 0) {
+        app_ctx.using_ssl = 1;
+    }
+    else {
+        app_ctx.using_ssl = 0;
+    }
+
+    if (strcasecmp(method, "HEAD") == 0) {
+        app_ctx.head_request = 1;
+    }
+    else {
+        app_ctx.head_request = 0;
+    }
+
+    app_ctx.hostinfo = url.hostinfo;
+
+    context = serf_context_create(pool);
+
+    if (proxy)
+    {
+        apr_sockaddr_t *proxy_address = NULL;
+        apr_port_t proxy_port;
+        char *proxy_host;
+        char *proxy_scope;
+
+        status = apr_parse_addr_port(&proxy_host, &proxy_scope, &proxy_port, proxy, pool);
+        if (status)
+        {
+            printf("Cannot parse proxy hostname/port: %d\n", status);
+            apr_pool_destroy(pool);
+            exit(1);
+        }
+
+        if (!proxy_host)
+        {
+            printf("Proxy hostname must be specified\n");
+            apr_pool_destroy(pool);
+            exit(1);
+        }
+
+        if (!proxy_port)
+        {
+            printf("Proxy port must be specified\n");
+            apr_pool_destroy(pool);
+            exit(1);
+        }
+
+        status = apr_sockaddr_info_get(&proxy_address, proxy_host, APR_UNSPEC,
+                                       proxy_port, 0, pool);
+
+        if (status)
+        {
+            printf("Cannot resolve proxy address '%s': %d\n", proxy_host, status);
+            apr_pool_destroy(pool);
+            exit(1);
+        }
+
+        serf_config_proxy(context, proxy_address);
+    }
+
+    if (username)
+    {
+        serf_config_authn_types(context, SERF_AUTHN_ALL);
+    }
+    else
+    {
+        serf_config_authn_types(context, SERF_AUTHN_NTLM | SERF_AUTHN_NEGOTIATE);
+    }
+
+    serf_config_credentials_callback(context, credentials_callback);
+
+    /* ### Connection or Context should have an allocator? */
+    app_ctx.bkt_alloc = bkt_alloc;
+    app_ctx.ssl_ctx = NULL;
+
+    status = serf_connection_create2(&connection, context, url,
+                                     conn_setup, &app_ctx,
+                                     closed_connection, &app_ctx,
+                                     pool);
+    if (status) {
+        printf("Error creating connection: %d\n", status);
+        apr_pool_destroy(pool);
+        exit(1);
+    }
+
+    handler_ctx.completed_requests = 0;
+    handler_ctx.print_headers = print_headers;
+    apr_file_open_stdout(&handler_ctx.output_file, pool);
+
+    handler_ctx.host = url.hostinfo;
+    handler_ctx.method = method;
+    handler_ctx.path = apr_pstrcat(pool,
+                                   url.path,
+                                   url.query ? "?" : "",
+                                   url.query ? url.query : "",
+                                   NULL);
+    handler_ctx.username = username;
+    handler_ctx.password = password;
+    handler_ctx.auth_attempts = 0;
+
+    handler_ctx.req_body_path = req_body_path;
+
+    handler_ctx.acceptor = accept_response;
+    handler_ctx.acceptor_baton = &app_ctx;
+    handler_ctx.handler = handle_response;
+    handler_ctx.req_hdrs = req_hdrs;
+
+    serf_connection_set_max_outstanding_requests(connection, inflight);
+
+    for (i = 0; i < count; i++) {
+        request = serf_connection_request_create(connection, setup_request,
+                                                 &handler_ctx);
+    }
+
+    while (1) {
+        status = serf_context_run(context, SERF_DURATION_FOREVER, pool);
+        if (APR_STATUS_IS_TIMEUP(status))
+            continue;
+        if (status) {
+            char buf[200];
+            const char *err_string;
+            err_string = serf_error_string(status);
+            if (!err_string) {
+                err_string = apr_strerror(status, buf, sizeof(buf));
+            }
+
+            printf("Error running context: (%d) %s\n", status, err_string);
+            apr_pool_destroy(pool);
+            exit(1);
+        }
+        if (apr_atomic_read32(&handler_ctx.completed_requests) >= count) {
+            break;
+        }
+        /* Debugging purposes only! */
+        serf_debug__closed_conn(app_ctx.bkt_alloc);
+    }
+
+    serf_connection_close(connection);
+
+    apr_pool_destroy(pool);
+    return 0;
+}

Deleted: vendor/serf/1.3.9/test/serf_request.c
===================================================================
--- vendor/serf/dist/test/serf_request.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/test/serf_request.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,79 +0,0 @@
-/* Copyright 2002-2004 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 "serf.h"
-
-static apr_status_t drain_bucket(serf_bucket_t *bucket)
-{
-    apr_status_t status;
-    const char *data;
-    apr_size_t len;
-
-    while (1) {
-        status = serf_bucket_read(bucket, 2048, &data, &len);
-        if (SERF_BUCKET_READ_ERROR(status))
-            return status;
-
-        /* got some data. print it out. */
-        fwrite(data, 1, len, stdout);
-
-        /* are we done yet? */
-        if (APR_STATUS_IS_EOF(status)) {
-            return APR_EOF;
-        }
-
-        /* have we drained the response so far? */
-        if (APR_STATUS_IS_EAGAIN(status))
-            return APR_SUCCESS;
-
-        /* loop to read some more. */
-    }
-    /* NOTREACHED */
-}
-
-int main(int argc, const char **argv)
-{
-    apr_pool_t *pool;
-    serf_bucket_t *req_bkt;
-    serf_bucket_t *hdrs_bkt;
-    serf_bucket_alloc_t *allocator;
-
-    apr_initialize();
-    atexit(apr_terminate);
-
-    apr_pool_create(&pool, NULL);
-    /* serf_initialize(); */
-
-    allocator = serf_bucket_allocator_create(pool, NULL, NULL);
-
-    req_bkt = serf_bucket_request_create("GET", "/", NULL, allocator);
-
-    hdrs_bkt = serf_bucket_request_get_headers(req_bkt);
-
-    /* FIXME: Shouldn't we be able to figure out the host ourselves? */
-    serf_bucket_headers_setn(hdrs_bkt, "Host", "localhost");
-    serf_bucket_headers_setn(hdrs_bkt, "User-Agent",
-                             "Serf/" SERF_VERSION_STRING);
-
-    (void) drain_bucket(req_bkt);
-
-    serf_bucket_destroy(req_bkt);
-
-    apr_pool_destroy(pool);
-
-    return 0;
-}

Copied: vendor/serf/1.3.9/test/serf_request.c (from rev 9259, vendor/serf/dist/test/serf_request.c)
===================================================================
--- vendor/serf/1.3.9/test/serf_request.c	                        (rev 0)
+++ vendor/serf/1.3.9/test/serf_request.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,84 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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 "serf.h"
+
+static apr_status_t drain_bucket(serf_bucket_t *bucket)
+{
+    apr_status_t status;
+    const char *data;
+    apr_size_t len;
+
+    while (1) {
+        status = serf_bucket_read(bucket, 2048, &data, &len);
+        if (SERF_BUCKET_READ_ERROR(status))
+            return status;
+
+        /* got some data. print it out. */
+        fwrite(data, 1, len, stdout);
+
+        /* are we done yet? */
+        if (APR_STATUS_IS_EOF(status)) {
+            return APR_EOF;
+        }
+
+        /* have we drained the response so far? */
+        if (APR_STATUS_IS_EAGAIN(status))
+            return APR_SUCCESS;
+
+        /* loop to read some more. */
+    }
+    /* NOTREACHED */
+}
+
+int main(int argc, const char **argv)
+{
+    apr_pool_t *pool;
+    serf_bucket_t *req_bkt;
+    serf_bucket_t *hdrs_bkt;
+    serf_bucket_alloc_t *allocator;
+
+    apr_initialize();
+    atexit(apr_terminate);
+
+    apr_pool_create(&pool, NULL);
+    /* serf_initialize(); */
+
+    allocator = serf_bucket_allocator_create(pool, NULL, NULL);
+
+    req_bkt = serf_bucket_request_create("GET", "/", NULL, allocator);
+
+    hdrs_bkt = serf_bucket_request_get_headers(req_bkt);
+
+    /* FIXME: Shouldn't we be able to figure out the host ourselves? */
+    serf_bucket_headers_setn(hdrs_bkt, "Host", "localhost");
+    serf_bucket_headers_setn(hdrs_bkt, "User-Agent",
+                             "Serf/" SERF_VERSION_STRING);
+
+    (void) drain_bucket(req_bkt);
+
+    serf_bucket_destroy(req_bkt);
+
+    apr_pool_destroy(pool);
+
+    return 0;
+}

Deleted: vendor/serf/1.3.9/test/serf_response.c
===================================================================
--- vendor/serf/dist/test/serf_response.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/test/serf_response.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,161 +0,0 @@
-/* Copyright 2002-2004 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_uri.h>
-#include <apr_strings.h>
-#include <apr_atomic.h>
-#include <apr_version.h>
-
-#include "serf.h"
-
-typedef struct {
-    const char *resp_file;
-    serf_bucket_t *bkt;
-} accept_baton_t;
-
-static serf_bucket_t* accept_response(void *acceptor_baton,
-                                      serf_bucket_alloc_t *bkt_alloc,
-                                      apr_pool_t *pool)
-{
-    accept_baton_t *ctx = acceptor_baton;
-    serf_bucket_t *c;
-    apr_file_t *file;
-    apr_status_t status;
-
-    status = apr_file_open(&file, ctx->resp_file,
-                           APR_READ, APR_OS_DEFAULT, pool);
-    if (status) {
-        return NULL;
-    }
-
-    c = ctx->bkt = serf_bucket_file_create(file, bkt_alloc);
-
-    c = serf_bucket_barrier_create(c, bkt_alloc);
-
-    return serf_bucket_response_create(c, bkt_alloc);
-}
-
-typedef struct {
-#if APR_MAJOR_VERSION > 0
-    apr_uint32_t requests_outstanding;
-#else
-    apr_atomic_t requests_outstanding;
-#endif
-} handler_baton_t;
-
-/* Kludges for APR 0.9 support. */
-#if APR_MAJOR_VERSION == 0
-#define apr_atomic_inc32 apr_atomic_inc
-#define apr_atomic_dec32 apr_atomic_dec
-#define apr_atomic_read32 apr_atomic_read
-#endif
-
-static apr_status_t handle_response(serf_request_t *request,
-                                    serf_bucket_t *response,
-                                    void *handler_baton,
-                                    apr_pool_t *pool)
-{
-    const char *data, *s;
-    apr_size_t len;
-    serf_status_line sl;
-    apr_status_t status;
-    handler_baton_t *ctx = handler_baton;
-
-    status = serf_bucket_response_status(response, &sl);
-    if (status) {
-        if (APR_STATUS_IS_EAGAIN(status)) {
-            return APR_SUCCESS;
-        }
-        abort();
-    }
-
-    status = serf_bucket_read(response, 2048, &data, &len);
-
-    if (!status || APR_STATUS_IS_EOF(status)) {
-        if (len) {
-            s = apr_pstrmemdup(pool, data, len);
-            printf("%s", s);
-        }
-    }
-    else if (APR_STATUS_IS_EAGAIN(status)) {
-        status = APR_SUCCESS;
-    }
-    if (APR_STATUS_IS_EOF(status)) {
-        serf_bucket_t *hdrs;
-        const char *v;
-
-        hdrs = serf_bucket_response_get_headers(response);
-        v = serf_bucket_headers_get(hdrs, "Trailer-Test");
-        if (v) {
-            printf("Trailer-Test: %s\n", v);
-        }
-
-        apr_atomic_dec32(&ctx->requests_outstanding);
-    }
-
-    return status;
-}
-
-int main(int argc, const char **argv)
-{
-    apr_status_t status;
-    apr_pool_t *pool;
-    serf_bucket_t *resp_bkt;
-    accept_baton_t accept_ctx;
-    handler_baton_t handler_ctx;
-    serf_bucket_alloc_t *allocator;
-
-    if (argc != 2) {
-        printf("%s: [Resp. File]\n", argv[0]);
-        exit(-1);
-    }
-    accept_ctx.resp_file = argv[1];
-    accept_ctx.bkt = NULL;
-
-    apr_initialize();
-    atexit(apr_terminate);
-
-    apr_pool_create(&pool, NULL);
-    apr_atomic_init(pool);
-    /* serf_initialize(); */
-
-    allocator = serf_bucket_allocator_create(pool, NULL, NULL);
-
-    handler_ctx.requests_outstanding = 0;
-    apr_atomic_inc32(&handler_ctx.requests_outstanding);
-
-    resp_bkt = accept_response(&accept_ctx, allocator, pool);
-    while (1) {
-        status = handle_response(NULL, resp_bkt, &handler_ctx, pool);
-        if (APR_STATUS_IS_TIMEUP(status))
-            continue;
-        if (SERF_BUCKET_READ_ERROR(status)) {
-            printf("Error running context: %d\n", status);
-            exit(1);
-        }
-        if (!apr_atomic_read32(&handler_ctx.requests_outstanding)) {
-            break;
-        }
-    }
-    serf_bucket_destroy(resp_bkt);
-    serf_bucket_destroy(accept_ctx.bkt);
-
-    apr_pool_destroy(pool);
-
-    return 0;
-}

Copied: vendor/serf/1.3.9/test/serf_response.c (from rev 9259, vendor/serf/dist/test/serf_response.c)
===================================================================
--- vendor/serf/1.3.9/test/serf_response.c	                        (rev 0)
+++ vendor/serf/1.3.9/test/serf_response.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,166 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_uri.h>
+#include <apr_strings.h>
+#include <apr_atomic.h>
+#include <apr_version.h>
+
+#include "serf.h"
+
+typedef struct {
+    const char *resp_file;
+    serf_bucket_t *bkt;
+} accept_baton_t;
+
+static serf_bucket_t* accept_response(void *acceptor_baton,
+                                      serf_bucket_alloc_t *bkt_alloc,
+                                      apr_pool_t *pool)
+{
+    accept_baton_t *ctx = acceptor_baton;
+    serf_bucket_t *c;
+    apr_file_t *file;
+    apr_status_t status;
+
+    status = apr_file_open(&file, ctx->resp_file,
+                           APR_READ, APR_OS_DEFAULT, pool);
+    if (status) {
+        return NULL;
+    }
+
+    c = ctx->bkt = serf_bucket_file_create(file, bkt_alloc);
+
+    c = serf_bucket_barrier_create(c, bkt_alloc);
+
+    return serf_bucket_response_create(c, bkt_alloc);
+}
+
+typedef struct {
+#if APR_MAJOR_VERSION > 0
+    apr_uint32_t requests_outstanding;
+#else
+    apr_atomic_t requests_outstanding;
+#endif
+} handler_baton_t;
+
+/* Kludges for APR 0.9 support. */
+#if APR_MAJOR_VERSION == 0
+#define apr_atomic_inc32 apr_atomic_inc
+#define apr_atomic_dec32 apr_atomic_dec
+#define apr_atomic_read32 apr_atomic_read
+#endif
+
+static apr_status_t handle_response(serf_request_t *request,
+                                    serf_bucket_t *response,
+                                    void *handler_baton,
+                                    apr_pool_t *pool)
+{
+    const char *data, *s;
+    apr_size_t len;
+    serf_status_line sl;
+    apr_status_t status;
+    handler_baton_t *ctx = handler_baton;
+
+    status = serf_bucket_response_status(response, &sl);
+    if (status) {
+        if (APR_STATUS_IS_EAGAIN(status)) {
+            return APR_SUCCESS;
+        }
+        abort();
+    }
+
+    status = serf_bucket_read(response, 2048, &data, &len);
+
+    if (!status || APR_STATUS_IS_EOF(status)) {
+        if (len) {
+            s = apr_pstrmemdup(pool, data, len);
+            printf("%s", s);
+        }
+    }
+    else if (APR_STATUS_IS_EAGAIN(status)) {
+        status = APR_SUCCESS;
+    }
+    if (APR_STATUS_IS_EOF(status)) {
+        serf_bucket_t *hdrs;
+        const char *v;
+
+        hdrs = serf_bucket_response_get_headers(response);
+        v = serf_bucket_headers_get(hdrs, "Trailer-Test");
+        if (v) {
+            printf("Trailer-Test: %s\n", v);
+        }
+
+        apr_atomic_dec32(&ctx->requests_outstanding);
+    }
+
+    return status;
+}
+
+int main(int argc, const char **argv)
+{
+    apr_status_t status;
+    apr_pool_t *pool;
+    serf_bucket_t *resp_bkt;
+    accept_baton_t accept_ctx;
+    handler_baton_t handler_ctx;
+    serf_bucket_alloc_t *allocator;
+
+    if (argc != 2) {
+        printf("%s: [Resp. File]\n", argv[0]);
+        exit(-1);
+    }
+    accept_ctx.resp_file = argv[1];
+    accept_ctx.bkt = NULL;
+
+    apr_initialize();
+    atexit(apr_terminate);
+
+    apr_pool_create(&pool, NULL);
+    apr_atomic_init(pool);
+    /* serf_initialize(); */
+
+    allocator = serf_bucket_allocator_create(pool, NULL, NULL);
+
+    handler_ctx.requests_outstanding = 0;
+    apr_atomic_inc32(&handler_ctx.requests_outstanding);
+
+    resp_bkt = accept_response(&accept_ctx, allocator, pool);
+    while (1) {
+        status = handle_response(NULL, resp_bkt, &handler_ctx, pool);
+        if (APR_STATUS_IS_TIMEUP(status))
+            continue;
+        if (SERF_BUCKET_READ_ERROR(status)) {
+            printf("Error running context: %d\n", status);
+            exit(1);
+        }
+        if (!apr_atomic_read32(&handler_ctx.requests_outstanding)) {
+            break;
+        }
+    }
+    serf_bucket_destroy(resp_bkt);
+    serf_bucket_destroy(accept_ctx.bkt);
+
+    apr_pool_destroy(pool);
+
+    return 0;
+}

Deleted: vendor/serf/1.3.9/test/serf_server.c
===================================================================
--- vendor/serf/dist/test/serf_server.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/test/serf_server.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,147 +0,0 @@
-/* Copyright 2002-2004 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_uri.h>
-#include <apr_strings.h>
-#include <apr_atomic.h>
-#include <apr_base64.h>
-#include <apr_getopt.h>
-#include <apr_version.h>
-
-#include "serf.h"
-
-typedef struct {
-    int foo;
-} app_baton_t;
-
-
-static apr_status_t incoming_request(serf_context_t *ctx,
-                                        serf_incoming_request_t *req,
-                                        void *request_baton,
-                                        apr_pool_t *pool)
-{
-    printf("INCOMING REQUEST\n");
-    return APR_SUCCESS;
-}
-
-
-static apr_status_t accept_fn(serf_context_t *ctx, 
-                                        serf_listener_t *l,
-                                        void *baton,
-                                        apr_socket_t *insock,
-                                        apr_pool_t *pool)
-{
-    serf_incoming_t *client = NULL;
-    printf("new connection from \n");
-    return serf_incoming_create(&client, ctx, insock, baton, incoming_request, pool);
-}
-            
-static void print_usage(apr_pool_t *pool)
-{
-    puts("serf_server [options] listen_address:listen_port");
-    puts("-h\tDisplay this help");
-    puts("-v\tDisplay version");
-}
-
-int main(int argc, const char **argv)
-{
-    apr_status_t rv;
-    apr_pool_t *pool;
-    serf_context_t *context;
-    serf_listener_t *listener;
-    app_baton_t app_ctx;
-    const char *listen_spec;
-    char *addr = NULL;
-    char *scope_id = NULL;
-    apr_port_t port;
-    apr_getopt_t *opt;
-    char opt_c;
-    const char *opt_arg;
-
-    apr_initialize();
-    atexit(apr_terminate);
-
-    apr_pool_create(&pool, NULL);
-
-    apr_getopt_init(&opt, pool, argc, argv);
-
-    while ((rv = apr_getopt(opt, "hv", &opt_c, &opt_arg)) ==
-           APR_SUCCESS) {
-        switch (opt_c) {
-        case 'h':
-            print_usage(pool);
-            exit(0);
-            break;
-        case 'v':
-            puts("Serf version: " SERF_VERSION_STRING);
-            exit(0);
-        default:
-            break;
-        }
-    }
-
-    if (opt->ind != opt->argc - 1) {
-        print_usage(pool);
-        exit(-1);
-    }
-
-    listen_spec = argv[opt->ind];
-
-
-    rv = apr_parse_addr_port(&addr, &scope_id, &port, listen_spec, pool);
-    if (rv) {
-        printf("Error parsing listen address: %d\n", rv);
-        exit(1);
-    }
-
-    if (!addr) {
-        addr = "0.0.0.0";
-    }
-
-    if (port == 0) {
-        port = 8080;
-    }
-
-    context = serf_context_create(pool);
-
-    /* TODO.... stuff */
-    app_ctx.foo = 1;
-    rv = serf_listener_create(&listener, context, addr, port, 
-                              &app_ctx, accept_fn, pool);
-    if (rv) {
-        printf("Error parsing listener: %d\n", rv);
-        exit(1);
-    }
-
-    while (1) {
-        rv = serf_context_run(context, SERF_DURATION_FOREVER, pool);
-        if (APR_STATUS_IS_TIMEUP(rv))
-            continue;
-        if (rv) {
-            char buf[200];
-
-            printf("Error running context: (%d) %s\n", rv,
-                   apr_strerror(rv, buf, sizeof(buf)));
-            apr_pool_destroy(pool);
-            exit(1);
-        }
-    }
-
-    apr_pool_destroy(pool);
-    return 0;
-}

Copied: vendor/serf/1.3.9/test/serf_server.c (from rev 9259, vendor/serf/dist/test/serf_server.c)
===================================================================
--- vendor/serf/1.3.9/test/serf_server.c	                        (rev 0)
+++ vendor/serf/1.3.9/test/serf_server.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,152 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_uri.h>
+#include <apr_strings.h>
+#include <apr_atomic.h>
+#include <apr_base64.h>
+#include <apr_getopt.h>
+#include <apr_version.h>
+
+#include "serf.h"
+
+typedef struct {
+    int foo;
+} app_baton_t;
+
+
+static apr_status_t incoming_request(serf_context_t *ctx,
+                                        serf_incoming_request_t *req,
+                                        void *request_baton,
+                                        apr_pool_t *pool)
+{
+    printf("INCOMING REQUEST\n");
+    return APR_SUCCESS;
+}
+
+
+static apr_status_t accept_fn(serf_context_t *ctx, 
+                                        serf_listener_t *l,
+                                        void *baton,
+                                        apr_socket_t *insock,
+                                        apr_pool_t *pool)
+{
+    serf_incoming_t *client = NULL;
+    printf("new connection from \n");
+    return serf_incoming_create(&client, ctx, insock, baton, incoming_request, pool);
+}
+            
+static void print_usage(apr_pool_t *pool)
+{
+    puts("serf_server [options] listen_address:listen_port");
+    puts("-h\tDisplay this help");
+    puts("-v\tDisplay version");
+}
+
+int main(int argc, const char **argv)
+{
+    apr_status_t rv;
+    apr_pool_t *pool;
+    serf_context_t *context;
+    serf_listener_t *listener;
+    app_baton_t app_ctx;
+    const char *listen_spec;
+    char *addr = NULL;
+    char *scope_id = NULL;
+    apr_port_t port;
+    apr_getopt_t *opt;
+    char opt_c;
+    const char *opt_arg;
+
+    apr_initialize();
+    atexit(apr_terminate);
+
+    apr_pool_create(&pool, NULL);
+
+    apr_getopt_init(&opt, pool, argc, argv);
+
+    while ((rv = apr_getopt(opt, "hv", &opt_c, &opt_arg)) ==
+           APR_SUCCESS) {
+        switch (opt_c) {
+        case 'h':
+            print_usage(pool);
+            exit(0);
+            break;
+        case 'v':
+            puts("Serf version: " SERF_VERSION_STRING);
+            exit(0);
+        default:
+            break;
+        }
+    }
+
+    if (opt->ind != opt->argc - 1) {
+        print_usage(pool);
+        exit(-1);
+    }
+
+    listen_spec = argv[opt->ind];
+
+
+    rv = apr_parse_addr_port(&addr, &scope_id, &port, listen_spec, pool);
+    if (rv) {
+        printf("Error parsing listen address: %d\n", rv);
+        exit(1);
+    }
+
+    if (!addr) {
+        addr = "0.0.0.0";
+    }
+
+    if (port == 0) {
+        port = 8080;
+    }
+
+    context = serf_context_create(pool);
+
+    /* TODO.... stuff */
+    app_ctx.foo = 1;
+    rv = serf_listener_create(&listener, context, addr, port, 
+                              &app_ctx, accept_fn, pool);
+    if (rv) {
+        printf("Error parsing listener: %d\n", rv);
+        exit(1);
+    }
+
+    while (1) {
+        rv = serf_context_run(context, SERF_DURATION_FOREVER, pool);
+        if (APR_STATUS_IS_TIMEUP(rv))
+            continue;
+        if (rv) {
+            char buf[200];
+
+            printf("Error running context: (%d) %s\n", rv,
+                   apr_strerror(rv, buf, sizeof(buf)));
+            apr_pool_destroy(pool);
+            exit(1);
+        }
+    }
+
+    apr_pool_destroy(pool);
+    return 0;
+}

Deleted: vendor/serf/1.3.9/test/serf_spider.c
===================================================================
--- vendor/serf/dist/test/serf_spider.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/test/serf_spider.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,826 +0,0 @@
-/* Copyright 2002-2004 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_uri.h>
-#include <apr_strings.h>
-#include <apr_atomic.h>
-#include <apr_base64.h>
-#include <apr_getopt.h>
-#include <apr_xml.h>
-#include <apr_thread_proc.h>
-#include <apr_thread_mutex.h>
-#include <apr_thread_cond.h>
-#include <apr_version.h>
-
-#include "serf.h"
-#include "serf_bucket_util.h"
-
-/*#define SERF_VERBOSE*/
-
-#if !APR_HAS_THREADS
-#error serf spider needs threads.
-#endif
-
-/* This is a rough-sketch example of how a multi-threaded spider could be
- * constructed using serf.
- *
- * A network thread will read in a URL and feed it into an expat parser.
- * After the entire response is read, the XML structure and the path is
- * passed to a set of parser threads.  These threads will scan the document
- * for HTML href's and queue up any links that it finds.
- *
- * It does try to stay on the same server as it only uses one connection.
- *
- * Because we feed the responses into an XML parser, the documents must be
- * well-formed XHTML.
- *
- * There is no duplicate link detection.  You've been warned.
- */
-
-/* The structure passed to the parser thread after we've read the entire
- * response.
- */
-typedef struct {
-    apr_xml_doc *doc;
-    char *path;
-    apr_pool_t *pool;
-} doc_path_t;
-
-typedef struct {
-    const char *authn;
-    int using_ssl;
-    serf_ssl_context_t *ssl_ctx;
-    serf_bucket_alloc_t *bkt_alloc;
-} app_baton_t;
-
-static void closed_connection(serf_connection_t *conn,
-                              void *closed_baton,
-                              apr_status_t why,
-                              apr_pool_t *pool)
-{
-    if (why) {
-        abort();
-    }
-}
-
-static apr_status_t conn_setup(apr_socket_t *skt,
-                                serf_bucket_t **input_bkt,
-                                serf_bucket_t **output_bkt,
-                                void *setup_baton,
-                                apr_pool_t *pool)
-{
-    serf_bucket_t *c;
-    app_baton_t *ctx = setup_baton;
-
-    c = serf_bucket_socket_create(skt, ctx->bkt_alloc);
-    if (ctx->using_ssl) {
-        c = serf_bucket_ssl_decrypt_create(c, ctx->ssl_ctx, ctx->bkt_alloc);
-    }
-
-    *input_bkt = c;
-
-    return APR_SUCCESS;
-}
-
-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;
-
-    /* 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);
-
-    return serf_bucket_response_create(c, bkt_alloc);
-}
-
-typedef struct {
-    serf_bucket_alloc_t *allocator;
-#if APR_MAJOR_VERSION > 0
-    apr_uint32_t *requests_outstanding;
-#else
-    apr_atomic_t *requests_outstanding;
-#endif
-    serf_bucket_alloc_t *doc_queue_alloc;
-    apr_array_header_t *doc_queue;
-    apr_thread_cond_t *doc_queue_condvar;
-
-    const char *hostinfo;
-
-    /* includes: path, query, fragment. */
-    char *full_path;
-    apr_size_t full_path_len;
-
-    char *path;
-    apr_size_t path_len;
-
-    char *query;
-    apr_size_t query_len;
-
-    char *fragment;
-    apr_size_t fragment_len;
-
-    apr_xml_parser *parser;
-    apr_pool_t *parser_pool;
-
-    int hdr_read;
-    int is_html;
-
-    serf_response_acceptor_t acceptor;
-    void *acceptor_baton;
-    serf_response_handler_t handler;
-
-    app_baton_t *app_ctx;
-} handler_baton_t;
-
-/* Kludges for APR 0.9 support. */
-#if APR_MAJOR_VERSION == 0
-#define apr_atomic_inc32 apr_atomic_inc
-#define apr_atomic_dec32 apr_atomic_dec
-#define apr_atomic_read32 apr_atomic_read
-#define apr_atomic_set32 apr_atomic_set
-#endif
-
-static apr_status_t handle_response(serf_request_t *request,
-                                    serf_bucket_t *response,
-                                    void *handler_baton,
-                                    apr_pool_t *pool)
-{
-    const char *data;
-    apr_size_t len;
-    serf_status_line sl;
-    apr_status_t status;
-    handler_baton_t *ctx = handler_baton;
-
-    if (!response) {
-        /* Oh no!  We've been cancelled! */
-        abort();
-    }
-
-    status = serf_bucket_response_status(response, &sl);
-    if (status) {
-        if (APR_STATUS_IS_EAGAIN(status)) {
-            return APR_SUCCESS;
-        }
-        abort();
-    }
-
-    while (1) {
-        status = serf_bucket_read(response, 2048, &data, &len);
-
-        if (SERF_BUCKET_READ_ERROR(status))
-            return status;
-
-        /*fwrite(data, 1, len, stdout);*/
-
-        if (!ctx->hdr_read) {
-            serf_bucket_t *hdrs;
-            const char *val;
-
-            printf("Processing %s\n", ctx->path);
-
-            hdrs = serf_bucket_response_get_headers(response);
-            val = serf_bucket_headers_get(hdrs, "Content-Type");
-            /* FIXME: This check isn't quite right because Content-Type could
-             * be decorated; ideally strcasestr would be correct.
-             */
-            if (val && strcasecmp(val, "text/html") == 0) {
-                ctx->is_html = 1;
-                apr_pool_create(&ctx->parser_pool, NULL);
-                ctx->parser = apr_xml_parser_create(ctx->parser_pool);
-            }
-            else {
-                ctx->is_html = 0;
-            }
-            ctx->hdr_read = 1;
-        }
-        if (ctx->is_html) {
-            apr_status_t xs;
-
-            xs = apr_xml_parser_feed(ctx->parser, data, len);
-            /* Uh-oh. */
-            if (xs) {
-#ifdef SERF_VERBOSE
-                printf("XML parser error (feed): %d\n", xs);
-#endif
-                ctx->is_html = 0;
-            }
-        }
-
-        /* are we done yet? */
-        if (APR_STATUS_IS_EOF(status)) {
-
-            if (ctx->is_html) {
-                apr_xml_doc *xmld;
-                apr_status_t xs;
-                doc_path_t *dup;
-
-                xs = apr_xml_parser_done(ctx->parser, &xmld);
-                if (xs) {
-#ifdef SERF_VERBOSE
-                    printf("XML parser error (done): %d\n", xs);
-#endif
-                    return xs;
-                }
-                dup = (doc_path_t*)
-                    serf_bucket_mem_alloc(ctx->doc_queue_alloc,
-                                          sizeof(doc_path_t));
-                dup->doc = xmld;
-                dup->path = (char*)serf_bucket_mem_alloc(ctx->doc_queue_alloc,
-                                                         ctx->path_len);
-                memcpy(dup->path, ctx->path, ctx->path_len);
-                dup->pool = ctx->parser_pool;
-
-                *(doc_path_t **)apr_array_push(ctx->doc_queue) = dup;
-
-                apr_thread_cond_signal(ctx->doc_queue_condvar);
-            }
-
-            apr_atomic_dec32(ctx->requests_outstanding);
-            serf_bucket_mem_free(ctx->allocator, ctx->path);
-            if (ctx->query) {
-                serf_bucket_mem_free(ctx->allocator, ctx->query);
-                serf_bucket_mem_free(ctx->allocator, ctx->full_path);
-            }
-            if (ctx->fragment) {
-                serf_bucket_mem_free(ctx->allocator, ctx->fragment);
-            }
-            serf_bucket_mem_free(ctx->allocator, ctx);
-            return APR_EOF;
-        }
-
-        /* have we drained the response so far? */
-        if (APR_STATUS_IS_EAGAIN(status))
-            return APR_SUCCESS;
-
-        /* loop to read some more. */
-    }
-    /* NOTREACHED */
-}
-
-typedef struct {
-    apr_uint32_t *requests_outstanding;
-    serf_connection_t *connection;
-    apr_array_header_t *doc_queue;
-    serf_bucket_alloc_t *doc_queue_alloc;
-
-    apr_thread_cond_t *condvar;
-    apr_thread_mutex_t *mutex;
-
-    /* Master host: for now, we'll stick to one host. */
-    const char *hostinfo;
-
-    app_baton_t *app_ctx;
-} parser_baton_t;
-
-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 *hdrs_bkt;
-
-    *req_bkt = serf_bucket_request_create("GET", ctx->full_path, NULL,
-                                          serf_request_get_alloc(request));
-
-    hdrs_bkt = serf_bucket_request_get_headers(*req_bkt);
-
-    /* FIXME: Shouldn't we be able to figure out the host ourselves? */
-    serf_bucket_headers_setn(hdrs_bkt, "Host", ctx->hostinfo);
-    serf_bucket_headers_setn(hdrs_bkt, "User-Agent",
-                             "Serf/" SERF_VERSION_STRING);
-
-    /* Shouldn't serf do this for us? */
-    serf_bucket_headers_setn(hdrs_bkt, "Accept-Encoding", "gzip");
-
-    if (ctx->app_ctx->authn != NULL) {
-        serf_bucket_headers_setn(hdrs_bkt, "Authorization",
-                                 ctx->app_ctx->authn);
-    }
-
-    if (ctx->app_ctx->using_ssl) {
-        serf_bucket_alloc_t *req_alloc;
-
-        req_alloc = serf_request_get_alloc(request);
-
-        if (ctx->app_ctx->ssl_ctx == NULL) {
-            *req_bkt = serf_bucket_ssl_encrypt_create(*req_bkt, NULL,
-                                                      ctx->app_ctx->bkt_alloc);
-            ctx->app_ctx->ssl_ctx =
-                serf_bucket_ssl_encrypt_context_get(*req_bkt);
-        }
-        else {
-            *req_bkt =
-                serf_bucket_ssl_encrypt_create(*req_bkt, ctx->app_ctx->ssl_ctx,
-                                               ctx->app_ctx->bkt_alloc);
-        }
-    }
-
-
-#ifdef SERF_VERBOSE
-    printf("Url requesting: %s\n", ctx->full_path);
-#endif
-
-    *acceptor = ctx->acceptor;
-    *acceptor_baton = ctx->acceptor_baton;
-    *handler = ctx->handler;
-    *handler_baton = ctx;
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t create_request(const char *hostinfo,
-                                   const char *path,
-                                   const char *query,
-                                   const char *fragment,
-                                   parser_baton_t *ctx,
-                                   apr_pool_t *tmppool)
-{
-    handler_baton_t *new_ctx;
-
-    if (hostinfo) {
-        /* Yes, this is a pointer comparison; not a string comparison. */
-        if (hostinfo != ctx->hostinfo) {
-            /* Not on the same host; ignore */
-            return APR_SUCCESS;
-        }
-    }
-
-    new_ctx = (handler_baton_t*)serf_bucket_mem_alloc(ctx->app_ctx->bkt_alloc,
-                                                      sizeof(handler_baton_t));
-    new_ctx->allocator = ctx->app_ctx->bkt_alloc;
-    new_ctx->requests_outstanding = ctx->requests_outstanding;
-    new_ctx->app_ctx = ctx->app_ctx;
-
-    /* See above: this example restricts ourselves to the same vhost. */
-    new_ctx->hostinfo = ctx->hostinfo;
-
-    /* we need to copy it so it falls under the request's scope. */
-    new_ctx->path_len = strlen(path);
-    new_ctx->path = (char*)serf_bucket_mem_alloc(ctx->app_ctx->bkt_alloc,
-                                                 new_ctx->path_len + 1);
-    memcpy(new_ctx->path, path, new_ctx->path_len + 1);
-
-    /* we need to copy it so it falls under the request's scope. */
-    if (query) {
-        new_ctx->query_len = strlen(query);
-        new_ctx->query = (char*)serf_bucket_mem_alloc(ctx->app_ctx->bkt_alloc,
-                                                      new_ctx->query_len + 1);
-        memcpy(new_ctx->query, query, new_ctx->query_len + 1);
-    }
-    else {
-        new_ctx->query = NULL;
-        new_ctx->query_len = 0;
-    }
-
-    /* we need to copy it so it falls under the request's scope. */
-    if (fragment) {
-        new_ctx->fragment_len = strlen(fragment);
-        new_ctx->fragment =
-            (char*)serf_bucket_mem_alloc(ctx->app_ctx->bkt_alloc,
-                                         new_ctx->fragment_len + 1);
-        memcpy(new_ctx->fragment, fragment, new_ctx->fragment_len + 1);
-    }
-    else {
-        new_ctx->fragment = NULL;
-        new_ctx->fragment_len = 0;
-    }
-
-    if (!new_ctx->query) {
-        new_ctx->full_path = new_ctx->path;
-        new_ctx->full_path_len = new_ctx->path_len;
-    }
-    else {
-        new_ctx->full_path_len = new_ctx->path_len + new_ctx->query_len;
-        new_ctx->full_path =
-            (char*)serf_bucket_mem_alloc(ctx->app_ctx->bkt_alloc,
-                                         new_ctx->full_path_len + 1);
-        memcpy(new_ctx->full_path, new_ctx->path, new_ctx->path_len);
-        memcpy(new_ctx->full_path + new_ctx->path_len, new_ctx->query,
-               new_ctx->query_len + 1);
-    }
-
-    new_ctx->hdr_read = 0;
-
-    new_ctx->doc_queue_condvar = ctx->condvar;
-    new_ctx->doc_queue = ctx->doc_queue;
-    new_ctx->doc_queue_alloc = ctx->doc_queue_alloc;
-
-    new_ctx->acceptor = accept_response;
-    new_ctx->acceptor_baton = &ctx->app_ctx;
-    new_ctx->handler = handle_response;
-
-    apr_atomic_inc32(ctx->requests_outstanding);
-
-    serf_connection_request_create(ctx->connection, setup_request, new_ctx);
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t put_req(const char *c, const char *orig_path,
-                            parser_baton_t *ctx, apr_pool_t *pool)
-{
-    apr_status_t status;
-    apr_uri_t url;
-
-    /* Build url */
-#ifdef SERF_VERBOSE
-    printf("Url discovered: %s\n", c);
-#endif
-
-    status = apr_uri_parse(pool, c, &url);
-
-    /* We got something that was minimally useful. */
-    if (status == 0 && url.path) {
-        const char *path, *query, *fragment;
-
-        /* This is likely a relative URL. So, merge and hope for the
-         * best.
-         */
-        if (!url.hostinfo && url.path[0] != '/') {
-            struct iovec vec[2];
-            char *c;
-            apr_size_t nbytes;
-
-            c = strrchr(orig_path, '/');
-
-            /* assert c */
-            if (!c) {
-                return APR_EGENERAL;
-            }
-
-            vec[0].iov_base = (char*)orig_path;
-            vec[0].iov_len = c - orig_path + 1;
-
-            /* If the HTML is cute and gives us ./foo - skip the ./ */
-            if (url.path[0] == '.' && url.path[1] == '/') {
-                vec[1].iov_base = url.path + 2;
-                vec[1].iov_len = strlen(url.path + 2);
-            }
-            else if (url.path[0] == '.' && url.path[1] == '.') {
-                /* FIXME We could be cute and consolidate the path; we're a
-                 * toy example.  So no.
-                 */
-                vec[1].iov_base = url.path;
-                vec[1].iov_len = strlen(url.path);
-            }
-            else {
-                vec[1].iov_base = url.path;
-                vec[1].iov_len = strlen(url.path);
-            }
-
-            path = apr_pstrcatv(pool, vec, 2, &nbytes);
-        }
-        else {
-            path = url.path;
-        }
-
-        query = url.query;
-        fragment = url.fragment;
-
-        return create_request(url.hostinfo, path, query, fragment, ctx, pool);
-    }
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t find_href(apr_xml_elem *e, const char *orig_path,
-                              parser_baton_t *ctx, apr_pool_t *pool)
-{
-    apr_status_t status;
-
-    do {
-        /* print */
-        if (e->name[0] == 'a' && e->name[1] == '\0') {
-            apr_xml_attr *a;
-
-            a = e->attr;
-            while (a) {
-                if (strcasecmp(a->name, "href") == 0) {
-                    break;
-                }
-                a = a->next;
-            }
-            if (a) {
-                status = put_req(a->value, orig_path, ctx, pool);
-                if (status) {
-                    return status;
-                }
-            }
-        }
-
-        if (e->first_child) {
-            status = find_href(e->first_child, orig_path, ctx, pool);
-            if (status) {
-                return status;
-            }
-        }
-
-        e = e->next;
-    }
-    while (e);
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t find_href_doc(apr_xml_doc *doc, const char *path,
-                                  parser_baton_t *ctx,
-                                  apr_pool_t *pool)
-{
-    return find_href(doc->root, path, ctx, pool);
-}
-
-static void * APR_THREAD_FUNC parser_thread(apr_thread_t *thread, void *data)
-{
-    apr_status_t status;
-    apr_pool_t *pool, *subpool;
-    parser_baton_t *ctx;
-
-    ctx = (parser_baton_t*)data;
-    pool = apr_thread_pool_get(thread);
-
-    apr_pool_create(&subpool, pool);
-
-    while (1) {
-        doc_path_t *dup;
-
-        apr_pool_clear(subpool);
-
-        /* Grab it. */
-        apr_thread_mutex_lock(ctx->mutex);
-        /* Sleep. */
-        apr_thread_cond_wait(ctx->condvar, ctx->mutex);
-
-        /* Fetch the doc off the list. */
-        if (ctx->doc_queue->nelts) {
-            dup = *(doc_path_t**)(apr_array_pop(ctx->doc_queue));
-            /* dup = (ctx->doc_queue->conns->elts)[0]; */
-        }
-        else {
-            dup = NULL;
-        }
-
-        /* Don't need the mutex now. */
-        apr_thread_mutex_unlock(ctx->mutex);
-
-        /* Parse the doc/url pair. */
-        if (dup) {
-            status = find_href_doc(dup->doc, dup->path, ctx, subpool);
-            if (status) {
-                printf("Error finding hrefs: %d %s\n", status, dup->path);
-            }
-            /* Free the doc pair and its pool. */
-            apr_pool_destroy(dup->pool);
-            serf_bucket_mem_free(ctx->doc_queue_alloc, dup->path);
-            serf_bucket_mem_free(ctx->doc_queue_alloc, dup);
-        }
-
-        /* Hey are we done? */
-        if (!apr_atomic_read32(ctx->requests_outstanding)) {
-            break;
-        }
-    }
-    return NULL;
-}
-
-static void print_usage(apr_pool_t *pool)
-{
-    puts("serf_get [options] URL");
-    puts("-h\tDisplay this help");
-    puts("-v\tDisplay version");
-    puts("-H\tPrint response headers");
-    puts("-a <user:password> Present Basic authentication credentials");
-}
-
-int main(int argc, const char **argv)
-{
-    apr_status_t status;
-    apr_pool_t *pool;
-    apr_sockaddr_t *address;
-    serf_context_t *context;
-    serf_connection_t *connection;
-    app_baton_t app_ctx;
-    handler_baton_t *handler_ctx;
-    apr_uri_t url;
-    const char *raw_url, *method;
-    int count;
-    apr_getopt_t *opt;
-    char opt_c;
-    char *authn = NULL;
-    const char *opt_arg;
-
-    /* For the parser threads */
-    apr_thread_t *thread[3];
-    apr_threadattr_t *tattr;
-    apr_status_t parser_status;
-    parser_baton_t *parser_ctx;
-
-    apr_initialize();
-    atexit(apr_terminate);
-
-    apr_pool_create(&pool, NULL);
-    apr_atomic_init(pool);
-    /* serf_initialize(); */
-
-    /* Default to one round of fetching. */
-    count = 1;
-    /* Default to GET. */
-    method = "GET";
-
-    apr_getopt_init(&opt, pool, argc, argv);
-
-    while ((status = apr_getopt(opt, "a:hv", &opt_c, &opt_arg)) ==
-           APR_SUCCESS) {
-        int srclen, enclen;
-
-        switch (opt_c) {
-        case 'a':
-            srclen = strlen(opt_arg);
-            enclen = apr_base64_encode_len(srclen);
-            authn = apr_palloc(pool, enclen + 6);
-            strcpy(authn, "Basic ");
-            (void) apr_base64_encode(&authn[6], opt_arg, srclen);
-            break;
-        case 'h':
-            print_usage(pool);
-            exit(0);
-            break;
-        case 'v':
-            puts("Serf version: " SERF_VERSION_STRING);
-            exit(0);
-        default:
-            break;
-        }
-    }
-
-    if (opt->ind != opt->argc - 1) {
-        print_usage(pool);
-        exit(-1);
-    }
-
-    raw_url = argv[opt->ind];
-
-    apr_uri_parse(pool, raw_url, &url);
-    if (!url.port) {
-        url.port = apr_uri_port_of_scheme(url.scheme);
-    }
-    if (!url.path) {
-        url.path = "/";
-    }
-
-    if (strcasecmp(url.scheme, "https") == 0) {
-        app_ctx.using_ssl = 1;
-    }
-    else {
-        app_ctx.using_ssl = 0;
-    }
-
-    status = apr_sockaddr_info_get(&address,
-                                   url.hostname, APR_UNSPEC, url.port, 0,
-                                   pool);
-    if (status) {
-        printf("Error creating address: %d\n", status);
-        exit(1);
-    }
-
-    context = serf_context_create(pool);
-
-    /* ### Connection or Context should have an allocator? */
-    app_ctx.bkt_alloc = serf_bucket_allocator_create(pool, NULL, NULL);
-    app_ctx.ssl_ctx = NULL;
-    app_ctx.authn = authn;
-
-    connection = serf_connection_create(context, address,
-                                        conn_setup, &app_ctx,
-                                        closed_connection, &app_ctx,
-                                        pool);
-
-    handler_ctx = (handler_baton_t*)serf_bucket_mem_alloc(app_ctx.bkt_alloc,
-                                                      sizeof(handler_baton_t));
-    handler_ctx->allocator = app_ctx.bkt_alloc;
-    handler_ctx->doc_queue = apr_array_make(pool, 1, sizeof(doc_path_t*));
-    handler_ctx->doc_queue_alloc = app_ctx.bkt_alloc;
-
-    handler_ctx->requests_outstanding =
-        (apr_uint32_t*)serf_bucket_mem_alloc(app_ctx.bkt_alloc,
-                                             sizeof(apr_uint32_t));
-    apr_atomic_set32(handler_ctx->requests_outstanding, 0);
-    handler_ctx->hdr_read = 0;
-
-    parser_ctx = (void*)serf_bucket_mem_alloc(app_ctx.bkt_alloc,
-                                       sizeof(parser_baton_t));
-
-    parser_ctx->requests_outstanding = handler_ctx->requests_outstanding;
-    parser_ctx->connection = connection;
-    parser_ctx->app_ctx = &app_ctx;
-    parser_ctx->doc_queue = handler_ctx->doc_queue;
-    parser_ctx->doc_queue_alloc = handler_ctx->doc_queue_alloc;
-    /* Restrict ourselves to this host. */
-    parser_ctx->hostinfo = url.hostinfo;
-
-    status = apr_thread_mutex_create(&parser_ctx->mutex,
-                                     APR_THREAD_MUTEX_DEFAULT, pool);
-    if (status) {
-        printf("Couldn't create mutex %d\n", status);
-        return status;
-    }
-
-    status = apr_thread_cond_create(&parser_ctx->condvar, pool);
-    if (status) {
-        printf("Couldn't create condvar: %d\n", status);
-        return status;
-    }
-
-    /* Let the handler now which condvar to use. */
-    handler_ctx->doc_queue_condvar = parser_ctx->condvar;
-
-    apr_threadattr_create(&tattr, pool);
-
-    /* Start the parser thread. */
-    apr_thread_create(&thread[0], tattr, parser_thread, parser_ctx, pool);
-
-    /* Deliver the first request. */
-    create_request(url.hostinfo, url.path, NULL, NULL, parser_ctx, pool);
-
-    /* Go run our normal thread. */
-    while (1) {
-        int tries = 0;
-
-        status = serf_context_run(context, SERF_DURATION_FOREVER, pool);
-        if (APR_STATUS_IS_TIMEUP(status))
-            continue;
-        if (status) {
-            char buf[200];
-
-            printf("Error running context: (%d) %s\n", status,
-                   apr_strerror(status, buf, sizeof(buf)));
-            exit(1);
-        }
-
-        /* We run this check to allow our parser threads to add more
-         * requests to our queue.
-         */
-        for (tries = 0; tries < 3; tries++) {
-            if (!apr_atomic_read32(handler_ctx->requests_outstanding)) {
-#ifdef SERF_VERBOSE
-                printf("Waiting...");
-#endif
-                apr_sleep(100000);
-#ifdef SERF_VERBOSE
-                printf("Done\n");
-#endif
-            }
-            else {
-                break;
-            }
-        }
-        if (tries >= 3) {
-            break;
-        }
-        /* Debugging purposes only! */
-        serf_debug__closed_conn(app_ctx.bkt_alloc);
-    }
-
-    printf("Quitting...\n");
-    serf_connection_close(connection);
-
-    /* wake up the parser via condvar signal */
-    apr_thread_cond_signal(parser_ctx->condvar);
-
-    status = apr_thread_join(&parser_status, thread[0]);
-    if (status) {
-        printf("Error joining thread: %d\n", status);
-        return status;
-    }
-
-    serf_bucket_mem_free(app_ctx.bkt_alloc, handler_ctx->requests_outstanding);
-    serf_bucket_mem_free(app_ctx.bkt_alloc, parser_ctx);
-
-    apr_pool_destroy(pool);
-    return 0;
-}

Copied: vendor/serf/1.3.9/test/serf_spider.c (from rev 9259, vendor/serf/dist/test/serf_spider.c)
===================================================================
--- vendor/serf/1.3.9/test/serf_spider.c	                        (rev 0)
+++ vendor/serf/1.3.9/test/serf_spider.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,831 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_uri.h>
+#include <apr_strings.h>
+#include <apr_atomic.h>
+#include <apr_base64.h>
+#include <apr_getopt.h>
+#include <apr_xml.h>
+#include <apr_thread_proc.h>
+#include <apr_thread_mutex.h>
+#include <apr_thread_cond.h>
+#include <apr_version.h>
+
+#include "serf.h"
+#include "serf_bucket_util.h"
+
+/*#define SERF_VERBOSE*/
+
+#if !APR_HAS_THREADS
+#error serf spider needs threads.
+#endif
+
+/* This is a rough-sketch example of how a multi-threaded spider could be
+ * constructed using serf.
+ *
+ * A network thread will read in a URL and feed it into an expat parser.
+ * After the entire response is read, the XML structure and the path is
+ * passed to a set of parser threads.  These threads will scan the document
+ * for HTML href's and queue up any links that it finds.
+ *
+ * It does try to stay on the same server as it only uses one connection.
+ *
+ * Because we feed the responses into an XML parser, the documents must be
+ * well-formed XHTML.
+ *
+ * There is no duplicate link detection.  You've been warned.
+ */
+
+/* The structure passed to the parser thread after we've read the entire
+ * response.
+ */
+typedef struct {
+    apr_xml_doc *doc;
+    char *path;
+    apr_pool_t *pool;
+} doc_path_t;
+
+typedef struct {
+    const char *authn;
+    int using_ssl;
+    serf_ssl_context_t *ssl_ctx;
+    serf_bucket_alloc_t *bkt_alloc;
+} app_baton_t;
+
+static void closed_connection(serf_connection_t *conn,
+                              void *closed_baton,
+                              apr_status_t why,
+                              apr_pool_t *pool)
+{
+    if (why) {
+        abort();
+    }
+}
+
+static apr_status_t conn_setup(apr_socket_t *skt,
+                                serf_bucket_t **input_bkt,
+                                serf_bucket_t **output_bkt,
+                                void *setup_baton,
+                                apr_pool_t *pool)
+{
+    serf_bucket_t *c;
+    app_baton_t *ctx = setup_baton;
+
+    c = serf_bucket_socket_create(skt, ctx->bkt_alloc);
+    if (ctx->using_ssl) {
+        c = serf_bucket_ssl_decrypt_create(c, ctx->ssl_ctx, ctx->bkt_alloc);
+    }
+
+    *input_bkt = c;
+
+    return APR_SUCCESS;
+}
+
+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;
+
+    /* 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);
+
+    return serf_bucket_response_create(c, bkt_alloc);
+}
+
+typedef struct {
+    serf_bucket_alloc_t *allocator;
+#if APR_MAJOR_VERSION > 0
+    apr_uint32_t *requests_outstanding;
+#else
+    apr_atomic_t *requests_outstanding;
+#endif
+    serf_bucket_alloc_t *doc_queue_alloc;
+    apr_array_header_t *doc_queue;
+    apr_thread_cond_t *doc_queue_condvar;
+
+    const char *hostinfo;
+
+    /* includes: path, query, fragment. */
+    char *full_path;
+    apr_size_t full_path_len;
+
+    char *path;
+    apr_size_t path_len;
+
+    char *query;
+    apr_size_t query_len;
+
+    char *fragment;
+    apr_size_t fragment_len;
+
+    apr_xml_parser *parser;
+    apr_pool_t *parser_pool;
+
+    int hdr_read;
+    int is_html;
+
+    serf_response_acceptor_t acceptor;
+    void *acceptor_baton;
+    serf_response_handler_t handler;
+
+    app_baton_t *app_ctx;
+} handler_baton_t;
+
+/* Kludges for APR 0.9 support. */
+#if APR_MAJOR_VERSION == 0
+#define apr_atomic_inc32 apr_atomic_inc
+#define apr_atomic_dec32 apr_atomic_dec
+#define apr_atomic_read32 apr_atomic_read
+#define apr_atomic_set32 apr_atomic_set
+#endif
+
+static apr_status_t handle_response(serf_request_t *request,
+                                    serf_bucket_t *response,
+                                    void *handler_baton,
+                                    apr_pool_t *pool)
+{
+    const char *data;
+    apr_size_t len;
+    serf_status_line sl;
+    apr_status_t status;
+    handler_baton_t *ctx = handler_baton;
+
+    if (!response) {
+        /* Oh no!  We've been cancelled! */
+        abort();
+    }
+
+    status = serf_bucket_response_status(response, &sl);
+    if (status) {
+        if (APR_STATUS_IS_EAGAIN(status)) {
+            return APR_SUCCESS;
+        }
+        abort();
+    }
+
+    while (1) {
+        status = serf_bucket_read(response, 2048, &data, &len);
+
+        if (SERF_BUCKET_READ_ERROR(status))
+            return status;
+
+        /*fwrite(data, 1, len, stdout);*/
+
+        if (!ctx->hdr_read) {
+            serf_bucket_t *hdrs;
+            const char *val;
+
+            printf("Processing %s\n", ctx->path);
+
+            hdrs = serf_bucket_response_get_headers(response);
+            val = serf_bucket_headers_get(hdrs, "Content-Type");
+            /* FIXME: This check isn't quite right because Content-Type could
+             * be decorated; ideally strcasestr would be correct.
+             */
+            if (val && strcasecmp(val, "text/html") == 0) {
+                ctx->is_html = 1;
+                apr_pool_create(&ctx->parser_pool, NULL);
+                ctx->parser = apr_xml_parser_create(ctx->parser_pool);
+            }
+            else {
+                ctx->is_html = 0;
+            }
+            ctx->hdr_read = 1;
+        }
+        if (ctx->is_html) {
+            apr_status_t xs;
+
+            xs = apr_xml_parser_feed(ctx->parser, data, len);
+            /* Uh-oh. */
+            if (xs) {
+#ifdef SERF_VERBOSE
+                printf("XML parser error (feed): %d\n", xs);
+#endif
+                ctx->is_html = 0;
+            }
+        }
+
+        /* are we done yet? */
+        if (APR_STATUS_IS_EOF(status)) {
+
+            if (ctx->is_html) {
+                apr_xml_doc *xmld;
+                apr_status_t xs;
+                doc_path_t *dup;
+
+                xs = apr_xml_parser_done(ctx->parser, &xmld);
+                if (xs) {
+#ifdef SERF_VERBOSE
+                    printf("XML parser error (done): %d\n", xs);
+#endif
+                    return xs;
+                }
+                dup = (doc_path_t*)
+                    serf_bucket_mem_alloc(ctx->doc_queue_alloc,
+                                          sizeof(doc_path_t));
+                dup->doc = xmld;
+                dup->path = (char*)serf_bucket_mem_alloc(ctx->doc_queue_alloc,
+                                                         ctx->path_len);
+                memcpy(dup->path, ctx->path, ctx->path_len);
+                dup->pool = ctx->parser_pool;
+
+                *(doc_path_t **)apr_array_push(ctx->doc_queue) = dup;
+
+                apr_thread_cond_signal(ctx->doc_queue_condvar);
+            }
+
+            apr_atomic_dec32(ctx->requests_outstanding);
+            serf_bucket_mem_free(ctx->allocator, ctx->path);
+            if (ctx->query) {
+                serf_bucket_mem_free(ctx->allocator, ctx->query);
+                serf_bucket_mem_free(ctx->allocator, ctx->full_path);
+            }
+            if (ctx->fragment) {
+                serf_bucket_mem_free(ctx->allocator, ctx->fragment);
+            }
+            serf_bucket_mem_free(ctx->allocator, ctx);
+            return APR_EOF;
+        }
+
+        /* have we drained the response so far? */
+        if (APR_STATUS_IS_EAGAIN(status))
+            return APR_SUCCESS;
+
+        /* loop to read some more. */
+    }
+    /* NOTREACHED */
+}
+
+typedef struct {
+    apr_uint32_t *requests_outstanding;
+    serf_connection_t *connection;
+    apr_array_header_t *doc_queue;
+    serf_bucket_alloc_t *doc_queue_alloc;
+
+    apr_thread_cond_t *condvar;
+    apr_thread_mutex_t *mutex;
+
+    /* Master host: for now, we'll stick to one host. */
+    const char *hostinfo;
+
+    app_baton_t *app_ctx;
+} parser_baton_t;
+
+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 *hdrs_bkt;
+
+    *req_bkt = serf_bucket_request_create("GET", ctx->full_path, NULL,
+                                          serf_request_get_alloc(request));
+
+    hdrs_bkt = serf_bucket_request_get_headers(*req_bkt);
+
+    /* FIXME: Shouldn't we be able to figure out the host ourselves? */
+    serf_bucket_headers_setn(hdrs_bkt, "Host", ctx->hostinfo);
+    serf_bucket_headers_setn(hdrs_bkt, "User-Agent",
+                             "Serf/" SERF_VERSION_STRING);
+
+    /* Shouldn't serf do this for us? */
+    serf_bucket_headers_setn(hdrs_bkt, "Accept-Encoding", "gzip");
+
+    if (ctx->app_ctx->authn != NULL) {
+        serf_bucket_headers_setn(hdrs_bkt, "Authorization",
+                                 ctx->app_ctx->authn);
+    }
+
+    if (ctx->app_ctx->using_ssl) {
+        serf_bucket_alloc_t *req_alloc;
+
+        req_alloc = serf_request_get_alloc(request);
+
+        if (ctx->app_ctx->ssl_ctx == NULL) {
+            *req_bkt = serf_bucket_ssl_encrypt_create(*req_bkt, NULL,
+                                                      ctx->app_ctx->bkt_alloc);
+            ctx->app_ctx->ssl_ctx =
+                serf_bucket_ssl_encrypt_context_get(*req_bkt);
+        }
+        else {
+            *req_bkt =
+                serf_bucket_ssl_encrypt_create(*req_bkt, ctx->app_ctx->ssl_ctx,
+                                               ctx->app_ctx->bkt_alloc);
+        }
+    }
+
+
+#ifdef SERF_VERBOSE
+    printf("Url requesting: %s\n", ctx->full_path);
+#endif
+
+    *acceptor = ctx->acceptor;
+    *acceptor_baton = ctx->acceptor_baton;
+    *handler = ctx->handler;
+    *handler_baton = ctx;
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t create_request(const char *hostinfo,
+                                   const char *path,
+                                   const char *query,
+                                   const char *fragment,
+                                   parser_baton_t *ctx,
+                                   apr_pool_t *tmppool)
+{
+    handler_baton_t *new_ctx;
+
+    if (hostinfo) {
+        /* Yes, this is a pointer comparison; not a string comparison. */
+        if (hostinfo != ctx->hostinfo) {
+            /* Not on the same host; ignore */
+            return APR_SUCCESS;
+        }
+    }
+
+    new_ctx = (handler_baton_t*)serf_bucket_mem_alloc(ctx->app_ctx->bkt_alloc,
+                                                      sizeof(handler_baton_t));
+    new_ctx->allocator = ctx->app_ctx->bkt_alloc;
+    new_ctx->requests_outstanding = ctx->requests_outstanding;
+    new_ctx->app_ctx = ctx->app_ctx;
+
+    /* See above: this example restricts ourselves to the same vhost. */
+    new_ctx->hostinfo = ctx->hostinfo;
+
+    /* we need to copy it so it falls under the request's scope. */
+    new_ctx->path_len = strlen(path);
+    new_ctx->path = (char*)serf_bucket_mem_alloc(ctx->app_ctx->bkt_alloc,
+                                                 new_ctx->path_len + 1);
+    memcpy(new_ctx->path, path, new_ctx->path_len + 1);
+
+    /* we need to copy it so it falls under the request's scope. */
+    if (query) {
+        new_ctx->query_len = strlen(query);
+        new_ctx->query = (char*)serf_bucket_mem_alloc(ctx->app_ctx->bkt_alloc,
+                                                      new_ctx->query_len + 1);
+        memcpy(new_ctx->query, query, new_ctx->query_len + 1);
+    }
+    else {
+        new_ctx->query = NULL;
+        new_ctx->query_len = 0;
+    }
+
+    /* we need to copy it so it falls under the request's scope. */
+    if (fragment) {
+        new_ctx->fragment_len = strlen(fragment);
+        new_ctx->fragment =
+            (char*)serf_bucket_mem_alloc(ctx->app_ctx->bkt_alloc,
+                                         new_ctx->fragment_len + 1);
+        memcpy(new_ctx->fragment, fragment, new_ctx->fragment_len + 1);
+    }
+    else {
+        new_ctx->fragment = NULL;
+        new_ctx->fragment_len = 0;
+    }
+
+    if (!new_ctx->query) {
+        new_ctx->full_path = new_ctx->path;
+        new_ctx->full_path_len = new_ctx->path_len;
+    }
+    else {
+        new_ctx->full_path_len = new_ctx->path_len + new_ctx->query_len;
+        new_ctx->full_path =
+            (char*)serf_bucket_mem_alloc(ctx->app_ctx->bkt_alloc,
+                                         new_ctx->full_path_len + 1);
+        memcpy(new_ctx->full_path, new_ctx->path, new_ctx->path_len);
+        memcpy(new_ctx->full_path + new_ctx->path_len, new_ctx->query,
+               new_ctx->query_len + 1);
+    }
+
+    new_ctx->hdr_read = 0;
+
+    new_ctx->doc_queue_condvar = ctx->condvar;
+    new_ctx->doc_queue = ctx->doc_queue;
+    new_ctx->doc_queue_alloc = ctx->doc_queue_alloc;
+
+    new_ctx->acceptor = accept_response;
+    new_ctx->acceptor_baton = &ctx->app_ctx;
+    new_ctx->handler = handle_response;
+
+    apr_atomic_inc32(ctx->requests_outstanding);
+
+    serf_connection_request_create(ctx->connection, setup_request, new_ctx);
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t put_req(const char *c, const char *orig_path,
+                            parser_baton_t *ctx, apr_pool_t *pool)
+{
+    apr_status_t status;
+    apr_uri_t url;
+
+    /* Build url */
+#ifdef SERF_VERBOSE
+    printf("Url discovered: %s\n", c);
+#endif
+
+    status = apr_uri_parse(pool, c, &url);
+
+    /* We got something that was minimally useful. */
+    if (status == 0 && url.path) {
+        const char *path, *query, *fragment;
+
+        /* This is likely a relative URL. So, merge and hope for the
+         * best.
+         */
+        if (!url.hostinfo && url.path[0] != '/') {
+            struct iovec vec[2];
+            char *c;
+            apr_size_t nbytes;
+
+            c = strrchr(orig_path, '/');
+
+            /* assert c */
+            if (!c) {
+                return APR_EGENERAL;
+            }
+
+            vec[0].iov_base = (char*)orig_path;
+            vec[0].iov_len = c - orig_path + 1;
+
+            /* If the HTML is cute and gives us ./foo - skip the ./ */
+            if (url.path[0] == '.' && url.path[1] == '/') {
+                vec[1].iov_base = url.path + 2;
+                vec[1].iov_len = strlen(url.path + 2);
+            }
+            else if (url.path[0] == '.' && url.path[1] == '.') {
+                /* FIXME We could be cute and consolidate the path; we're a
+                 * toy example.  So no.
+                 */
+                vec[1].iov_base = url.path;
+                vec[1].iov_len = strlen(url.path);
+            }
+            else {
+                vec[1].iov_base = url.path;
+                vec[1].iov_len = strlen(url.path);
+            }
+
+            path = apr_pstrcatv(pool, vec, 2, &nbytes);
+        }
+        else {
+            path = url.path;
+        }
+
+        query = url.query;
+        fragment = url.fragment;
+
+        return create_request(url.hostinfo, path, query, fragment, ctx, pool);
+    }
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t find_href(apr_xml_elem *e, const char *orig_path,
+                              parser_baton_t *ctx, apr_pool_t *pool)
+{
+    apr_status_t status;
+
+    do {
+        /* print */
+        if (e->name[0] == 'a' && e->name[1] == '\0') {
+            apr_xml_attr *a;
+
+            a = e->attr;
+            while (a) {
+                if (strcasecmp(a->name, "href") == 0) {
+                    break;
+                }
+                a = a->next;
+            }
+            if (a) {
+                status = put_req(a->value, orig_path, ctx, pool);
+                if (status) {
+                    return status;
+                }
+            }
+        }
+
+        if (e->first_child) {
+            status = find_href(e->first_child, orig_path, ctx, pool);
+            if (status) {
+                return status;
+            }
+        }
+
+        e = e->next;
+    }
+    while (e);
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t find_href_doc(apr_xml_doc *doc, const char *path,
+                                  parser_baton_t *ctx,
+                                  apr_pool_t *pool)
+{
+    return find_href(doc->root, path, ctx, pool);
+}
+
+static void * APR_THREAD_FUNC parser_thread(apr_thread_t *thread, void *data)
+{
+    apr_status_t status;
+    apr_pool_t *pool, *subpool;
+    parser_baton_t *ctx;
+
+    ctx = (parser_baton_t*)data;
+    pool = apr_thread_pool_get(thread);
+
+    apr_pool_create(&subpool, pool);
+
+    while (1) {
+        doc_path_t *dup;
+
+        apr_pool_clear(subpool);
+
+        /* Grab it. */
+        apr_thread_mutex_lock(ctx->mutex);
+        /* Sleep. */
+        apr_thread_cond_wait(ctx->condvar, ctx->mutex);
+
+        /* Fetch the doc off the list. */
+        if (ctx->doc_queue->nelts) {
+            dup = *(doc_path_t**)(apr_array_pop(ctx->doc_queue));
+            /* dup = (ctx->doc_queue->conns->elts)[0]; */
+        }
+        else {
+            dup = NULL;
+        }
+
+        /* Don't need the mutex now. */
+        apr_thread_mutex_unlock(ctx->mutex);
+
+        /* Parse the doc/url pair. */
+        if (dup) {
+            status = find_href_doc(dup->doc, dup->path, ctx, subpool);
+            if (status) {
+                printf("Error finding hrefs: %d %s\n", status, dup->path);
+            }
+            /* Free the doc pair and its pool. */
+            apr_pool_destroy(dup->pool);
+            serf_bucket_mem_free(ctx->doc_queue_alloc, dup->path);
+            serf_bucket_mem_free(ctx->doc_queue_alloc, dup);
+        }
+
+        /* Hey are we done? */
+        if (!apr_atomic_read32(ctx->requests_outstanding)) {
+            break;
+        }
+    }
+    return NULL;
+}
+
+static void print_usage(apr_pool_t *pool)
+{
+    puts("serf_get [options] URL");
+    puts("-h\tDisplay this help");
+    puts("-v\tDisplay version");
+    puts("-H\tPrint response headers");
+    puts("-a <user:password> Present Basic authentication credentials");
+}
+
+int main(int argc, const char **argv)
+{
+    apr_status_t status;
+    apr_pool_t *pool;
+    apr_sockaddr_t *address;
+    serf_context_t *context;
+    serf_connection_t *connection;
+    app_baton_t app_ctx;
+    handler_baton_t *handler_ctx;
+    apr_uri_t url;
+    const char *raw_url, *method;
+    int count;
+    apr_getopt_t *opt;
+    char opt_c;
+    char *authn = NULL;
+    const char *opt_arg;
+
+    /* For the parser threads */
+    apr_thread_t *thread[3];
+    apr_threadattr_t *tattr;
+    apr_status_t parser_status;
+    parser_baton_t *parser_ctx;
+
+    apr_initialize();
+    atexit(apr_terminate);
+
+    apr_pool_create(&pool, NULL);
+    apr_atomic_init(pool);
+    /* serf_initialize(); */
+
+    /* Default to one round of fetching. */
+    count = 1;
+    /* Default to GET. */
+    method = "GET";
+
+    apr_getopt_init(&opt, pool, argc, argv);
+
+    while ((status = apr_getopt(opt, "a:hv", &opt_c, &opt_arg)) ==
+           APR_SUCCESS) {
+        int srclen, enclen;
+
+        switch (opt_c) {
+        case 'a':
+            srclen = strlen(opt_arg);
+            enclen = apr_base64_encode_len(srclen);
+            authn = apr_palloc(pool, enclen + 6);
+            strcpy(authn, "Basic ");
+            (void) apr_base64_encode(&authn[6], opt_arg, srclen);
+            break;
+        case 'h':
+            print_usage(pool);
+            exit(0);
+            break;
+        case 'v':
+            puts("Serf version: " SERF_VERSION_STRING);
+            exit(0);
+        default:
+            break;
+        }
+    }
+
+    if (opt->ind != opt->argc - 1) {
+        print_usage(pool);
+        exit(-1);
+    }
+
+    raw_url = argv[opt->ind];
+
+    apr_uri_parse(pool, raw_url, &url);
+    if (!url.port) {
+        url.port = apr_uri_port_of_scheme(url.scheme);
+    }
+    if (!url.path) {
+        url.path = "/";
+    }
+
+    if (strcasecmp(url.scheme, "https") == 0) {
+        app_ctx.using_ssl = 1;
+    }
+    else {
+        app_ctx.using_ssl = 0;
+    }
+
+    status = apr_sockaddr_info_get(&address,
+                                   url.hostname, APR_UNSPEC, url.port, 0,
+                                   pool);
+    if (status) {
+        printf("Error creating address: %d\n", status);
+        exit(1);
+    }
+
+    context = serf_context_create(pool);
+
+    /* ### Connection or Context should have an allocator? */
+    app_ctx.bkt_alloc = serf_bucket_allocator_create(pool, NULL, NULL);
+    app_ctx.ssl_ctx = NULL;
+    app_ctx.authn = authn;
+
+    connection = serf_connection_create(context, address,
+                                        conn_setup, &app_ctx,
+                                        closed_connection, &app_ctx,
+                                        pool);
+
+    handler_ctx = (handler_baton_t*)serf_bucket_mem_alloc(app_ctx.bkt_alloc,
+                                                      sizeof(handler_baton_t));
+    handler_ctx->allocator = app_ctx.bkt_alloc;
+    handler_ctx->doc_queue = apr_array_make(pool, 1, sizeof(doc_path_t*));
+    handler_ctx->doc_queue_alloc = app_ctx.bkt_alloc;
+
+    handler_ctx->requests_outstanding =
+        (apr_uint32_t*)serf_bucket_mem_alloc(app_ctx.bkt_alloc,
+                                             sizeof(apr_uint32_t));
+    apr_atomic_set32(handler_ctx->requests_outstanding, 0);
+    handler_ctx->hdr_read = 0;
+
+    parser_ctx = (void*)serf_bucket_mem_alloc(app_ctx.bkt_alloc,
+                                       sizeof(parser_baton_t));
+
+    parser_ctx->requests_outstanding = handler_ctx->requests_outstanding;
+    parser_ctx->connection = connection;
+    parser_ctx->app_ctx = &app_ctx;
+    parser_ctx->doc_queue = handler_ctx->doc_queue;
+    parser_ctx->doc_queue_alloc = handler_ctx->doc_queue_alloc;
+    /* Restrict ourselves to this host. */
+    parser_ctx->hostinfo = url.hostinfo;
+
+    status = apr_thread_mutex_create(&parser_ctx->mutex,
+                                     APR_THREAD_MUTEX_DEFAULT, pool);
+    if (status) {
+        printf("Couldn't create mutex %d\n", status);
+        return status;
+    }
+
+    status = apr_thread_cond_create(&parser_ctx->condvar, pool);
+    if (status) {
+        printf("Couldn't create condvar: %d\n", status);
+        return status;
+    }
+
+    /* Let the handler now which condvar to use. */
+    handler_ctx->doc_queue_condvar = parser_ctx->condvar;
+
+    apr_threadattr_create(&tattr, pool);
+
+    /* Start the parser thread. */
+    apr_thread_create(&thread[0], tattr, parser_thread, parser_ctx, pool);
+
+    /* Deliver the first request. */
+    create_request(url.hostinfo, url.path, NULL, NULL, parser_ctx, pool);
+
+    /* Go run our normal thread. */
+    while (1) {
+        int tries = 0;
+
+        status = serf_context_run(context, SERF_DURATION_FOREVER, pool);
+        if (APR_STATUS_IS_TIMEUP(status))
+            continue;
+        if (status) {
+            char buf[200];
+
+            printf("Error running context: (%d) %s\n", status,
+                   apr_strerror(status, buf, sizeof(buf)));
+            exit(1);
+        }
+
+        /* We run this check to allow our parser threads to add more
+         * requests to our queue.
+         */
+        for (tries = 0; tries < 3; tries++) {
+            if (!apr_atomic_read32(handler_ctx->requests_outstanding)) {
+#ifdef SERF_VERBOSE
+                printf("Waiting...");
+#endif
+                apr_sleep(100000);
+#ifdef SERF_VERBOSE
+                printf("Done\n");
+#endif
+            }
+            else {
+                break;
+            }
+        }
+        if (tries >= 3) {
+            break;
+        }
+        /* Debugging purposes only! */
+        serf_debug__closed_conn(app_ctx.bkt_alloc);
+    }
+
+    printf("Quitting...\n");
+    serf_connection_close(connection);
+
+    /* wake up the parser via condvar signal */
+    apr_thread_cond_signal(parser_ctx->condvar);
+
+    status = apr_thread_join(&parser_status, thread[0]);
+    if (status) {
+        printf("Error joining thread: %d\n", status);
+        return status;
+    }
+
+    serf_bucket_mem_free(app_ctx.bkt_alloc, handler_ctx->requests_outstanding);
+    serf_bucket_mem_free(app_ctx.bkt_alloc, parser_ctx);
+
+    apr_pool_destroy(pool);
+    return 0;
+}

Deleted: vendor/serf/1.3.9/test/server/test_server.c
===================================================================
--- vendor/serf/dist/test/server/test_server.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/test/server/test_server.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,663 +0,0 @@
-/* Copyright 2011 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 "serf_private.h" /* for serf__log and serf__bucket_stream_create */
-
-#include "test_server.h"
-
-#define BUFSIZE 8192
-
-/* Cleanup callback for a server. */
-static apr_status_t cleanup_server(void *baton)
-{
-    serv_ctx_t *servctx = baton;
-    apr_status_t status;
-
-    if (servctx->serv_sock)
-      status = apr_socket_close(servctx->serv_sock);
-    else
-      status = APR_EGENERAL;
-
-    if (servctx->client_sock) {
-        apr_socket_close(servctx->client_sock);
-    }
-
-    return status;
-}
-
-/* Replay support functions */
-static void next_message(serv_ctx_t *servctx)
-{
-    servctx->cur_message++;
-}
-
-static void next_action(serv_ctx_t *servctx)
-{
-    servctx->cur_action++;
-    servctx->action_buf_pos = 0;
-}
-
-static apr_status_t
-socket_write(serv_ctx_t *serv_ctx, const char *data,
-             apr_size_t *len)
-{
-    return apr_socket_send(serv_ctx->client_sock, data, len);
-}
-
-static apr_status_t
-socket_read(serv_ctx_t *serv_ctx, char *data,
-            apr_size_t *len)
-{
-    return apr_socket_recv(serv_ctx->client_sock, data, len);
-}
-
-static apr_status_t
-create_client_socket(apr_socket_t **skt,
-                     serv_ctx_t *servctx,
-                     const char *url)
-{
-    apr_sockaddr_t *address;
-    apr_uri_t uri;
-    apr_status_t status;
-
-    status = apr_uri_parse(servctx->pool, url, &uri);
-    if (status != APR_SUCCESS)
-        return status;
-
-    status = apr_sockaddr_info_get(&address,
-                                   uri.hostname,
-                                   APR_UNSPEC,
-                                   uri.port,
-                                   0,
-                                   servctx->pool);
-    if (status != APR_SUCCESS)
-        return status;
-
-    status = apr_socket_create(skt,
-                               address->family,
-                               SOCK_STREAM,
-#if APR_MAJOR_VERSION > 0
-                               APR_PROTO_TCP,
-#endif
-                               servctx->pool);
-    if (status != APR_SUCCESS)
-        return status;
-
-    /* Set the socket to be non-blocking */
-    status = apr_socket_timeout_set(*skt, 0);
-    if (status != APR_SUCCESS)
-        return status;
-
-    status = apr_socket_connect(*skt, address);
-    if (status != APR_SUCCESS && !APR_STATUS_IS_EINPROGRESS(status))
-        return status;
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t detect_eof(void *baton, serf_bucket_t *aggregate_bucket)
-{
-    return APR_EAGAIN;
-}
-
-/* Verify received requests and take the necessary actions
-   (return a response, kill the connection ...) */
-static apr_status_t replay(serv_ctx_t *servctx,
-                           apr_int16_t rtnevents,
-                           apr_pool_t *pool)
-{
-    apr_status_t status = APR_SUCCESS;
-    test_server_action_t *action;
-
-    if (rtnevents & APR_POLLIN) {
-        if (servctx->message_list == NULL) {
-            /* we're not expecting any requests to reach this server! */
-            serf__log(TEST_VERBOSE, __FILE__,
-                      "Received request where none was expected.\n");
-
-            return SERF_ERROR_ISSUE_IN_TESTSUITE;
-        }
-
-        if (servctx->cur_action >= servctx->action_count) {
-            char buf[128];
-            apr_size_t len = sizeof(buf);
-
-            status = servctx->read(servctx, buf, &len);
-            if (! APR_STATUS_IS_EAGAIN(status)) {
-                /* we're out of actions! */
-                serf__log(TEST_VERBOSE, __FILE__,
-                          "Received more requests than expected.\n");
-
-                return SERF_ERROR_ISSUE_IN_TESTSUITE;
-            }
-            return status;
-        }
-
-        action = &servctx->action_list[servctx->cur_action];
-
-        serf__log(TEST_VERBOSE, __FILE__,
-                  "POLLIN while replaying action %d, kind: %d.\n",
-                  servctx->cur_action, action->kind);
-
-        /* Read the remaining data from the client and kill the socket. */
-        if (action->kind == SERVER_IGNORE_AND_KILL_CONNECTION) {
-            char buf[128];
-            apr_size_t len = sizeof(buf);
-
-            status = servctx->read(servctx, buf, &len);
-
-            if (status == APR_EOF) {
-                serf__log(TEST_VERBOSE, __FILE__,
-                          "Killing this connection.\n");
-                apr_socket_close(servctx->client_sock);
-                servctx->client_sock = NULL;
-                next_action(servctx);
-                return APR_SUCCESS;
-            }
-
-            return status;
-        }
-        else if (action->kind == SERVER_RECV ||
-                 (action->kind == SERVER_RESPOND &&
-                  servctx->outstanding_responses == 0)) {
-            apr_size_t msg_len, len;
-            char buf[128];
-            test_server_message_t *message;
-
-            message = &servctx->message_list[servctx->cur_message];
-            msg_len = strlen(message->text);
-
-            do
-            {
-                len = msg_len - servctx->message_buf_pos;
-                if (len > sizeof(buf))
-                    len = sizeof(buf);
-
-                status = servctx->read(servctx, buf, &len);
-                if (SERF_BUCKET_READ_ERROR(status))
-                    return status;
-
-                if (status == APR_EOF) {
-                    serf__log(TEST_VERBOSE, __FILE__,
-                              "Server: Client hung up the connection.\n");
-                    break;
-                }
-                if (servctx->options & TEST_SERVER_DUMP)
-                    fwrite(buf, len, 1, stdout);
-
-                if (strncmp(buf,
-                            message->text + servctx->message_buf_pos,
-                            len) != 0) {
-                    /* ## TODO: Better diagnostics. */
-                    printf("Expected: (\n");
-                    fwrite(message->text + servctx->message_buf_pos, len, 1,
-                           stdout);
-                    printf(")\n");
-                    printf("Actual: (\n");
-                    fwrite(buf, len, 1, stdout);
-                    printf(")\n");
-
-                    return SERF_ERROR_ISSUE_IN_TESTSUITE;
-                }
-
-                servctx->message_buf_pos += len;
-
-                if (servctx->message_buf_pos >= msg_len) {
-                    next_message(servctx);
-                    servctx->message_buf_pos -= msg_len;
-                    if (action->kind == SERVER_RESPOND)
-                        servctx->outstanding_responses++;
-                    if (action->kind == SERVER_RECV)
-                        next_action(servctx);
-                    break;
-                }
-            } while (!status);
-        }
-        else if (action->kind == PROXY_FORWARD) {
-            apr_size_t len;
-            char buf[BUFSIZE];
-            serf_bucket_t *tmp;
-
-            /* Read all incoming data from the client to forward it to the
-               server later. */
-            do
-            {
-                len = BUFSIZE;
-
-                status = servctx->read(servctx, buf, &len);
-                if (SERF_BUCKET_READ_ERROR(status))
-                    return status;
-
-                serf__log(TEST_VERBOSE, __FILE__,
-                          "proxy: reading %d bytes %.*s from client with "
-                          "status %d.\n",
-                          len, len, buf, status);
-
-                if (status == APR_EOF) {
-                    serf__log(TEST_VERBOSE, __FILE__,
-                              "Proxy: client hung up the connection. Reset the "
-                              "connection to the server.\n");
-                    /* We have to stop forwarding, if a new connection opens
-                       the CONNECT request should not be forwarded to the
-                       server. */
-                    next_action(servctx);
-                }
-                if (!servctx->servstream)
-                    servctx->servstream = serf__bucket_stream_create(
-                                              servctx->allocator,
-                                              detect_eof,servctx);
-                if (len) {
-                    tmp = serf_bucket_simple_copy_create(buf, len,
-                                                         servctx->allocator);
-                    serf_bucket_aggregate_append(servctx->servstream, tmp);
-                }
-            } while (!status);
-        }
-    }
-    if (rtnevents & APR_POLLOUT) {
-        action = &servctx->action_list[servctx->cur_action];
-
-        serf__log(TEST_VERBOSE, __FILE__,
-                  "POLLOUT when replaying action %d, kind: %d.\n", servctx->cur_action,
-                  action->kind);
-
-        if (action->kind == SERVER_RESPOND && servctx->outstanding_responses) {
-            apr_size_t msg_len;
-            apr_size_t len;
-
-            msg_len = strlen(action->text);
-            len = msg_len - servctx->action_buf_pos;
-
-            status = servctx->send(servctx,
-                                   action->text + servctx->action_buf_pos,
-                                   &len);
-            if (status != APR_SUCCESS)
-                return status;
-
-            if (servctx->options & TEST_SERVER_DUMP)
-                fwrite(action->text + servctx->action_buf_pos, len, 1, stdout);
-
-            servctx->action_buf_pos += len;
-
-            if (servctx->action_buf_pos >= msg_len) {
-                next_action(servctx);
-                servctx->outstanding_responses--;
-            }
-        }
-        else if (action->kind == SERVER_KILL_CONNECTION ||
-                 action->kind == SERVER_IGNORE_AND_KILL_CONNECTION) {
-            serf__log(TEST_VERBOSE, __FILE__,
-                      "Killing this connection.\n");
-            apr_socket_close(servctx->client_sock);
-            servctx->client_sock = NULL;
-            next_action(servctx);
-        }
-        else if (action->kind == PROXY_FORWARD) {
-            apr_size_t len;
-            char *buf;
-
-            if (!servctx->proxy_client_sock) {
-                serf__log(TEST_VERBOSE, __FILE__, "Proxy: setting up connection "
-                          "to server.\n");
-                status = create_client_socket(&servctx->proxy_client_sock,
-                                              servctx, action->text);
-                if (!servctx->clientstream)
-                    servctx->clientstream = serf__bucket_stream_create(
-                                                servctx->allocator,
-                                                detect_eof,servctx);
-            }
-
-            /* Send all data received from the server to the client. */
-            do
-            {
-                apr_size_t readlen;
-
-                readlen = BUFSIZE;
-
-                status = serf_bucket_read(servctx->clientstream, readlen,
-                                          &buf, &readlen);
-                if (SERF_BUCKET_READ_ERROR(status))
-                    return status;
-                if (!readlen)
-                    break;
-
-                len = readlen;
-
-                serf__log(TEST_VERBOSE, __FILE__,
-                          "proxy: sending %d bytes to client.\n", len);
-                status = servctx->send(servctx, buf, &len);
-                if (status != APR_SUCCESS) {
-                    return status;
-                }
-                
-                if (len != readlen) /* abort for now, return buf to aggregate
-                                       if not everything could be sent. */
-                    return APR_EGENERAL;
-            } while (!status);
-        }
-    }
-    else if (rtnevents & APR_POLLIN) {
-        /* ignore */
-    }
-    else {
-        printf("Unknown rtnevents: %d\n", rtnevents);
-        abort();
-    }
-
-    return status;
-}
-
-/* Exchange data between proxy and server */
-static apr_status_t proxy_replay(serv_ctx_t *servctx,
-                                 apr_int16_t rtnevents,
-                                 apr_pool_t *pool)
-{
-    apr_status_t status;
-
-    if (rtnevents & APR_POLLIN) {
-        apr_size_t len;
-        char buf[BUFSIZE];
-        serf_bucket_t *tmp;
-
-        serf__log(TEST_VERBOSE, __FILE__, "proxy_replay: POLLIN\n");
-        /* Read all incoming data from the server to forward it to the
-           client later. */
-        do
-        {
-            len = BUFSIZE;
-
-            status = apr_socket_recv(servctx->proxy_client_sock, buf, &len);
-            if (SERF_BUCKET_READ_ERROR(status))
-                return status;
-
-            serf__log(TEST_VERBOSE, __FILE__,
-                      "proxy: reading %d bytes %.*s from server.\n",
-                      len, len, buf);
-            tmp = serf_bucket_simple_copy_create(buf, len,
-                                                 servctx->allocator);
-            serf_bucket_aggregate_append(servctx->clientstream, tmp);
-        } while (!status);
-    }
-
-    if (rtnevents & APR_POLLOUT) {
-        apr_size_t len;
-        char *buf;
-
-        serf__log(TEST_VERBOSE, __FILE__, "proxy_replay: POLLOUT\n");
-        /* Send all data received from the client to the server. */
-        do
-        {
-            apr_size_t readlen;
-
-            readlen = BUFSIZE;
-
-            if (!servctx->servstream)
-                servctx->servstream = serf__bucket_stream_create(
-                                          servctx->allocator,
-                                          detect_eof,servctx);
-            status = serf_bucket_read(servctx->servstream, BUFSIZE,
-                                      &buf, &readlen);
-            if (SERF_BUCKET_READ_ERROR(status))
-                return status;
-            if (!readlen)
-                break;
-
-            len = readlen;
-
-            serf__log(TEST_VERBOSE, __FILE__,
-                      "proxy: sending %d bytes %.*s to server.\n",
-                      len, len, buf);
-            status = apr_socket_send(servctx->proxy_client_sock, buf, &len);
-            if (status != APR_SUCCESS) {
-                return status;
-            }
-
-            if (len != readlen) /* abort for now */
-                return APR_EGENERAL;
-        } while (!status);
-    }
-    else if (rtnevents & APR_POLLIN) {
-        /* ignore */
-    }
-    else {
-        printf("Unknown rtnevents: %d\n", rtnevents);
-        abort();
-    }
-
-    return status;
-}
-
-apr_status_t run_test_server(serv_ctx_t *servctx,
-                             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 */
-#ifdef BROKEN_WSAPOLL
-    status = apr_pollset_create_ex(&pollset, 32, pool, 0,
-                                 APR_POLLSET_SELECT);
-#else
-    status = apr_pollset_create(&pollset, 32, pool, 0);
-#endif
-
-    if (status != APR_SUCCESS)
-        return status;
-
-    /* Don't accept new connection while processing client connection. At
-       least for present time.*/
-    if (servctx->client_sock) {
-        apr_pollfd_t pfd = { 0 };
-
-        pfd.desc_type = APR_POLL_SOCKET;
-        pfd.desc.s = servctx->client_sock;
-        pfd.reqevents = APR_POLLIN | APR_POLLOUT;
-
-        status = apr_pollset_add(pollset, &pfd);
-        if (status != APR_SUCCESS)
-            goto cleanup;
-
-        if (servctx->proxy_client_sock) {
-            apr_pollfd_t pfd = { 0 };
-
-            pfd.desc_type = APR_POLL_SOCKET;
-            pfd.desc.s = servctx->proxy_client_sock;
-            pfd.reqevents = APR_POLLIN | APR_POLLOUT;
-
-            status = apr_pollset_add(pollset, &pfd);
-            if (status != APR_SUCCESS)
-                goto cleanup;
-        }
-    }
-    else {
-        apr_pollfd_t pfd = { 0 };
-
-        pfd.desc_type = APR_POLL_SOCKET;
-        pfd.desc.s = servctx->serv_sock;
-        pfd.reqevents = APR_POLLIN;
-
-        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 == servctx->serv_sock) {
-            status = apr_socket_accept(&servctx->client_sock, servctx->serv_sock,
-                                       servctx->pool);
-            if (status != APR_SUCCESS)
-                goto cleanup;
-
-            serf__log_skt(TEST_VERBOSE, __FILE__, servctx->client_sock,
-                          "server/proxy accepted incoming connection.\n");
-
-
-            apr_socket_opt_set(servctx->client_sock, APR_SO_NONBLOCK, 1);
-            apr_socket_timeout_set(servctx->client_sock, 0);
-
-            status = APR_SUCCESS;
-            goto cleanup;
-        }
-
-        if (desc->desc.s == servctx->client_sock) {
-            if (servctx->handshake) {
-                status = servctx->handshake(servctx);
-                if (status)
-                    goto cleanup;
-            }
-
-            /* Replay data to socket. */
-            status = replay(servctx, desc->rtnevents, pool);
-
-            if (APR_STATUS_IS_EOF(status)) {
-                apr_socket_close(servctx->client_sock);
-                servctx->client_sock = NULL;
-                if (servctx->reset)
-                    servctx->reset(servctx);
-
-                /* If this is a proxy and the client closed the connection, also
-                   close the connection to the server. */
-                if (servctx->proxy_client_sock) {
-                    apr_socket_close(servctx->proxy_client_sock);
-                    servctx->proxy_client_sock = NULL;
-                    goto cleanup;
-                }
-            }
-            else if (APR_STATUS_IS_EAGAIN(status)) {
-                status = APR_SUCCESS;
-            }
-            else if (status != APR_SUCCESS) {
-                /* Real error. */
-                goto cleanup;
-            }
-        }
-        if (desc->desc.s == servctx->proxy_client_sock) {
-            /* Replay data to proxy socket. */
-            status = proxy_replay(servctx, desc->rtnevents, pool);
-            if (APR_STATUS_IS_EOF(status)) {
-                apr_socket_close(servctx->proxy_client_sock);
-                servctx->proxy_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;
-}
-
-
-/* Setup the context needed to start a TCP server on adress.
-   message_list is a list of expected requests.
-   action_list is the list of responses to be returned in order.
- */
-void setup_test_server(serv_ctx_t **servctx_p,
-                       apr_sockaddr_t *address,
-                       test_server_message_t *message_list,
-                       apr_size_t message_count,
-                       test_server_action_t *action_list,
-                       apr_size_t action_count,
-                       apr_int32_t options,
-                       apr_pool_t *pool)
-{
-    serv_ctx_t *servctx;
-
-    servctx = apr_pcalloc(pool, sizeof(*servctx));
-    apr_pool_cleanup_register(pool, servctx,
-                              cleanup_server,
-                              apr_pool_cleanup_null);
-    *servctx_p = servctx;
-
-    servctx->serv_addr = address;
-    servctx->options = options;
-    servctx->pool = pool;
-    servctx->allocator = serf_bucket_allocator_create(pool, NULL, NULL);
-    servctx->message_list = message_list;
-    servctx->message_count = message_count;
-    servctx->action_list = action_list;
-    servctx->action_count = action_count;
-
-    /* Start replay from first action. */
-    servctx->cur_action = 0;
-    servctx->action_buf_pos = 0;
-    servctx->outstanding_responses = 0;
-
-    servctx->read = socket_read;
-    servctx->send = socket_write;
-
-    *servctx_p = servctx;
-}
-
-apr_status_t start_test_server(serv_ctx_t *servctx)
-{
-    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, servctx->serv_addr->family,
-                               SOCK_STREAM, 0,
-                               servctx->pool);
-#else
-    status = apr_socket_create(&serv_sock, servctx->serv_addr->family,
-                               SOCK_STREAM,
-                               servctx->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, servctx->serv_addr);
-    if (status != APR_SUCCESS)
-        return status;
-
-    /* listen for clients */
-    status = apr_socket_listen(serv_sock, SOMAXCONN);
-    if (status != APR_SUCCESS)
-        return status;
-
-    servctx->serv_sock = serv_sock;
-    servctx->client_sock = NULL;
-
-    return APR_SUCCESS;
-}

Copied: vendor/serf/1.3.9/test/server/test_server.c (from rev 9259, vendor/serf/dist/test/server/test_server.c)
===================================================================
--- vendor/serf/1.3.9/test/server/test_server.c	                        (rev 0)
+++ vendor/serf/1.3.9/test/server/test_server.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,668 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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 "serf_private.h" /* for serf__log and serf__bucket_stream_create */
+
+#include "test_server.h"
+
+#define BUFSIZE 8192
+
+/* Cleanup callback for a server. */
+static apr_status_t cleanup_server(void *baton)
+{
+    serv_ctx_t *servctx = baton;
+    apr_status_t status;
+
+    if (servctx->serv_sock)
+      status = apr_socket_close(servctx->serv_sock);
+    else
+      status = APR_EGENERAL;
+
+    if (servctx->client_sock) {
+        apr_socket_close(servctx->client_sock);
+    }
+
+    return status;
+}
+
+/* Replay support functions */
+static void next_message(serv_ctx_t *servctx)
+{
+    servctx->cur_message++;
+}
+
+static void next_action(serv_ctx_t *servctx)
+{
+    servctx->cur_action++;
+    servctx->action_buf_pos = 0;
+}
+
+static apr_status_t
+socket_write(serv_ctx_t *serv_ctx, const char *data,
+             apr_size_t *len)
+{
+    return apr_socket_send(serv_ctx->client_sock, data, len);
+}
+
+static apr_status_t
+socket_read(serv_ctx_t *serv_ctx, char *data,
+            apr_size_t *len)
+{
+    return apr_socket_recv(serv_ctx->client_sock, data, len);
+}
+
+static apr_status_t
+create_client_socket(apr_socket_t **skt,
+                     serv_ctx_t *servctx,
+                     const char *url)
+{
+    apr_sockaddr_t *address;
+    apr_uri_t uri;
+    apr_status_t status;
+
+    status = apr_uri_parse(servctx->pool, url, &uri);
+    if (status != APR_SUCCESS)
+        return status;
+
+    status = apr_sockaddr_info_get(&address,
+                                   uri.hostname,
+                                   APR_UNSPEC,
+                                   uri.port,
+                                   0,
+                                   servctx->pool);
+    if (status != APR_SUCCESS)
+        return status;
+
+    status = apr_socket_create(skt,
+                               address->family,
+                               SOCK_STREAM,
+#if APR_MAJOR_VERSION > 0
+                               APR_PROTO_TCP,
+#endif
+                               servctx->pool);
+    if (status != APR_SUCCESS)
+        return status;
+
+    /* Set the socket to be non-blocking */
+    status = apr_socket_timeout_set(*skt, 0);
+    if (status != APR_SUCCESS)
+        return status;
+
+    status = apr_socket_connect(*skt, address);
+    if (status != APR_SUCCESS && !APR_STATUS_IS_EINPROGRESS(status))
+        return status;
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t detect_eof(void *baton, serf_bucket_t *aggregate_bucket)
+{
+    return APR_EAGAIN;
+}
+
+/* Verify received requests and take the necessary actions
+   (return a response, kill the connection ...) */
+static apr_status_t replay(serv_ctx_t *servctx,
+                           apr_int16_t rtnevents,
+                           apr_pool_t *pool)
+{
+    apr_status_t status = APR_SUCCESS;
+    test_server_action_t *action;
+
+    if (rtnevents & APR_POLLIN) {
+        if (servctx->message_list == NULL) {
+            /* we're not expecting any requests to reach this server! */
+            serf__log(TEST_VERBOSE, __FILE__,
+                      "Received request where none was expected.\n");
+
+            return SERF_ERROR_ISSUE_IN_TESTSUITE;
+        }
+
+        if (servctx->cur_action >= servctx->action_count) {
+            char buf[128];
+            apr_size_t len = sizeof(buf);
+
+            status = servctx->read(servctx, buf, &len);
+            if (! APR_STATUS_IS_EAGAIN(status)) {
+                /* we're out of actions! */
+                serf__log(TEST_VERBOSE, __FILE__,
+                          "Received more requests than expected.\n");
+
+                return SERF_ERROR_ISSUE_IN_TESTSUITE;
+            }
+            return status;
+        }
+
+        action = &servctx->action_list[servctx->cur_action];
+
+        serf__log(TEST_VERBOSE, __FILE__,
+                  "POLLIN while replaying action %d, kind: %d.\n",
+                  servctx->cur_action, action->kind);
+
+        /* Read the remaining data from the client and kill the socket. */
+        if (action->kind == SERVER_IGNORE_AND_KILL_CONNECTION) {
+            char buf[128];
+            apr_size_t len = sizeof(buf);
+
+            status = servctx->read(servctx, buf, &len);
+
+            if (status == APR_EOF) {
+                serf__log(TEST_VERBOSE, __FILE__,
+                          "Killing this connection.\n");
+                apr_socket_close(servctx->client_sock);
+                servctx->client_sock = NULL;
+                next_action(servctx);
+                return APR_SUCCESS;
+            }
+
+            return status;
+        }
+        else if (action->kind == SERVER_RECV ||
+                 (action->kind == SERVER_RESPOND &&
+                  servctx->outstanding_responses == 0)) {
+            apr_size_t msg_len, len;
+            char buf[128];
+            test_server_message_t *message;
+
+            message = &servctx->message_list[servctx->cur_message];
+            msg_len = strlen(message->text);
+
+            do
+            {
+                len = msg_len - servctx->message_buf_pos;
+                if (len > sizeof(buf))
+                    len = sizeof(buf);
+
+                status = servctx->read(servctx, buf, &len);
+                if (SERF_BUCKET_READ_ERROR(status))
+                    return status;
+
+                if (status == APR_EOF) {
+                    serf__log(TEST_VERBOSE, __FILE__,
+                              "Server: Client hung up the connection.\n");
+                    break;
+                }
+                if (servctx->options & TEST_SERVER_DUMP)
+                    fwrite(buf, len, 1, stdout);
+
+                if (strncmp(buf,
+                            message->text + servctx->message_buf_pos,
+                            len) != 0) {
+                    /* ## TODO: Better diagnostics. */
+                    printf("Expected: (\n");
+                    fwrite(message->text + servctx->message_buf_pos, len, 1,
+                           stdout);
+                    printf(")\n");
+                    printf("Actual: (\n");
+                    fwrite(buf, len, 1, stdout);
+                    printf(")\n");
+
+                    return SERF_ERROR_ISSUE_IN_TESTSUITE;
+                }
+
+                servctx->message_buf_pos += len;
+
+                if (servctx->message_buf_pos >= msg_len) {
+                    next_message(servctx);
+                    servctx->message_buf_pos -= msg_len;
+                    if (action->kind == SERVER_RESPOND)
+                        servctx->outstanding_responses++;
+                    if (action->kind == SERVER_RECV)
+                        next_action(servctx);
+                    break;
+                }
+            } while (!status);
+        }
+        else if (action->kind == PROXY_FORWARD) {
+            apr_size_t len;
+            char buf[BUFSIZE];
+            serf_bucket_t *tmp;
+
+            /* Read all incoming data from the client to forward it to the
+               server later. */
+            do
+            {
+                len = BUFSIZE;
+
+                status = servctx->read(servctx, buf, &len);
+                if (SERF_BUCKET_READ_ERROR(status))
+                    return status;
+
+                serf__log(TEST_VERBOSE, __FILE__,
+                          "proxy: reading %d bytes %.*s from client with "
+                          "status %d.\n",
+                          len, len, buf, status);
+
+                if (status == APR_EOF) {
+                    serf__log(TEST_VERBOSE, __FILE__,
+                              "Proxy: client hung up the connection. Reset the "
+                              "connection to the server.\n");
+                    /* We have to stop forwarding, if a new connection opens
+                       the CONNECT request should not be forwarded to the
+                       server. */
+                    next_action(servctx);
+                }
+                if (!servctx->servstream)
+                    servctx->servstream = serf__bucket_stream_create(
+                                              servctx->allocator,
+                                              detect_eof,servctx);
+                if (len) {
+                    tmp = serf_bucket_simple_copy_create(buf, len,
+                                                         servctx->allocator);
+                    serf_bucket_aggregate_append(servctx->servstream, tmp);
+                }
+            } while (!status);
+        }
+    }
+    if (rtnevents & APR_POLLOUT) {
+        action = &servctx->action_list[servctx->cur_action];
+
+        serf__log(TEST_VERBOSE, __FILE__,
+                  "POLLOUT when replaying action %d, kind: %d.\n", servctx->cur_action,
+                  action->kind);
+
+        if (action->kind == SERVER_RESPOND && servctx->outstanding_responses) {
+            apr_size_t msg_len;
+            apr_size_t len;
+
+            msg_len = strlen(action->text);
+            len = msg_len - servctx->action_buf_pos;
+
+            status = servctx->send(servctx,
+                                   action->text + servctx->action_buf_pos,
+                                   &len);
+            if (status != APR_SUCCESS)
+                return status;
+
+            if (servctx->options & TEST_SERVER_DUMP)
+                fwrite(action->text + servctx->action_buf_pos, len, 1, stdout);
+
+            servctx->action_buf_pos += len;
+
+            if (servctx->action_buf_pos >= msg_len) {
+                next_action(servctx);
+                servctx->outstanding_responses--;
+            }
+        }
+        else if (action->kind == SERVER_KILL_CONNECTION ||
+                 action->kind == SERVER_IGNORE_AND_KILL_CONNECTION) {
+            serf__log(TEST_VERBOSE, __FILE__,
+                      "Killing this connection.\n");
+            apr_socket_close(servctx->client_sock);
+            servctx->client_sock = NULL;
+            next_action(servctx);
+        }
+        else if (action->kind == PROXY_FORWARD) {
+            apr_size_t len;
+            char *buf;
+
+            if (!servctx->proxy_client_sock) {
+                serf__log(TEST_VERBOSE, __FILE__, "Proxy: setting up connection "
+                          "to server.\n");
+                status = create_client_socket(&servctx->proxy_client_sock,
+                                              servctx, action->text);
+                if (!servctx->clientstream)
+                    servctx->clientstream = serf__bucket_stream_create(
+                                                servctx->allocator,
+                                                detect_eof,servctx);
+            }
+
+            /* Send all data received from the server to the client. */
+            do
+            {
+                apr_size_t readlen;
+
+                readlen = BUFSIZE;
+
+                status = serf_bucket_read(servctx->clientstream, readlen,
+                                          &buf, &readlen);
+                if (SERF_BUCKET_READ_ERROR(status))
+                    return status;
+                if (!readlen)
+                    break;
+
+                len = readlen;
+
+                serf__log(TEST_VERBOSE, __FILE__,
+                          "proxy: sending %d bytes to client.\n", len);
+                status = servctx->send(servctx, buf, &len);
+                if (status != APR_SUCCESS) {
+                    return status;
+                }
+                
+                if (len != readlen) /* abort for now, return buf to aggregate
+                                       if not everything could be sent. */
+                    return APR_EGENERAL;
+            } while (!status);
+        }
+    }
+    else if (rtnevents & APR_POLLIN) {
+        /* ignore */
+    }
+    else {
+        printf("Unknown rtnevents: %d\n", rtnevents);
+        abort();
+    }
+
+    return status;
+}
+
+/* Exchange data between proxy and server */
+static apr_status_t proxy_replay(serv_ctx_t *servctx,
+                                 apr_int16_t rtnevents,
+                                 apr_pool_t *pool)
+{
+    apr_status_t status;
+
+    if (rtnevents & APR_POLLIN) {
+        apr_size_t len;
+        char buf[BUFSIZE];
+        serf_bucket_t *tmp;
+
+        serf__log(TEST_VERBOSE, __FILE__, "proxy_replay: POLLIN\n");
+        /* Read all incoming data from the server to forward it to the
+           client later. */
+        do
+        {
+            len = BUFSIZE;
+
+            status = apr_socket_recv(servctx->proxy_client_sock, buf, &len);
+            if (SERF_BUCKET_READ_ERROR(status))
+                return status;
+
+            serf__log(TEST_VERBOSE, __FILE__,
+                      "proxy: reading %d bytes %.*s from server.\n",
+                      len, len, buf);
+            tmp = serf_bucket_simple_copy_create(buf, len,
+                                                 servctx->allocator);
+            serf_bucket_aggregate_append(servctx->clientstream, tmp);
+        } while (!status);
+    }
+
+    if (rtnevents & APR_POLLOUT) {
+        apr_size_t len;
+        char *buf;
+
+        serf__log(TEST_VERBOSE, __FILE__, "proxy_replay: POLLOUT\n");
+        /* Send all data received from the client to the server. */
+        do
+        {
+            apr_size_t readlen;
+
+            readlen = BUFSIZE;
+
+            if (!servctx->servstream)
+                servctx->servstream = serf__bucket_stream_create(
+                                          servctx->allocator,
+                                          detect_eof,servctx);
+            status = serf_bucket_read(servctx->servstream, BUFSIZE,
+                                      &buf, &readlen);
+            if (SERF_BUCKET_READ_ERROR(status))
+                return status;
+            if (!readlen)
+                break;
+
+            len = readlen;
+
+            serf__log(TEST_VERBOSE, __FILE__,
+                      "proxy: sending %d bytes %.*s to server.\n",
+                      len, len, buf);
+            status = apr_socket_send(servctx->proxy_client_sock, buf, &len);
+            if (status != APR_SUCCESS) {
+                return status;
+            }
+
+            if (len != readlen) /* abort for now */
+                return APR_EGENERAL;
+        } while (!status);
+    }
+    else if (rtnevents & APR_POLLIN) {
+        /* ignore */
+    }
+    else {
+        printf("Unknown rtnevents: %d\n", rtnevents);
+        abort();
+    }
+
+    return status;
+}
+
+apr_status_t run_test_server(serv_ctx_t *servctx,
+                             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 */
+#ifdef BROKEN_WSAPOLL
+    status = apr_pollset_create_ex(&pollset, 32, pool, 0,
+                                 APR_POLLSET_SELECT);
+#else
+    status = apr_pollset_create(&pollset, 32, pool, 0);
+#endif
+
+    if (status != APR_SUCCESS)
+        return status;
+
+    /* Don't accept new connection while processing client connection. At
+       least for present time.*/
+    if (servctx->client_sock) {
+        apr_pollfd_t pfd = { 0 };
+
+        pfd.desc_type = APR_POLL_SOCKET;
+        pfd.desc.s = servctx->client_sock;
+        pfd.reqevents = APR_POLLIN | APR_POLLOUT;
+
+        status = apr_pollset_add(pollset, &pfd);
+        if (status != APR_SUCCESS)
+            goto cleanup;
+
+        if (servctx->proxy_client_sock) {
+            apr_pollfd_t pfd = { 0 };
+
+            pfd.desc_type = APR_POLL_SOCKET;
+            pfd.desc.s = servctx->proxy_client_sock;
+            pfd.reqevents = APR_POLLIN | APR_POLLOUT;
+
+            status = apr_pollset_add(pollset, &pfd);
+            if (status != APR_SUCCESS)
+                goto cleanup;
+        }
+    }
+    else {
+        apr_pollfd_t pfd = { 0 };
+
+        pfd.desc_type = APR_POLL_SOCKET;
+        pfd.desc.s = servctx->serv_sock;
+        pfd.reqevents = APR_POLLIN;
+
+        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 == servctx->serv_sock) {
+            status = apr_socket_accept(&servctx->client_sock, servctx->serv_sock,
+                                       servctx->pool);
+            if (status != APR_SUCCESS)
+                goto cleanup;
+
+            serf__log_skt(TEST_VERBOSE, __FILE__, servctx->client_sock,
+                          "server/proxy accepted incoming connection.\n");
+
+
+            apr_socket_opt_set(servctx->client_sock, APR_SO_NONBLOCK, 1);
+            apr_socket_timeout_set(servctx->client_sock, 0);
+
+            status = APR_SUCCESS;
+            goto cleanup;
+        }
+
+        if (desc->desc.s == servctx->client_sock) {
+            if (servctx->handshake) {
+                status = servctx->handshake(servctx);
+                if (status)
+                    goto cleanup;
+            }
+
+            /* Replay data to socket. */
+            status = replay(servctx, desc->rtnevents, pool);
+
+            if (APR_STATUS_IS_EOF(status)) {
+                apr_socket_close(servctx->client_sock);
+                servctx->client_sock = NULL;
+                if (servctx->reset)
+                    servctx->reset(servctx);
+
+                /* If this is a proxy and the client closed the connection, also
+                   close the connection to the server. */
+                if (servctx->proxy_client_sock) {
+                    apr_socket_close(servctx->proxy_client_sock);
+                    servctx->proxy_client_sock = NULL;
+                    goto cleanup;
+                }
+            }
+            else if (APR_STATUS_IS_EAGAIN(status)) {
+                status = APR_SUCCESS;
+            }
+            else if (status != APR_SUCCESS) {
+                /* Real error. */
+                goto cleanup;
+            }
+        }
+        if (desc->desc.s == servctx->proxy_client_sock) {
+            /* Replay data to proxy socket. */
+            status = proxy_replay(servctx, desc->rtnevents, pool);
+            if (APR_STATUS_IS_EOF(status)) {
+                apr_socket_close(servctx->proxy_client_sock);
+                servctx->proxy_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;
+}
+
+
+/* Setup the context needed to start a TCP server on adress.
+   message_list is a list of expected requests.
+   action_list is the list of responses to be returned in order.
+ */
+void setup_test_server(serv_ctx_t **servctx_p,
+                       apr_sockaddr_t *address,
+                       test_server_message_t *message_list,
+                       apr_size_t message_count,
+                       test_server_action_t *action_list,
+                       apr_size_t action_count,
+                       apr_int32_t options,
+                       apr_pool_t *pool)
+{
+    serv_ctx_t *servctx;
+
+    servctx = apr_pcalloc(pool, sizeof(*servctx));
+    apr_pool_cleanup_register(pool, servctx,
+                              cleanup_server,
+                              apr_pool_cleanup_null);
+    *servctx_p = servctx;
+
+    servctx->serv_addr = address;
+    servctx->options = options;
+    servctx->pool = pool;
+    servctx->allocator = serf_bucket_allocator_create(pool, NULL, NULL);
+    servctx->message_list = message_list;
+    servctx->message_count = message_count;
+    servctx->action_list = action_list;
+    servctx->action_count = action_count;
+
+    /* Start replay from first action. */
+    servctx->cur_action = 0;
+    servctx->action_buf_pos = 0;
+    servctx->outstanding_responses = 0;
+
+    servctx->read = socket_read;
+    servctx->send = socket_write;
+
+    *servctx_p = servctx;
+}
+
+apr_status_t start_test_server(serv_ctx_t *servctx)
+{
+    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, servctx->serv_addr->family,
+                               SOCK_STREAM, 0,
+                               servctx->pool);
+#else
+    status = apr_socket_create(&serv_sock, servctx->serv_addr->family,
+                               SOCK_STREAM,
+                               servctx->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, servctx->serv_addr);
+    if (status != APR_SUCCESS)
+        return status;
+
+    /* listen for clients */
+    status = apr_socket_listen(serv_sock, SOMAXCONN);
+    if (status != APR_SUCCESS)
+        return status;
+
+    servctx->serv_sock = serv_sock;
+    servctx->client_sock = NULL;
+
+    return APR_SUCCESS;
+}

Deleted: vendor/serf/1.3.9/test/server/test_server.h
===================================================================
--- vendor/serf/dist/test/server/test_server.h	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/test/server/test_server.h	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,152 +0,0 @@
-/* Copyright 2011 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_SERVER_H
-#define TEST_SERVER_H
-
-/* Test logging facilities, set flag to 1 to enable console logging for
-   the test suite. */
-#define TEST_VERBOSE 0
-
-#define TEST_SERVER_DUMP 1
-
-/* Default port for our test server. */
-#define SERV_PORT 12345
-#define SERV_PORT_STR "12345"
-
-#define PROXY_PORT 23456
-
-typedef struct serv_ctx_t serv_ctx_t;
-
-typedef apr_status_t (*send_func_t)(serv_ctx_t *serv_ctx, const char *data,
-                                    apr_size_t *len);
-typedef apr_status_t (*receive_func_t)(serv_ctx_t *serv_ctx, char *data,
-                                       apr_size_t *len);
-
-typedef apr_status_t (*handshake_func_t)(serv_ctx_t *serv_ctx);
-typedef apr_status_t (*reset_conn_func_t)(serv_ctx_t *serv_ctx);
-
-typedef struct
-{
-    enum {
-        SERVER_RECV,
-        SERVER_SEND,
-        SERVER_RESPOND,
-        SERVER_IGNORE_AND_KILL_CONNECTION,
-        SERVER_KILL_CONNECTION,
-        PROXY_FORWARD,
-    } kind;
-
-    const char *text;
-} test_server_action_t;
-
-typedef struct
-{
-    const char *text;
-} test_server_message_t;
-
-struct serv_ctx_t {
-    /* Pool for resource allocation. */
-    apr_pool_t *pool;
-    serf_bucket_alloc_t *allocator;
-
-    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;
-
-    /* Array of messages the server will receive from the client. */
-    test_server_message_t *message_list;
-    /* Size of message_list array. */
-    apr_size_t message_count;
-    /* Index of current message. */
-    apr_size_t cur_message;
-
-    /* Number of messages received that the server didn't respond to yet. */
-    apr_size_t outstanding_responses;
-
-    /* Position in message buffer (incoming messages being read). */
-    apr_size_t message_buf_pos;
-
-    /* Position in action buffer. (outgoing messages being sent). */
-    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;
-
-    /* Client socket to a server, in case this server acts as a proxy. */
-    apr_socket_t *proxy_client_sock;
-
-    serf_bucket_t *clientstream;
-    serf_bucket_t *servstream;
-
-    send_func_t send;
-    receive_func_t read;
-
-    /* SSL related variables */
-    handshake_func_t handshake;
-    reset_conn_func_t reset;
-
-    void *ssl_ctx;
-    const char *client_cn;
-    apr_status_t bio_read_status;
-};
-
-void setup_test_server(serv_ctx_t **servctx_p,
-                       apr_sockaddr_t *address,
-                       test_server_message_t *message_list,
-                       apr_size_t message_count,
-                       test_server_action_t *action_list,
-                       apr_size_t action_count,
-                       apr_int32_t options,
-                       apr_pool_t *pool);
-
-void setup_https_test_server(serv_ctx_t **servctx_p,
-                             apr_sockaddr_t *address,
-                             test_server_message_t *message_list,
-                             apr_size_t message_count,
-                             test_server_action_t *action_list,
-                             apr_size_t action_count,
-                             apr_int32_t options,
-                             const char *keyfile,
-                             const char **certfiles,
-                             const char *client_cn,
-                             apr_pool_t *pool);
-
-apr_status_t start_test_server(serv_ctx_t *serv_ctx);
-
-apr_status_t run_test_server(serv_ctx_t *servctx,
-                             apr_short_interval_time_t duration,
-                             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_SERVER_H */

Copied: vendor/serf/1.3.9/test/server/test_server.h (from rev 9259, vendor/serf/dist/test/server/test_server.h)
===================================================================
--- vendor/serf/1.3.9/test/server/test_server.h	                        (rev 0)
+++ vendor/serf/1.3.9/test/server/test_server.h	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,157 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_SERVER_H
+#define TEST_SERVER_H
+
+/* Test logging facilities, set flag to 1 to enable console logging for
+   the test suite. */
+#define TEST_VERBOSE 0
+
+#define TEST_SERVER_DUMP 1
+
+/* Default port for our test server. */
+#define SERV_PORT 12345
+#define SERV_PORT_STR "12345"
+
+#define PROXY_PORT 23456
+
+typedef struct serv_ctx_t serv_ctx_t;
+
+typedef apr_status_t (*send_func_t)(serv_ctx_t *serv_ctx, const char *data,
+                                    apr_size_t *len);
+typedef apr_status_t (*receive_func_t)(serv_ctx_t *serv_ctx, char *data,
+                                       apr_size_t *len);
+
+typedef apr_status_t (*handshake_func_t)(serv_ctx_t *serv_ctx);
+typedef apr_status_t (*reset_conn_func_t)(serv_ctx_t *serv_ctx);
+
+typedef struct
+{
+    enum {
+        SERVER_RECV,
+        SERVER_SEND,
+        SERVER_RESPOND,
+        SERVER_IGNORE_AND_KILL_CONNECTION,
+        SERVER_KILL_CONNECTION,
+        PROXY_FORWARD,
+    } kind;
+
+    const char *text;
+} test_server_action_t;
+
+typedef struct
+{
+    const char *text;
+} test_server_message_t;
+
+struct serv_ctx_t {
+    /* Pool for resource allocation. */
+    apr_pool_t *pool;
+    serf_bucket_alloc_t *allocator;
+
+    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;
+
+    /* Array of messages the server will receive from the client. */
+    test_server_message_t *message_list;
+    /* Size of message_list array. */
+    apr_size_t message_count;
+    /* Index of current message. */
+    apr_size_t cur_message;
+
+    /* Number of messages received that the server didn't respond to yet. */
+    apr_size_t outstanding_responses;
+
+    /* Position in message buffer (incoming messages being read). */
+    apr_size_t message_buf_pos;
+
+    /* Position in action buffer. (outgoing messages being sent). */
+    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;
+
+    /* Client socket to a server, in case this server acts as a proxy. */
+    apr_socket_t *proxy_client_sock;
+
+    serf_bucket_t *clientstream;
+    serf_bucket_t *servstream;
+
+    send_func_t send;
+    receive_func_t read;
+
+    /* SSL related variables */
+    handshake_func_t handshake;
+    reset_conn_func_t reset;
+
+    void *ssl_ctx;
+    const char *client_cn;
+    apr_status_t bio_read_status;
+};
+
+void setup_test_server(serv_ctx_t **servctx_p,
+                       apr_sockaddr_t *address,
+                       test_server_message_t *message_list,
+                       apr_size_t message_count,
+                       test_server_action_t *action_list,
+                       apr_size_t action_count,
+                       apr_int32_t options,
+                       apr_pool_t *pool);
+
+void setup_https_test_server(serv_ctx_t **servctx_p,
+                             apr_sockaddr_t *address,
+                             test_server_message_t *message_list,
+                             apr_size_t message_count,
+                             test_server_action_t *action_list,
+                             apr_size_t action_count,
+                             apr_int32_t options,
+                             const char *keyfile,
+                             const char **certfiles,
+                             const char *client_cn,
+                             apr_pool_t *pool);
+
+apr_status_t start_test_server(serv_ctx_t *serv_ctx);
+
+apr_status_t run_test_server(serv_ctx_t *servctx,
+                             apr_short_interval_time_t duration,
+                             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_SERVER_H */

Deleted: vendor/serf/1.3.9/test/server/test_sslserver.c
===================================================================
--- vendor/serf/dist/test/server/test_sslserver.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/test/server/test_sslserver.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,424 +0,0 @@
-/* Copyright 2013 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 "serf.h"
-#include "test_server.h"
-
-#include "serf_private.h"
-
-#include <openssl/bio.h>
-#include <openssl/ssl.h>
-#include <openssl/err.h>
-
-static int init_done = 0;
-
-typedef struct ssl_context_t {
-    int handshake_done;
-
-    SSL_CTX* ctx;
-    SSL* ssl;
-    BIO *bio;
-
-} ssl_context_t;
-
-static int pem_passwd_cb(char *buf, int size, int rwflag, void *userdata)
-{
-    strncpy(buf, "serftest", size);
-    buf[size - 1] = '\0';
-    return strlen(buf);
-}
-
-static int bio_apr_socket_create(BIO *bio)
-{
-    bio->shutdown = 1;
-    bio->init = 1;
-    bio->num = -1;
-    bio->ptr = NULL;
-
-    return 1;
-}
-
-static int bio_apr_socket_destroy(BIO *bio)
-{
-    /* Did we already free this? */
-    if (bio == NULL) {
-        return 0;
-    }
-
-    return 1;
-}
-
-static long bio_apr_socket_ctrl(BIO *bio, int cmd, long num, void *ptr)
-{
-    long ret = 1;
-
-    switch (cmd) {
-        default:
-            /* abort(); */
-            break;
-        case BIO_CTRL_FLUSH:
-            /* At this point we can't force a flush. */
-            break;
-        case BIO_CTRL_PUSH:
-        case BIO_CTRL_POP:
-            ret = 0;
-            break;
-    }
-    return ret;
-}
-
-/* Returns the amount read. */
-static int bio_apr_socket_read(BIO *bio, char *in, int inlen)
-{
-    apr_size_t len = inlen;
-    serv_ctx_t *serv_ctx = bio->ptr;
-    apr_status_t status;
-
-    BIO_clear_retry_flags(bio);
-
-    status = apr_socket_recv(serv_ctx->client_sock, in, &len);
-    serv_ctx->bio_read_status = status;
-    serf__log_skt(TEST_VERBOSE, __FILE__, serv_ctx->client_sock,
-                  "Read %d bytes from socket with status %d.\n", len, status);
-
-    if (status == APR_EAGAIN) {
-        BIO_set_retry_read(bio);
-        if (len == 0)
-            return -1;
-    }
-
-    if (SERF_BUCKET_READ_ERROR(status))
-        return -1;
-
-    return len;
-}
-
-/* Returns the amount written. */
-static int bio_apr_socket_write(BIO *bio, const char *in, int inlen)
-{
-    apr_size_t len = inlen;
-    serv_ctx_t *serv_ctx = bio->ptr;
-
-    apr_status_t status = apr_socket_send(serv_ctx->client_sock, in, &len);
-
-    serf__log_skt(TEST_VERBOSE, __FILE__, serv_ctx->client_sock,
-                  "Wrote %d of %d bytes to socket with status %d.\n",
-                  len, inlen, status);
-
-    if (SERF_BUCKET_READ_ERROR(status))
-        return -1;
-
-    return len;
-}
-
-
-static BIO_METHOD bio_apr_socket_method = {
-    BIO_TYPE_SOCKET,
-    "APR sockets",
-    bio_apr_socket_write,
-    bio_apr_socket_read,
-    NULL,                        /* Is this called? */
-    NULL,                        /* Is this called? */
-    bio_apr_socket_ctrl,
-    bio_apr_socket_create,
-    bio_apr_socket_destroy,
-#ifdef OPENSSL_VERSION_NUMBER
-    NULL /* sslc does not have the callback_ctrl field */
-#endif
-};
-
-static int validate_client_certificate(int preverify_ok, X509_STORE_CTX *ctx)
-{
-    serf__log(TEST_VERBOSE, __FILE__, "validate_client_certificate called, "
-              "preverify code: %d.\n", preverify_ok);
-
-    return preverify_ok;
-}
-
-static apr_status_t init_ssl(serv_ctx_t *serv_ctx)
-{
-    ssl_context_t *ssl_ctx = serv_ctx->ssl_ctx;
-
-    ssl_ctx->ssl = SSL_new(ssl_ctx->ctx);
-    SSL_set_cipher_list(ssl_ctx->ssl, "ALL");
-    SSL_set_bio(ssl_ctx->ssl, ssl_ctx->bio, ssl_ctx->bio);
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t
-init_ssl_context(serv_ctx_t *serv_ctx,
-                 const char *keyfile,
-                 const char **certfiles,
-                 const char *client_cn)
-{
-    ssl_context_t *ssl_ctx = apr_pcalloc(serv_ctx->pool, sizeof(*ssl_ctx));
-    serv_ctx->ssl_ctx = ssl_ctx;
-    serv_ctx->client_cn = client_cn;
-    serv_ctx->bio_read_status = APR_SUCCESS;
-
-    /* Init OpenSSL globally */
-    if (!init_done)
-    {
-        CRYPTO_malloc_init();
-        ERR_load_crypto_strings();
-        SSL_load_error_strings();
-        SSL_library_init();
-        OpenSSL_add_all_algorithms();
-        init_done = 1;
-    }
-
-    /* Init this connection */
-    if (!ssl_ctx->ctx) {
-        X509_STORE *store;
-        const char *certfile;
-        int i;
-        int rv;
-
-        ssl_ctx->ctx = SSL_CTX_new(SSLv23_server_method());
-        SSL_CTX_set_default_passwd_cb(ssl_ctx->ctx, pem_passwd_cb);
-        rv = SSL_CTX_use_PrivateKey_file(ssl_ctx->ctx, keyfile,
-                                         SSL_FILETYPE_PEM);
-        if (rv != 1) {
-            fprintf(stderr, "Cannot load private key from file '%s'\n", keyfile);
-            exit(1);
-        }
-
-        /* Set server certificate, add ca certificates if provided. */
-        certfile = certfiles[0];
-        rv = SSL_CTX_use_certificate_file(ssl_ctx->ctx, certfile, SSL_FILETYPE_PEM);
-        if (rv != 1) {
-            fprintf(stderr, "Cannot load certficate from file '%s'\n", keyfile);
-            exit(1);
-        }
-
-        i = 1;
-        certfile = certfiles[i++];
-        store = SSL_CTX_get_cert_store(ssl_ctx->ctx);
-
-        while(certfile) {
-            FILE *fp = fopen(certfile, "r");
-            if (fp) {
-                X509 *ssl_cert = PEM_read_X509(fp, NULL, NULL, NULL);
-                fclose(fp);
-
-                SSL_CTX_add_extra_chain_cert(ssl_ctx->ctx, ssl_cert);
-
-                X509_STORE_add_cert(store, ssl_cert);
-            }
-            certfile = certfiles[i++];
-        }
-
-        /* This makes the server send a client certificate request during
-           handshake. The client certificate is optional (most tests don't
-           send one) by default, but mandatory if client_cn was specified. */
-        SSL_CTX_set_verify(ssl_ctx->ctx, SSL_VERIFY_PEER,
-                           validate_client_certificate);
-
-        SSL_CTX_set_mode(ssl_ctx->ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
-
-        ssl_ctx->bio = BIO_new(&bio_apr_socket_method);
-        ssl_ctx->bio->ptr = serv_ctx;
-        init_ssl(serv_ctx);
-    }
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t ssl_reset(serv_ctx_t *serv_ctx)
-{
-    ssl_context_t *ssl_ctx = serv_ctx->ssl_ctx;
-
-    serf__log(TEST_VERBOSE, __FILE__, "Reset ssl context.\n");
-
-    ssl_ctx->handshake_done = 0;
-    if (ssl_ctx)
-        SSL_clear(ssl_ctx->ssl);
-    init_ssl(serv_ctx);
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t ssl_handshake(serv_ctx_t *serv_ctx)
-{
-    ssl_context_t *ssl_ctx = serv_ctx->ssl_ctx;
-    int result;
-
-    if (ssl_ctx->handshake_done)
-        return APR_SUCCESS;
-
-    /* SSL handshake */
-    result = SSL_accept(ssl_ctx->ssl);
-    if (result == 1) {
-        X509 *peer;
-
-        serf__log(TEST_VERBOSE, __FILE__, "Handshake successful.\n");
-
-        /* Check client certificate */
-        peer = SSL_get_peer_certificate(ssl_ctx->ssl);
-        if (peer)
-        {
-            serf__log(TEST_VERBOSE, __FILE__, "Peer cert received.\n");
-            if (SSL_get_verify_result(ssl_ctx->ssl) == X509_V_OK)
-            {
-                /* The client sent a certificate which verified OK */
-                char buf[1024];
-                int ret;
-                X509_NAME *subject = X509_get_subject_name(peer);
-
-                ret = X509_NAME_get_text_by_NID(subject,
-                                                NID_commonName,
-                                                buf, 1024);
-                if (ret != -1 && strcmp(serv_ctx->client_cn, buf) != 0) {
-                    serf__log(TEST_VERBOSE, __FILE__, "Client cert common name "
-                              "\"%s\" doesn't match expected \"%s\".\n", buf,
-                              serv_ctx->client_cn);
-                    return SERF_ERROR_ISSUE_IN_TESTSUITE;
-
-                }
-            }
-        } else {
-            if (serv_ctx->client_cn) {
-                serf__log(TEST_VERBOSE, __FILE__, "Client cert expected but not"
-                          " received.\n");
-                return SERF_ERROR_ISSUE_IN_TESTSUITE;
-            }
-        }
-
-        ssl_ctx->handshake_done = 1;
-    }
-    else {
-        int ssl_err;
-
-        ssl_err = SSL_get_error(ssl_ctx->ssl, result);
-        switch (ssl_err) {
-            case SSL_ERROR_WANT_READ:
-            case SSL_ERROR_WANT_WRITE:
-                return APR_EAGAIN;
-            case SSL_ERROR_SYSCALL:
-                return serv_ctx->bio_read_status; /* Usually APR_EAGAIN */
-            default:
-                serf__log(TEST_VERBOSE, __FILE__, "SSL Error %d: ", ssl_err);
-                ERR_print_errors_fp(stderr);
-                serf__log_nopref(TEST_VERBOSE, "\n");
-                return SERF_ERROR_ISSUE_IN_TESTSUITE;
-        }
-    }
-
-    return APR_EAGAIN;
-}
-
-static apr_status_t
-ssl_socket_write(serv_ctx_t *serv_ctx, const char *data,
-                 apr_size_t *len)
-{
-    ssl_context_t *ssl_ctx = serv_ctx->ssl_ctx;
-
-    int result = SSL_write(ssl_ctx->ssl, data, *len);
-    if (result > 0) {
-        *len = result;
-        return APR_SUCCESS;
-    }
-
-    if (result == 0)
-        return APR_EAGAIN;
-
-    serf__log(TEST_VERBOSE, __FILE__, "ssl_socket_write: ssl error?\n");
-
-    return SERF_ERROR_ISSUE_IN_TESTSUITE;
-}
-
-static apr_status_t
-ssl_socket_read(serv_ctx_t *serv_ctx, char *data,
-                apr_size_t *len)
-{
-    ssl_context_t *ssl_ctx = serv_ctx->ssl_ctx;
-
-    int result = SSL_read(ssl_ctx->ssl, data, *len);
-    if (result > 0) {
-        *len = result;
-        return APR_SUCCESS;
-    } else {
-        int ssl_err;
-
-        ssl_err = SSL_get_error(ssl_ctx->ssl, result);
-        switch (ssl_err) {
-            case SSL_ERROR_SYSCALL:
-                /* error in bio_bucket_read, probably APR_EAGAIN or APR_EOF */
-                *len = 0;
-                return serv_ctx->bio_read_status;
-            case SSL_ERROR_WANT_READ:
-                *len = 0;
-                return APR_EAGAIN;
-            case SSL_ERROR_SSL:
-            default:
-                *len = 0;
-                serf__log(TEST_VERBOSE, __FILE__,
-                          "ssl_socket_read SSL Error %d: ", ssl_err);
-                ERR_print_errors_fp(stderr);
-                serf__log_nopref(TEST_VERBOSE, "\n");
-                return SERF_ERROR_ISSUE_IN_TESTSUITE;
-        }
-    }
-
-    /* not reachable */
-    return SERF_ERROR_ISSUE_IN_TESTSUITE;
-}
-
-static apr_status_t cleanup_https_server(void *baton)
-{
-    serv_ctx_t *servctx = baton;
-    ssl_context_t *ssl_ctx = servctx->ssl_ctx;
-
-    if (ssl_ctx) {
-        if (ssl_ctx->ssl)
-          SSL_clear(ssl_ctx->ssl);
-        SSL_CTX_free(ssl_ctx->ctx);
-    }
-
-    return APR_SUCCESS;
-}
-
-void setup_https_test_server(serv_ctx_t **servctx_p,
-                             apr_sockaddr_t *address,
-                             test_server_message_t *message_list,
-                             apr_size_t message_count,
-                             test_server_action_t *action_list,
-                             apr_size_t action_count,
-                             apr_int32_t options,
-                             const char *keyfile,
-                             const char **certfiles,
-                             const char *client_cn,
-                             apr_pool_t *pool)
-{
-    serv_ctx_t *servctx;
-
-    setup_test_server(servctx_p, address, message_list,
-                      message_count, action_list, action_count,
-                      options, pool);
-    servctx = *servctx_p;
-    apr_pool_cleanup_register(pool, servctx,
-                              cleanup_https_server,
-                              apr_pool_cleanup_null);
-
-    servctx->handshake = ssl_handshake;
-    servctx->reset = ssl_reset;
-
-    /* Override with SSL encrypt/decrypt functions */
-    servctx->read = ssl_socket_read;
-    servctx->send = ssl_socket_write;
-
-    init_ssl_context(servctx, keyfile, certfiles, client_cn);
-}

Copied: vendor/serf/1.3.9/test/server/test_sslserver.c (from rev 9259, vendor/serf/dist/test/server/test_sslserver.c)
===================================================================
--- vendor/serf/1.3.9/test/server/test_sslserver.c	                        (rev 0)
+++ vendor/serf/1.3.9/test/server/test_sslserver.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,489 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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 "serf.h"
+#include "test_server.h"
+
+#include "serf_private.h"
+
+#include <openssl/bio.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L
+#define USE_OPENSSL_1_1_API
+#endif
+
+static int init_done = 0;
+
+typedef struct ssl_context_t {
+    int handshake_done;
+
+    SSL_CTX* ctx;
+    SSL* ssl;
+    BIO *bio;
+    BIO_METHOD *biom;
+
+} ssl_context_t;
+
+static int pem_passwd_cb(char *buf, int size, int rwflag, void *userdata)
+{
+    strncpy(buf, "serftest", size);
+    buf[size - 1] = '\0';
+    return strlen(buf);
+}
+
+static void bio_set_data(BIO *bio, void *data)
+{
+#ifdef USE_OPENSSL_1_1_API
+    BIO_set_data(bio, data);
+#else
+    bio->ptr = data;
+#endif
+}
+
+static void *bio_get_data(BIO *bio)
+{
+#ifdef USE_OPENSSL_1_1_API
+    return BIO_get_data(bio);
+#else
+    return bio->ptr;
+#endif
+}
+
+static int bio_apr_socket_create(BIO *bio)
+{
+#ifdef USE_OPENSSL_1_1_API
+    BIO_set_shutdown(bio, 1);
+    BIO_set_init(bio, 1);
+    BIO_set_data(bio, NULL);
+#else
+    bio->shutdown = 1;
+    bio->init = 1;
+    bio->num = -1;
+    bio->ptr = NULL;
+#endif
+
+    return 1;
+}
+
+static int bio_apr_socket_destroy(BIO *bio)
+{
+    /* Did we already free this? */
+    if (bio == NULL) {
+        return 0;
+    }
+
+    return 1;
+}
+
+static long bio_apr_socket_ctrl(BIO *bio, int cmd, long num, void *ptr)
+{
+    long ret = 1;
+
+    switch (cmd) {
+        default:
+            /* abort(); */
+            break;
+        case BIO_CTRL_FLUSH:
+            /* At this point we can't force a flush. */
+            break;
+        case BIO_CTRL_PUSH:
+        case BIO_CTRL_POP:
+            ret = 0;
+            break;
+    }
+    return ret;
+}
+
+/* Returns the amount read. */
+static int bio_apr_socket_read(BIO *bio, char *in, int inlen)
+{
+    apr_size_t len = inlen;
+    serv_ctx_t *serv_ctx = bio_get_data(bio);
+    apr_status_t status;
+
+    BIO_clear_retry_flags(bio);
+
+    status = apr_socket_recv(serv_ctx->client_sock, in, &len);
+    serv_ctx->bio_read_status = status;
+    serf__log_skt(TEST_VERBOSE, __FILE__, serv_ctx->client_sock,
+                  "Read %d bytes from socket with status %d.\n", len, status);
+
+    if (status == APR_EAGAIN) {
+        BIO_set_retry_read(bio);
+        if (len == 0)
+            return -1;
+    }
+
+    if (SERF_BUCKET_READ_ERROR(status))
+        return -1;
+
+    return len;
+}
+
+/* Returns the amount written. */
+static int bio_apr_socket_write(BIO *bio, const char *in, int inlen)
+{
+    apr_size_t len = inlen;
+    serv_ctx_t *serv_ctx = bio_get_data(bio);
+
+    apr_status_t status = apr_socket_send(serv_ctx->client_sock, in, &len);
+
+    serf__log_skt(TEST_VERBOSE, __FILE__, serv_ctx->client_sock,
+                  "Wrote %d of %d bytes to socket with status %d.\n",
+                  len, inlen, status);
+
+    if (SERF_BUCKET_READ_ERROR(status))
+        return -1;
+
+    return len;
+}
+
+
+#ifndef USE_OPENSSL_1_1_API
+static BIO_METHOD bio_apr_socket_method = {
+    BIO_TYPE_SOCKET,
+    "APR sockets",
+    bio_apr_socket_write,
+    bio_apr_socket_read,
+    NULL,                        /* Is this called? */
+    NULL,                        /* Is this called? */
+    bio_apr_socket_ctrl,
+    bio_apr_socket_create,
+    bio_apr_socket_destroy,
+#ifdef OPENSSL_VERSION_NUMBER
+    NULL /* sslc does not have the callback_ctrl field */
+#endif
+};
+#endif
+
+static BIO_METHOD *bio_meth_apr_socket_new(void)
+{
+    BIO_METHOD *biom = NULL;
+
+#ifdef USE_OPENSSL_1_1_API
+    biom = BIO_meth_new(BIO_TYPE_SOCKET, "APR sockets");
+    if (biom) {
+        BIO_meth_set_write(biom, bio_apr_socket_write);
+        BIO_meth_set_read(biom, bio_apr_socket_read);
+        BIO_meth_set_ctrl(biom, bio_apr_socket_ctrl);
+        BIO_meth_set_create(biom, bio_apr_socket_create);
+        BIO_meth_set_destroy(biom, bio_apr_socket_destroy);
+    }
+#else
+    biom = &bio_apr_socket_method;
+#endif
+
+    return biom;
+}
+
+static int validate_client_certificate(int preverify_ok, X509_STORE_CTX *ctx)
+{
+    serf__log(TEST_VERBOSE, __FILE__, "validate_client_certificate called, "
+              "preverify code: %d.\n", preverify_ok);
+
+    return preverify_ok;
+}
+
+static apr_status_t init_ssl(serv_ctx_t *serv_ctx)
+{
+    ssl_context_t *ssl_ctx = serv_ctx->ssl_ctx;
+
+    ssl_ctx->ssl = SSL_new(ssl_ctx->ctx);
+    SSL_set_cipher_list(ssl_ctx->ssl, "ALL");
+    SSL_set_bio(ssl_ctx->ssl, ssl_ctx->bio, ssl_ctx->bio);
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t
+init_ssl_context(serv_ctx_t *serv_ctx,
+                 const char *keyfile,
+                 const char **certfiles,
+                 const char *client_cn)
+{
+    ssl_context_t *ssl_ctx = apr_pcalloc(serv_ctx->pool, sizeof(*ssl_ctx));
+    serv_ctx->ssl_ctx = ssl_ctx;
+    serv_ctx->client_cn = client_cn;
+    serv_ctx->bio_read_status = APR_SUCCESS;
+
+    /* Init OpenSSL globally */
+    if (!init_done)
+    {
+#ifdef USE_OPENSSL_1_1_API
+        OPENSSL_malloc_init();
+#else
+        CRYPTO_malloc_init();
+#endif
+        ERR_load_crypto_strings();
+        SSL_load_error_strings();
+        SSL_library_init();
+        OpenSSL_add_all_algorithms();
+        init_done = 1;
+    }
+
+    /* Init this connection */
+    if (!ssl_ctx->ctx) {
+        X509_STORE *store;
+        const char *certfile;
+        int i;
+        int rv;
+
+        ssl_ctx->ctx = SSL_CTX_new(SSLv23_server_method());
+        SSL_CTX_set_default_passwd_cb(ssl_ctx->ctx, pem_passwd_cb);
+        rv = SSL_CTX_use_PrivateKey_file(ssl_ctx->ctx, keyfile,
+                                         SSL_FILETYPE_PEM);
+        if (rv != 1) {
+            fprintf(stderr, "Cannot load private key from file '%s'\n", keyfile);
+            exit(1);
+        }
+
+        /* Set server certificate, add ca certificates if provided. */
+        certfile = certfiles[0];
+        rv = SSL_CTX_use_certificate_file(ssl_ctx->ctx, certfile, SSL_FILETYPE_PEM);
+        if (rv != 1) {
+            fprintf(stderr, "Cannot load certficate from file '%s'\n", certfile);
+            exit(1);
+        }
+
+        i = 1;
+        certfile = certfiles[i++];
+        store = SSL_CTX_get_cert_store(ssl_ctx->ctx);
+
+        while(certfile) {
+            FILE *fp = fopen(certfile, "r");
+            if (fp) {
+                X509 *ssl_cert = PEM_read_X509(fp, NULL, NULL, NULL);
+                fclose(fp);
+
+                SSL_CTX_add_extra_chain_cert(ssl_ctx->ctx, ssl_cert);
+
+                X509_STORE_add_cert(store, ssl_cert);
+            }
+            certfile = certfiles[i++];
+        }
+
+        /* This makes the server send a client certificate request during
+           handshake. The client certificate is optional (most tests don't
+           send one) by default, but mandatory if client_cn was specified. */
+        SSL_CTX_set_verify(ssl_ctx->ctx, SSL_VERIFY_PEER,
+                           validate_client_certificate);
+
+        SSL_CTX_set_mode(ssl_ctx->ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
+
+        ssl_ctx->biom = bio_meth_apr_socket_new();
+        ssl_ctx->bio = BIO_new(ssl_ctx->biom);
+        bio_set_data(ssl_ctx->bio, serv_ctx);
+        init_ssl(serv_ctx);
+    }
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t ssl_reset(serv_ctx_t *serv_ctx)
+{
+    ssl_context_t *ssl_ctx = serv_ctx->ssl_ctx;
+
+    serf__log(TEST_VERBOSE, __FILE__, "Reset ssl context.\n");
+
+    ssl_ctx->handshake_done = 0;
+    if (ssl_ctx)
+        SSL_clear(ssl_ctx->ssl);
+    init_ssl(serv_ctx);
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t ssl_handshake(serv_ctx_t *serv_ctx)
+{
+    ssl_context_t *ssl_ctx = serv_ctx->ssl_ctx;
+    int result;
+
+    if (ssl_ctx->handshake_done)
+        return APR_SUCCESS;
+
+    /* SSL handshake */
+    result = SSL_accept(ssl_ctx->ssl);
+    if (result == 1) {
+        X509 *peer;
+
+        serf__log(TEST_VERBOSE, __FILE__, "Handshake successful.\n");
+
+        /* Check client certificate */
+        peer = SSL_get_peer_certificate(ssl_ctx->ssl);
+        if (peer)
+        {
+            serf__log(TEST_VERBOSE, __FILE__, "Peer cert received.\n");
+            if (SSL_get_verify_result(ssl_ctx->ssl) == X509_V_OK)
+            {
+                /* The client sent a certificate which verified OK */
+                char buf[1024];
+                int ret;
+                X509_NAME *subject = X509_get_subject_name(peer);
+
+                ret = X509_NAME_get_text_by_NID(subject,
+                                                NID_commonName,
+                                                buf, 1024);
+                if (ret != -1 && strcmp(serv_ctx->client_cn, buf) != 0) {
+                    serf__log(TEST_VERBOSE, __FILE__, "Client cert common name "
+                              "\"%s\" doesn't match expected \"%s\".\n", buf,
+                              serv_ctx->client_cn);
+                    return SERF_ERROR_ISSUE_IN_TESTSUITE;
+
+                }
+            }
+        } else {
+            if (serv_ctx->client_cn) {
+                serf__log(TEST_VERBOSE, __FILE__, "Client cert expected but not"
+                          " received.\n");
+                return SERF_ERROR_ISSUE_IN_TESTSUITE;
+            }
+        }
+
+        ssl_ctx->handshake_done = 1;
+    }
+    else {
+        int ssl_err;
+
+        ssl_err = SSL_get_error(ssl_ctx->ssl, result);
+        switch (ssl_err) {
+            case SSL_ERROR_WANT_READ:
+            case SSL_ERROR_WANT_WRITE:
+                return APR_EAGAIN;
+            case SSL_ERROR_SYSCALL:
+                return serv_ctx->bio_read_status; /* Usually APR_EAGAIN */
+            default:
+                serf__log(TEST_VERBOSE, __FILE__, "SSL Error %d: ", ssl_err);
+                ERR_print_errors_fp(stderr);
+                serf__log_nopref(TEST_VERBOSE, "\n");
+                return SERF_ERROR_ISSUE_IN_TESTSUITE;
+        }
+    }
+
+    return APR_EAGAIN;
+}
+
+static apr_status_t
+ssl_socket_write(serv_ctx_t *serv_ctx, const char *data,
+                 apr_size_t *len)
+{
+    ssl_context_t *ssl_ctx = serv_ctx->ssl_ctx;
+
+    int result = SSL_write(ssl_ctx->ssl, data, *len);
+    if (result > 0) {
+        *len = result;
+        return APR_SUCCESS;
+    }
+
+    if (result == 0)
+        return APR_EAGAIN;
+
+    serf__log(TEST_VERBOSE, __FILE__, "ssl_socket_write: ssl error?\n");
+
+    return SERF_ERROR_ISSUE_IN_TESTSUITE;
+}
+
+static apr_status_t
+ssl_socket_read(serv_ctx_t *serv_ctx, char *data,
+                apr_size_t *len)
+{
+    ssl_context_t *ssl_ctx = serv_ctx->ssl_ctx;
+
+    int result = SSL_read(ssl_ctx->ssl, data, *len);
+    if (result > 0) {
+        *len = result;
+        return APR_SUCCESS;
+    } else {
+        int ssl_err;
+
+        ssl_err = SSL_get_error(ssl_ctx->ssl, result);
+        switch (ssl_err) {
+            case SSL_ERROR_SYSCALL:
+                /* error in bio_bucket_read, probably APR_EAGAIN or APR_EOF */
+                *len = 0;
+                return serv_ctx->bio_read_status;
+            case SSL_ERROR_WANT_READ:
+                *len = 0;
+                return APR_EAGAIN;
+            case SSL_ERROR_SSL:
+            default:
+                *len = 0;
+                serf__log(TEST_VERBOSE, __FILE__,
+                          "ssl_socket_read SSL Error %d: ", ssl_err);
+                ERR_print_errors_fp(stderr);
+                serf__log_nopref(TEST_VERBOSE, "\n");
+                return SERF_ERROR_ISSUE_IN_TESTSUITE;
+        }
+    }
+
+    /* not reachable */
+    return SERF_ERROR_ISSUE_IN_TESTSUITE;
+}
+
+static apr_status_t cleanup_https_server(void *baton)
+{
+    serv_ctx_t *servctx = baton;
+    ssl_context_t *ssl_ctx = servctx->ssl_ctx;
+
+    if (ssl_ctx) {
+        if (ssl_ctx->ssl) {
+          SSL_clear(ssl_ctx->ssl);
+#ifdef USE_OPENSSL_1_1_API
+          BIO_meth_free(ssl_ctx->biom);
+#endif
+        }
+        SSL_CTX_free(ssl_ctx->ctx);
+    }
+
+    return APR_SUCCESS;
+}
+
+void setup_https_test_server(serv_ctx_t **servctx_p,
+                             apr_sockaddr_t *address,
+                             test_server_message_t *message_list,
+                             apr_size_t message_count,
+                             test_server_action_t *action_list,
+                             apr_size_t action_count,
+                             apr_int32_t options,
+                             const char *keyfile,
+                             const char **certfiles,
+                             const char *client_cn,
+                             apr_pool_t *pool)
+{
+    serv_ctx_t *servctx;
+
+    setup_test_server(servctx_p, address, message_list,
+                      message_count, action_list, action_count,
+                      options, pool);
+    servctx = *servctx_p;
+    apr_pool_cleanup_register(pool, servctx,
+                              cleanup_https_server,
+                              apr_pool_cleanup_null);
+
+    servctx->handshake = ssl_handshake;
+    servctx->reset = ssl_reset;
+
+    /* Override with SSL encrypt/decrypt functions */
+    servctx->read = ssl_socket_read;
+    servctx->send = ssl_socket_write;
+
+    init_ssl_context(servctx, keyfile, certfiles, client_cn);
+}

Deleted: vendor/serf/1.3.9/test/test_all.c
===================================================================
--- vendor/serf/dist/test/test_all.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/test/test_all.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,106 +0,0 @@
-/* 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>
-
-static const struct testlist {
-    const char *testname;
-    CuSuite *(*func)(void);
-} tests[] = {
-    {"context", test_context},
-    {"buckets", test_buckets},
-    {"ssl",     test_ssl},
-    {"auth",    test_auth},
-#if 0
-    /* internal test for the mock bucket. */
-    {"mock",    test_mock_bucket},
-#endif
-    {"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);
-
-    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);
-
-    return exit_code;
-}

Copied: vendor/serf/1.3.9/test/test_all.c (from rev 9259, vendor/serf/dist/test/test_all.c)
===================================================================
--- vendor/serf/1.3.9/test/test_all.c	                        (rev 0)
+++ vendor/serf/1.3.9/test/test_all.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,111 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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>
+
+static const struct testlist {
+    const char *testname;
+    CuSuite *(*func)(void);
+} tests[] = {
+    {"context", test_context},
+    {"buckets", test_buckets},
+    {"ssl",     test_ssl},
+    {"auth",    test_auth},
+#if 0
+    /* internal test for the mock bucket. */
+    {"mock",    test_mock_bucket},
+#endif
+    {"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);
+
+    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);
+
+    return exit_code;
+}

Deleted: vendor/serf/1.3.9/test/test_auth.c
===================================================================
--- vendor/serf/dist/test/test_auth.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/test/test_auth.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,629 +0,0 @@
-/* Copyright 2013 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_strings.h>
-
-#include "serf.h"
-#include "test_serf.h"
-
-static apr_status_t
-authn_callback_expect_not_called(char **username,
-                                 char **password,
-                                 serf_request_t *request, void *baton,
-                                 int code, const char *authn_type,
-                                 const char *realm,
-                                 apr_pool_t *pool)
-{
-    handler_baton_t *handler_ctx = baton;
-    test_baton_t *tb = handler_ctx->tb;
-
-    tb->result_flags |= TEST_RESULT_AUTHNCB_CALLED;
-
-    /* Should not have been called. */
-    return SERF_ERROR_ISSUE_IN_TESTSUITE;
-}
-
-/* Tests that authn fails if all authn schemes are disabled. */
-static void test_authentication_disabled(CuTest *tc)
-{
-    test_baton_t *tb;
-    handler_baton_t handler_ctx[2];
-
-    test_server_message_t message_list[] = {
-        {CHUNKED_REQUEST(1, "1")} };
-    test_server_action_t action_list[] = {
-        {SERVER_RESPOND, "HTTP/1.1 401 Unauthorized" CRLF
-            "Transfer-Encoding: chunked" CRLF
-            "WWW-Authenticate: Basic realm=""Test Suite""" CRLF
-            CRLF
-            "1" CRLF CRLF
-            "0" CRLF CRLF},
-    };
-    apr_status_t status;
-
-    apr_pool_t *test_pool = tc->testBaton;
-
-    /* Set up a test context with a server */
-    status = test_http_server_setup(&tb,
-                                    message_list, 1,
-                                    action_list, 1, 0, NULL,
-                                    test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    serf_config_authn_types(tb->context, SERF_AUTHN_NONE);
-    serf_config_credentials_callback(tb->context,
-                                     authn_callback_expect_not_called);
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
-
-    status = test_helper_run_requests_no_check(tc, tb, 1,
-                                               handler_ctx, test_pool);
-    CuAssertIntEquals(tc, SERF_ERROR_AUTHN_NOT_SUPPORTED, status);
-    CuAssertIntEquals(tc, 1, tb->sent_requests->nelts);
-    CuAssertIntEquals(tc, 1, tb->accepted_requests->nelts);
-    CuAssertIntEquals(tc, 0, tb->handled_requests->nelts);
-
-    CuAssertTrue(tc, !(tb->result_flags & TEST_RESULT_AUTHNCB_CALLED));
-}
-
-/* Tests that authn fails if encountered an unsupported scheme. */
-static void test_unsupported_authentication(CuTest *tc)
-{
-    test_baton_t *tb;
-    handler_baton_t handler_ctx[2];
-
-    test_server_message_t message_list[] = {
-        {CHUNKED_REQUEST(1, "1")} };
-    test_server_action_t action_list[] = {
-        {SERVER_RESPOND, "HTTP/1.1 401 Unauthorized" CRLF
-            "Transfer-Encoding: chunked" CRLF
-            "WWW-Authenticate: NotExistent realm=""Test Suite""" CRLF
-            CRLF
-            "1" CRLF CRLF
-            "0" CRLF CRLF},
-    };
-    apr_status_t status;
-
-    apr_pool_t *test_pool = tc->testBaton;
-
-    /* Set up a test context with a server */
-    status = test_http_server_setup(&tb,
-                                    message_list, 1,
-                                    action_list, 1, 0, NULL,
-                                    test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    serf_config_authn_types(tb->context, SERF_AUTHN_ALL);
-    serf_config_credentials_callback(tb->context,
-                                     authn_callback_expect_not_called);
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
-
-    status = test_helper_run_requests_no_check(tc, tb, 1,
-                                               handler_ctx, test_pool);
-    CuAssertIntEquals(tc, SERF_ERROR_AUTHN_NOT_SUPPORTED, status);
-    CuAssertIntEquals(tc, 1, tb->sent_requests->nelts);
-    CuAssertIntEquals(tc, 1, tb->accepted_requests->nelts);
-    CuAssertIntEquals(tc, 0, tb->handled_requests->nelts);
-
-    CuAssertTrue(tc, !(tb->result_flags & TEST_RESULT_AUTHNCB_CALLED));
-}
-
-static apr_status_t
-basic_authn_callback(char **username,
-                     char **password,
-                     serf_request_t *request, void *baton,
-                     int code, const char *authn_type,
-                     const char *realm,
-                     apr_pool_t *pool)
-{
-    handler_baton_t *handler_ctx = baton;
-    test_baton_t *tb = handler_ctx->tb;
-
-    tb->result_flags |= TEST_RESULT_AUTHNCB_CALLED;
-
-    if (code != 401)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    if (strcmp("Basic", authn_type) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    if (strcmp("<http://localhost:12345> Test Suite", realm) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-
-    *username = "serf";
-    *password = "serftest";
-
-    return APR_SUCCESS;
-}
-
-/* Test template, used for KeepAlive Off and KeepAlive On test */
-static void basic_authentication(CuTest *tc, const char *resp_hdrs)
-{
-    test_baton_t *tb;
-    handler_baton_t handler_ctx[2];
-    int num_requests_sent, num_requests_recvd;
-    test_server_message_t message_list[3];
-    test_server_action_t action_list[3];
-    apr_status_t status;
-
-    apr_pool_t *test_pool = tc->testBaton;
-    
-    /* Expected string relies on strict order of headers, which is not
-       guaranteed. c2VyZjpzZXJmdGVzdA== is base64 encoded serf:serftest . */
-    message_list[0].text = CHUNKED_REQUEST(1, "1");
-    message_list[1].text = apr_psprintf(test_pool,
-        "GET / HTTP/1.1" CRLF
-        "Host: localhost:12345" CRLF
-        "Authorization: Basic c2VyZjpzZXJmdGVzdA==" CRLF
-        "Transfer-Encoding: chunked" CRLF
-        CRLF
-        "1" CRLF
-        "1" CRLF
-        "0" CRLF CRLF);
-    message_list[2].text = apr_psprintf(test_pool,
-        "GET / HTTP/1.1" CRLF
-        "Host: localhost:12345" CRLF
-        "Authorization: Basic c2VyZjpzZXJmdGVzdA==" CRLF
-        "Transfer-Encoding: chunked" CRLF
-        CRLF
-        "1" CRLF
-        "2" CRLF
-        "0" CRLF CRLF);
-
-    action_list[0].kind = SERVER_RESPOND;
-    /* Use non-standard case WWW-Authenticate header and scheme name to test
-       for case insensitive comparisons. */
-    action_list[0].text = apr_psprintf(test_pool,
-        "HTTP/1.1 401 Unauthorized" CRLF
-        "Transfer-Encoding: chunked" CRLF
-        "www-Authenticate: bAsIc realm=""Test Suite""" CRLF
-        "%s"
-        CRLF
-        "1" CRLF CRLF
-        "0" CRLF CRLF, resp_hdrs);
-    action_list[1].kind = SERVER_RESPOND;
-    action_list[1].text = CHUNKED_EMPTY_RESPONSE;
-    action_list[2].kind = SERVER_RESPOND;
-    action_list[2].text = CHUNKED_EMPTY_RESPONSE;
-
-    /* Set up a test context with a server */
-    status = test_http_server_setup(&tb,
-                                    message_list, 3,
-                                    action_list, 3, 0, NULL,
-                                    test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    serf_config_authn_types(tb->context, SERF_AUTHN_BASIC);
-    serf_config_credentials_callback(tb->context, basic_authn_callback);
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
-
-    /* Test that a request is retried and authentication headers are set
-       correctly. */
-    num_requests_sent = 1;
-    num_requests_recvd = 2;
-
-    status = test_helper_run_requests_no_check(tc, tb, num_requests_sent,
-                                               handler_ctx, test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-    CuAssertIntEquals(tc, num_requests_recvd, tb->sent_requests->nelts);
-    CuAssertIntEquals(tc, num_requests_recvd, tb->accepted_requests->nelts);
-    CuAssertIntEquals(tc, num_requests_sent, tb->handled_requests->nelts);
-
-    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_AUTHNCB_CALLED);
-
-    /* Test that credentials were cached by asserting that the authn callback
-       wasn't called again. */
-    tb->result_flags = 0;
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 2);
-    status = test_helper_run_requests_no_check(tc, tb, num_requests_sent,
-                                               handler_ctx, test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-    CuAssertTrue(tc, !(tb->result_flags & TEST_RESULT_AUTHNCB_CALLED));
-}
-
-static void test_basic_authentication(CuTest *tc)
-{
-    basic_authentication(tc, "");
-}
-
-static void test_basic_authentication_keepalive_off(CuTest *tc)
-{
-    basic_authentication(tc, "Connection: close" CRLF);
-}
-
-static apr_status_t
-digest_authn_callback(char **username,
-                      char **password,
-                      serf_request_t *request, void *baton,
-                      int code, const char *authn_type,
-                      const char *realm,
-                      apr_pool_t *pool)
-{
-    handler_baton_t *handler_ctx = baton;
-    test_baton_t *tb = handler_ctx->tb;
-
-    tb->result_flags |= TEST_RESULT_AUTHNCB_CALLED;
-
-    if (code != 401)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    if (strcmp("Digest", authn_type) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    if (strcmp("<http://localhost:12345> Test Suite", realm) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-
-    *username = "serf";
-    *password = "serftest";
-
-    return APR_SUCCESS;
-}
-
-/* Test template, used for KeepAlive Off and KeepAlive On test */
-static void digest_authentication(CuTest *tc, const char *resp_hdrs)
-{
-    test_baton_t *tb;
-    handler_baton_t handler_ctx[2];
-    int num_requests_sent, num_requests_recvd;
-    test_server_message_t message_list[2];
-    test_server_action_t action_list[2];
-    apr_pool_t *test_pool = tc->testBaton;
-    apr_status_t status;
-
-    /* Expected string relies on strict order of headers and attributes of
-       Digest, both are not guaranteed.
-       6ff0d4cc201513ce970d5c6b25e1043b is encoded as: 
-         md5hex(md5hex("serf:Test Suite:serftest") & ":" &
-                md5hex("ABCDEF1234567890") & ":" &
-                md5hex("GET:/test/index.html"))
-     */
-    message_list[0].text = CHUNKED_REQUEST_URI("/test/index.html", 1, "1");
-    message_list[1].text = apr_psprintf(test_pool,
-        "GET /test/index.html HTTP/1.1" CRLF
-        "Host: localhost:12345" CRLF
-        "Authorization: Digest realm=\"Test Suite\", username=\"serf\", "
-        "nonce=\"ABCDEF1234567890\", uri=\"/test/index.html\", "
-        "response=\"6ff0d4cc201513ce970d5c6b25e1043b\", opaque=\"myopaque\", "
-        "algorithm=\"MD5\"" CRLF
-        "Transfer-Encoding: chunked" CRLF
-        CRLF
-        "1" CRLF
-        "1" CRLF
-        "0" CRLF CRLF);
-    action_list[0].kind = SERVER_RESPOND;
-    action_list[0].text = apr_psprintf(test_pool,
-        "HTTP/1.1 401 Unauthorized" CRLF
-        "Transfer-Encoding: chunked" CRLF
-        "WWW-Authenticate: Digest realm=\"Test Suite\","
-        "nonce=\"ABCDEF1234567890\",opaque=\"myopaque\","
-        "algorithm=\"MD5\",qop-options=\"auth\"" CRLF
-        "%s"
-        CRLF
-        "1" CRLF CRLF
-        "0" CRLF CRLF, resp_hdrs);
-    /* If the resp_hdrs includes "Connection: close", serf will automatically
-       reset the connection from the client side, no need to use 
-       SERVER_KILL_CONNECTION. */
-    action_list[1].kind = SERVER_RESPOND;
-    action_list[1].text = CHUNKED_EMPTY_RESPONSE;
-
-    /* Set up a test context with a server */
-    status = test_http_server_setup(&tb,
-                                    message_list, 2,
-                                    action_list, 2, 0, NULL,
-                                    test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    /* Add both Basic and Digest here, should use Digest only. */
-    serf_config_authn_types(tb->context, SERF_AUTHN_BASIC | SERF_AUTHN_DIGEST);
-    serf_config_credentials_callback(tb->context, digest_authn_callback);
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/test/index.html", 1);
-
-    /* Test that a request is retried and authentication headers are set
-       correctly. */
-    num_requests_sent = 1;
-    num_requests_recvd = 2;
-
-    status = test_helper_run_requests_no_check(tc, tb, num_requests_sent,
-                                               handler_ctx, test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-    CuAssertIntEquals(tc, num_requests_recvd, tb->sent_requests->nelts);
-    CuAssertIntEquals(tc, num_requests_recvd, tb->accepted_requests->nelts);
-    CuAssertIntEquals(tc, num_requests_sent, tb->handled_requests->nelts);
-
-    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_AUTHNCB_CALLED);
-}
-
-static void test_digest_authentication(CuTest *tc)
-{
-    digest_authentication(tc, "");
-}
-
-static void test_digest_authentication_keepalive_off(CuTest *tc)
-{
-    /* Add the Connection: close header to the response with the Digest headers.
-       This to test that the Digest headers will be added to the retry of the
-       request on the new connection. */
-    digest_authentication(tc, "Connection: close" CRLF);
-}
-
-static apr_status_t
-switched_realm_authn_callback(char **username,
-                              char **password,
-                              serf_request_t *request, void *baton,
-                              int code, const char *authn_type,
-                              const char *realm,
-                              apr_pool_t *pool)
-{
-    handler_baton_t *handler_ctx = baton;
-    test_baton_t *tb = handler_ctx->tb;
-    const char *exp_realm = tb->user_baton;
-
-    tb->result_flags |= TEST_RESULT_AUTHNCB_CALLED;
-
-    if (code != 401)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    if (strcmp(exp_realm, realm) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-
-    if (strcmp(realm, "<http://localhost:12345> Test Suite") == 0) {
-        *username = "serf";
-        *password = "serftest";
-    } else {
-        *username = "serf_newrealm";
-        *password = "serftest";
-    }
-
-    return APR_SUCCESS;
-}
-
-/* Test template, used for both Basic and Digest switch realms test */
-static void authentication_switch_realms(CuTest *tc,
-                                         const char *scheme,
-                                         const char *authn_attr,
-                                         const char *authz_attr_test_suite,
-                                         const char *authz_attr_wrong_realm,
-                                         const char *authz_attr_new_realm)
-{
-    test_baton_t *tb;
-    handler_baton_t handler_ctx[2];
-    int num_requests_sent, num_requests_recvd;
-    test_server_message_t message_list[5];
-    test_server_action_t action_list[5];
-    apr_pool_t *test_pool = tc->testBaton;
-    apr_status_t status;
-
-    
-    message_list[0].text = CHUNKED_REQUEST(1, "1");
-    message_list[1].text = apr_psprintf(test_pool,
-        "GET / HTTP/1.1" CRLF
-        "Host: localhost:12345" CRLF
-        "Authorization: %s %s" CRLF
-        "Transfer-Encoding: chunked" CRLF
-        CRLF
-        "1" CRLF
-        "1" CRLF
-        "0" CRLF CRLF, scheme, authz_attr_test_suite);
-    message_list[2].text = apr_psprintf(test_pool,
-        "GET / HTTP/1.1" CRLF
-        "Host: localhost:12345" CRLF
-        "Authorization: %s %s" CRLF
-        "Transfer-Encoding: chunked" CRLF
-        CRLF
-        "1" CRLF
-        "2" CRLF
-        "0" CRLF CRLF, scheme, authz_attr_test_suite);
-    /* The client doesn't know that /newrealm/ is in another realm, so it
-       reuses the credentials cached on the connection. */
-    message_list[3].text = apr_psprintf(test_pool,
-        "GET /newrealm/index.html HTTP/1.1" CRLF
-        "Host: localhost:12345" CRLF
-        "Authorization: %s %s" CRLF
-        "Transfer-Encoding: chunked" CRLF
-        CRLF
-        "1" CRLF
-        "3" CRLF
-        "0" CRLF CRLF, scheme, authz_attr_wrong_realm);
-    message_list[4].text = apr_psprintf(test_pool,
-        "GET /newrealm/index.html HTTP/1.1" CRLF
-        "Host: localhost:12345" CRLF
-        "Authorization: %s %s" CRLF
-        "Transfer-Encoding: chunked" CRLF
-        CRLF
-        "1" CRLF
-        "3" CRLF
-        "0" CRLF CRLF, scheme, authz_attr_new_realm);
-
-    action_list[0].kind = SERVER_RESPOND;
-    action_list[0].text = apr_psprintf(test_pool,
-        "HTTP/1.1 401 Unauthorized" CRLF
-        "Transfer-Encoding: chunked" CRLF
-        "WWW-Authenticate: %s realm=""Test Suite""%s" CRLF
-        CRLF
-        "1" CRLF CRLF
-        "0" CRLF CRLF, scheme, authn_attr);
-    action_list[1].kind = SERVER_RESPOND;
-    action_list[1].text = CHUNKED_EMPTY_RESPONSE;
-    action_list[2].kind = SERVER_RESPOND;
-    action_list[2].text = CHUNKED_EMPTY_RESPONSE;
-    action_list[3].kind = SERVER_RESPOND;
-    action_list[3].text = apr_psprintf(test_pool,
-        "HTTP/1.1 401 Unauthorized" CRLF
-        "Transfer-Encoding: chunked" CRLF
-        "WWW-Authenticate: %s realm=""New Realm""%s" CRLF
-        CRLF
-        "1" CRLF CRLF
-        "0" CRLF CRLF, scheme, authn_attr);
-    action_list[4].kind = SERVER_RESPOND;
-    action_list[4].text = CHUNKED_EMPTY_RESPONSE;
-
-    
-    /* Set up a test context with a server */
-    status = test_http_server_setup(&tb,
-                                    message_list, 5,
-                                    action_list, 5, 0, NULL,
-                                    test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    serf_config_authn_types(tb->context, SERF_AUTHN_BASIC | SERF_AUTHN_DIGEST);
-    serf_config_credentials_callback(tb->context,
-                                     switched_realm_authn_callback);
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
-
-    /* Test that a request is retried and authentication headers are set
-     correctly. */
-    num_requests_sent = 1;
-    num_requests_recvd = 2;
-
-    tb->user_baton = "<http://localhost:12345> Test Suite";
-    status = test_helper_run_requests_no_check(tc, tb, num_requests_sent,
-                                               handler_ctx, test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-    CuAssertIntEquals(tc, num_requests_recvd, tb->sent_requests->nelts);
-    CuAssertIntEquals(tc, num_requests_recvd, tb->accepted_requests->nelts);
-    CuAssertIntEquals(tc, num_requests_sent, tb->handled_requests->nelts);
-
-    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_AUTHNCB_CALLED);
-
-    /* Test that credentials were cached by asserting that the authn callback
-       wasn't called again. */
-    tb->result_flags = 0;
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 2);
-    status = test_helper_run_requests_no_check(tc, tb, num_requests_sent,
-                                               handler_ctx, test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-    CuAssertTrue(tc, !(tb->result_flags & TEST_RESULT_AUTHNCB_CALLED));
-
-    /* Switch realms. Test that serf asks the application for new
-       credentials. */
-    tb->result_flags = 0;
-    tb->user_baton = "<http://localhost:12345> New Realm";
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/newrealm/index.html", 3);
-    status = test_helper_run_requests_no_check(tc, tb, num_requests_sent,
-                                               handler_ctx, test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_AUTHNCB_CALLED);
-}
-
-static void test_basic_switch_realms(CuTest *tc)
-{
-    authentication_switch_realms(tc, "Basic", "", "c2VyZjpzZXJmdGVzdA==",
-                                 "c2VyZjpzZXJmdGVzdA==",
-                                 "c2VyZl9uZXdyZWFsbTpzZXJmdGVzdA==");
-}
-
-static void test_digest_switch_realms(CuTest *tc)
-{
-    authentication_switch_realms(tc, "Digest", ",nonce=\"ABCDEF1234567890\","
- "opaque=\"myopaque\", algorithm=\"MD5\",qop-options=\"auth\"",
- /* response hdr attribute for Test Suite realm, uri / */
- "realm=\"Test Suite\", username=\"serf\", nonce=\"ABCDEF1234567890\", "
- "uri=\"/\", response=\"3511a71fec5c02ab1c9212711a8baa58\", "
- "opaque=\"myopaque\", algorithm=\"MD5\"",
- /* response hdr attribute for Test Suite realm, uri /newrealm/index.html */
- "realm=\"Test Suite\", username=\"serf\", nonce=\"ABCDEF1234567890\", "
- "uri=\"/newrealm/index.html\", response=\"c6b673cf44ad16ef379930856b607344\", "
- "opaque=\"myopaque\", algorithm=\"MD5\"",
- /* response hdr attribute for New Realm realm, uri /newrealm/index.html */
- "realm=\"New Realm\", username=\"serf_newrealm\", nonce=\"ABCDEF1234567890\", "
- "uri=\"/newrealm/index.html\", response=\"f93f07d1412e53c421f66741a89198cb\", "
- "opaque=\"myopaque\", algorithm=\"MD5\"");
-}
-
-static void test_auth_on_HEAD(CuTest *tc)
-{
-    test_baton_t *tb;
-    handler_baton_t handler_ctx[2];
-    int num_requests_sent, num_requests_recvd;
-    apr_status_t status;
-    apr_pool_t *test_pool = tc->testBaton;
-
-    test_server_message_t message_list[] = {
-        { 
-            "HEAD / HTTP/1.1" CRLF
-            "Host: localhost:12345" CRLF
-            CRLF
-        },
-        {
-            "HEAD / HTTP/1.1" CRLF
-            "Host: localhost:12345" CRLF
-            "Authorization: Basic c2VyZjpzZXJmdGVzdA==" CRLF
-            CRLF
-        },
-    };
-    test_server_action_t action_list[] = {
-        {
-            SERVER_RESPOND,
-            "HTTP/1.1 401 Unauthorized" CRLF
-            "WWW-Authenticate: Basic Realm=""Test Suite""" CRLF
-            CRLF
-        },
-        {
-            SERVER_RESPOND,
-            "HTTP/1.1 200 Ok" CRLF
-            "Content-Type: text/html" CRLF
-            CRLF
-        },
-    };
-
-    /* Set up a test context with a server */
-    status = test_http_server_setup(&tb,
-                                    message_list, 2,
-                                    action_list, 2, 0, NULL,
-                                    test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    serf_config_authn_types(tb->context, SERF_AUTHN_BASIC);
-    serf_config_credentials_callback(tb->context, basic_authn_callback);
-
-    create_new_request(tb, &handler_ctx[0], "HEAD", "/", -1);
-
-    /* Test that a request is retried and authentication headers are set
-       correctly. */
-    num_requests_sent = 1;
-    num_requests_recvd = 2;
-
-    status = test_helper_run_requests_no_check(tc, tb, num_requests_sent,
-                                               handler_ctx, test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-    CuAssertIntEquals(tc, num_requests_recvd, tb->sent_requests->nelts);
-    CuAssertIntEquals(tc, num_requests_recvd, tb->accepted_requests->nelts);
-    CuAssertIntEquals(tc, num_requests_sent, tb->handled_requests->nelts);
-
-    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_AUTHNCB_CALLED);
-}
-
-/*****************************************************************************/
-CuSuite *test_auth(void)
-{
-    CuSuite *suite = CuSuiteNew();
-
-    CuSuiteSetSetupTeardownCallbacks(suite, test_setup, test_teardown);
-
-    SUITE_ADD_TEST(suite, test_authentication_disabled);
-    SUITE_ADD_TEST(suite, test_unsupported_authentication);
-    SUITE_ADD_TEST(suite, test_basic_authentication);
-    SUITE_ADD_TEST(suite, test_basic_authentication_keepalive_off);
-    SUITE_ADD_TEST(suite, test_digest_authentication);
-    SUITE_ADD_TEST(suite, test_digest_authentication_keepalive_off);
-    SUITE_ADD_TEST(suite, test_basic_switch_realms);
-    SUITE_ADD_TEST(suite, test_digest_switch_realms);
-    SUITE_ADD_TEST(suite, test_auth_on_HEAD);
-
-    return suite;
-}

Copied: vendor/serf/1.3.9/test/test_auth.c (from rev 9259, vendor/serf/dist/test/test_auth.c)
===================================================================
--- vendor/serf/1.3.9/test/test_auth.c	                        (rev 0)
+++ vendor/serf/1.3.9/test/test_auth.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,634 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_strings.h>
+
+#include "serf.h"
+#include "test_serf.h"
+
+static apr_status_t
+authn_callback_expect_not_called(char **username,
+                                 char **password,
+                                 serf_request_t *request, void *baton,
+                                 int code, const char *authn_type,
+                                 const char *realm,
+                                 apr_pool_t *pool)
+{
+    handler_baton_t *handler_ctx = baton;
+    test_baton_t *tb = handler_ctx->tb;
+
+    tb->result_flags |= TEST_RESULT_AUTHNCB_CALLED;
+
+    /* Should not have been called. */
+    return SERF_ERROR_ISSUE_IN_TESTSUITE;
+}
+
+/* Tests that authn fails if all authn schemes are disabled. */
+static void test_authentication_disabled(CuTest *tc)
+{
+    test_baton_t *tb;
+    handler_baton_t handler_ctx[2];
+
+    test_server_message_t message_list[] = {
+        {CHUNKED_REQUEST(1, "1")} };
+    test_server_action_t action_list[] = {
+        {SERVER_RESPOND, "HTTP/1.1 401 Unauthorized" CRLF
+            "Transfer-Encoding: chunked" CRLF
+            "WWW-Authenticate: Basic realm=""Test Suite""" CRLF
+            CRLF
+            "1" CRLF CRLF
+            "0" CRLF CRLF},
+    };
+    apr_status_t status;
+
+    apr_pool_t *test_pool = tc->testBaton;
+
+    /* Set up a test context with a server */
+    status = test_http_server_setup(&tb,
+                                    message_list, 1,
+                                    action_list, 1, 0, NULL,
+                                    test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    serf_config_authn_types(tb->context, SERF_AUTHN_NONE);
+    serf_config_credentials_callback(tb->context,
+                                     authn_callback_expect_not_called);
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+
+    status = test_helper_run_requests_no_check(tc, tb, 1,
+                                               handler_ctx, test_pool);
+    CuAssertIntEquals(tc, SERF_ERROR_AUTHN_NOT_SUPPORTED, status);
+    CuAssertIntEquals(tc, 1, tb->sent_requests->nelts);
+    CuAssertIntEquals(tc, 1, tb->accepted_requests->nelts);
+    CuAssertIntEquals(tc, 0, tb->handled_requests->nelts);
+
+    CuAssertTrue(tc, !(tb->result_flags & TEST_RESULT_AUTHNCB_CALLED));
+}
+
+/* Tests that authn fails if encountered an unsupported scheme. */
+static void test_unsupported_authentication(CuTest *tc)
+{
+    test_baton_t *tb;
+    handler_baton_t handler_ctx[2];
+
+    test_server_message_t message_list[] = {
+        {CHUNKED_REQUEST(1, "1")} };
+    test_server_action_t action_list[] = {
+        {SERVER_RESPOND, "HTTP/1.1 401 Unauthorized" CRLF
+            "Transfer-Encoding: chunked" CRLF
+            "WWW-Authenticate: NotExistent realm=""Test Suite""" CRLF
+            CRLF
+            "1" CRLF CRLF
+            "0" CRLF CRLF},
+    };
+    apr_status_t status;
+
+    apr_pool_t *test_pool = tc->testBaton;
+
+    /* Set up a test context with a server */
+    status = test_http_server_setup(&tb,
+                                    message_list, 1,
+                                    action_list, 1, 0, NULL,
+                                    test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    serf_config_authn_types(tb->context, SERF_AUTHN_ALL);
+    serf_config_credentials_callback(tb->context,
+                                     authn_callback_expect_not_called);
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+
+    status = test_helper_run_requests_no_check(tc, tb, 1,
+                                               handler_ctx, test_pool);
+    CuAssertIntEquals(tc, SERF_ERROR_AUTHN_NOT_SUPPORTED, status);
+    CuAssertIntEquals(tc, 1, tb->sent_requests->nelts);
+    CuAssertIntEquals(tc, 1, tb->accepted_requests->nelts);
+    CuAssertIntEquals(tc, 0, tb->handled_requests->nelts);
+
+    CuAssertTrue(tc, !(tb->result_flags & TEST_RESULT_AUTHNCB_CALLED));
+}
+
+static apr_status_t
+basic_authn_callback(char **username,
+                     char **password,
+                     serf_request_t *request, void *baton,
+                     int code, const char *authn_type,
+                     const char *realm,
+                     apr_pool_t *pool)
+{
+    handler_baton_t *handler_ctx = baton;
+    test_baton_t *tb = handler_ctx->tb;
+
+    tb->result_flags |= TEST_RESULT_AUTHNCB_CALLED;
+
+    if (code != 401)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    if (strcmp("Basic", authn_type) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    if (strcmp("<http://localhost:12345> Test Suite", realm) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+
+    *username = "serf";
+    *password = "serftest";
+
+    return APR_SUCCESS;
+}
+
+/* Test template, used for KeepAlive Off and KeepAlive On test */
+static void basic_authentication(CuTest *tc, const char *resp_hdrs)
+{
+    test_baton_t *tb;
+    handler_baton_t handler_ctx[2];
+    int num_requests_sent, num_requests_recvd;
+    test_server_message_t message_list[3];
+    test_server_action_t action_list[3];
+    apr_status_t status;
+
+    apr_pool_t *test_pool = tc->testBaton;
+    
+    /* Expected string relies on strict order of headers, which is not
+       guaranteed. c2VyZjpzZXJmdGVzdA== is base64 encoded serf:serftest . */
+    message_list[0].text = CHUNKED_REQUEST(1, "1");
+    message_list[1].text = apr_psprintf(test_pool,
+        "GET / HTTP/1.1" CRLF
+        "Host: localhost:12345" CRLF
+        "Authorization: Basic c2VyZjpzZXJmdGVzdA==" CRLF
+        "Transfer-Encoding: chunked" CRLF
+        CRLF
+        "1" CRLF
+        "1" CRLF
+        "0" CRLF CRLF);
+    message_list[2].text = apr_psprintf(test_pool,
+        "GET / HTTP/1.1" CRLF
+        "Host: localhost:12345" CRLF
+        "Authorization: Basic c2VyZjpzZXJmdGVzdA==" CRLF
+        "Transfer-Encoding: chunked" CRLF
+        CRLF
+        "1" CRLF
+        "2" CRLF
+        "0" CRLF CRLF);
+
+    action_list[0].kind = SERVER_RESPOND;
+    /* Use non-standard case WWW-Authenticate header and scheme name to test
+       for case insensitive comparisons. */
+    action_list[0].text = apr_psprintf(test_pool,
+        "HTTP/1.1 401 Unauthorized" CRLF
+        "Transfer-Encoding: chunked" CRLF
+        "www-Authenticate: bAsIc realm=""Test Suite""" CRLF
+        "%s"
+        CRLF
+        "1" CRLF CRLF
+        "0" CRLF CRLF, resp_hdrs);
+    action_list[1].kind = SERVER_RESPOND;
+    action_list[1].text = CHUNKED_EMPTY_RESPONSE;
+    action_list[2].kind = SERVER_RESPOND;
+    action_list[2].text = CHUNKED_EMPTY_RESPONSE;
+
+    /* Set up a test context with a server */
+    status = test_http_server_setup(&tb,
+                                    message_list, 3,
+                                    action_list, 3, 0, NULL,
+                                    test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    serf_config_authn_types(tb->context, SERF_AUTHN_BASIC);
+    serf_config_credentials_callback(tb->context, basic_authn_callback);
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+
+    /* Test that a request is retried and authentication headers are set
+       correctly. */
+    num_requests_sent = 1;
+    num_requests_recvd = 2;
+
+    status = test_helper_run_requests_no_check(tc, tb, num_requests_sent,
+                                               handler_ctx, test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    CuAssertIntEquals(tc, num_requests_recvd, tb->sent_requests->nelts);
+    CuAssertIntEquals(tc, num_requests_recvd, tb->accepted_requests->nelts);
+    CuAssertIntEquals(tc, num_requests_sent, tb->handled_requests->nelts);
+
+    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_AUTHNCB_CALLED);
+
+    /* Test that credentials were cached by asserting that the authn callback
+       wasn't called again. */
+    tb->result_flags = 0;
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 2);
+    status = test_helper_run_requests_no_check(tc, tb, num_requests_sent,
+                                               handler_ctx, test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    CuAssertTrue(tc, !(tb->result_flags & TEST_RESULT_AUTHNCB_CALLED));
+}
+
+static void test_basic_authentication(CuTest *tc)
+{
+    basic_authentication(tc, "");
+}
+
+static void test_basic_authentication_keepalive_off(CuTest *tc)
+{
+    basic_authentication(tc, "Connection: close" CRLF);
+}
+
+static apr_status_t
+digest_authn_callback(char **username,
+                      char **password,
+                      serf_request_t *request, void *baton,
+                      int code, const char *authn_type,
+                      const char *realm,
+                      apr_pool_t *pool)
+{
+    handler_baton_t *handler_ctx = baton;
+    test_baton_t *tb = handler_ctx->tb;
+
+    tb->result_flags |= TEST_RESULT_AUTHNCB_CALLED;
+
+    if (code != 401)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    if (strcmp("Digest", authn_type) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    if (strcmp("<http://localhost:12345> Test Suite", realm) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+
+    *username = "serf";
+    *password = "serftest";
+
+    return APR_SUCCESS;
+}
+
+/* Test template, used for KeepAlive Off and KeepAlive On test */
+static void digest_authentication(CuTest *tc, const char *resp_hdrs)
+{
+    test_baton_t *tb;
+    handler_baton_t handler_ctx[2];
+    int num_requests_sent, num_requests_recvd;
+    test_server_message_t message_list[2];
+    test_server_action_t action_list[2];
+    apr_pool_t *test_pool = tc->testBaton;
+    apr_status_t status;
+
+    /* Expected string relies on strict order of headers and attributes of
+       Digest, both are not guaranteed.
+       6ff0d4cc201513ce970d5c6b25e1043b is encoded as: 
+         md5hex(md5hex("serf:Test Suite:serftest") & ":" &
+                md5hex("ABCDEF1234567890") & ":" &
+                md5hex("GET:/test/index.html"))
+     */
+    message_list[0].text = CHUNKED_REQUEST_URI("/test/index.html", 1, "1");
+    message_list[1].text = apr_psprintf(test_pool,
+        "GET /test/index.html HTTP/1.1" CRLF
+        "Host: localhost:12345" CRLF
+        "Authorization: Digest realm=\"Test Suite\", username=\"serf\", "
+        "nonce=\"ABCDEF1234567890\", uri=\"/test/index.html\", "
+        "response=\"6ff0d4cc201513ce970d5c6b25e1043b\", opaque=\"myopaque\", "
+        "algorithm=\"MD5\"" CRLF
+        "Transfer-Encoding: chunked" CRLF
+        CRLF
+        "1" CRLF
+        "1" CRLF
+        "0" CRLF CRLF);
+    action_list[0].kind = SERVER_RESPOND;
+    action_list[0].text = apr_psprintf(test_pool,
+        "HTTP/1.1 401 Unauthorized" CRLF
+        "Transfer-Encoding: chunked" CRLF
+        "WWW-Authenticate: Digest realm=\"Test Suite\","
+        "nonce=\"ABCDEF1234567890\",opaque=\"myopaque\","
+        "algorithm=\"MD5\",qop-options=\"auth\"" CRLF
+        "%s"
+        CRLF
+        "1" CRLF CRLF
+        "0" CRLF CRLF, resp_hdrs);
+    /* If the resp_hdrs includes "Connection: close", serf will automatically
+       reset the connection from the client side, no need to use 
+       SERVER_KILL_CONNECTION. */
+    action_list[1].kind = SERVER_RESPOND;
+    action_list[1].text = CHUNKED_EMPTY_RESPONSE;
+
+    /* Set up a test context with a server */
+    status = test_http_server_setup(&tb,
+                                    message_list, 2,
+                                    action_list, 2, 0, NULL,
+                                    test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    /* Add both Basic and Digest here, should use Digest only. */
+    serf_config_authn_types(tb->context, SERF_AUTHN_BASIC | SERF_AUTHN_DIGEST);
+    serf_config_credentials_callback(tb->context, digest_authn_callback);
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/test/index.html", 1);
+
+    /* Test that a request is retried and authentication headers are set
+       correctly. */
+    num_requests_sent = 1;
+    num_requests_recvd = 2;
+
+    status = test_helper_run_requests_no_check(tc, tb, num_requests_sent,
+                                               handler_ctx, test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    CuAssertIntEquals(tc, num_requests_recvd, tb->sent_requests->nelts);
+    CuAssertIntEquals(tc, num_requests_recvd, tb->accepted_requests->nelts);
+    CuAssertIntEquals(tc, num_requests_sent, tb->handled_requests->nelts);
+
+    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_AUTHNCB_CALLED);
+}
+
+static void test_digest_authentication(CuTest *tc)
+{
+    digest_authentication(tc, "");
+}
+
+static void test_digest_authentication_keepalive_off(CuTest *tc)
+{
+    /* Add the Connection: close header to the response with the Digest headers.
+       This to test that the Digest headers will be added to the retry of the
+       request on the new connection. */
+    digest_authentication(tc, "Connection: close" CRLF);
+}
+
+static apr_status_t
+switched_realm_authn_callback(char **username,
+                              char **password,
+                              serf_request_t *request, void *baton,
+                              int code, const char *authn_type,
+                              const char *realm,
+                              apr_pool_t *pool)
+{
+    handler_baton_t *handler_ctx = baton;
+    test_baton_t *tb = handler_ctx->tb;
+    const char *exp_realm = tb->user_baton;
+
+    tb->result_flags |= TEST_RESULT_AUTHNCB_CALLED;
+
+    if (code != 401)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    if (strcmp(exp_realm, realm) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+
+    if (strcmp(realm, "<http://localhost:12345> Test Suite") == 0) {
+        *username = "serf";
+        *password = "serftest";
+    } else {
+        *username = "serf_newrealm";
+        *password = "serftest";
+    }
+
+    return APR_SUCCESS;
+}
+
+/* Test template, used for both Basic and Digest switch realms test */
+static void authentication_switch_realms(CuTest *tc,
+                                         const char *scheme,
+                                         const char *authn_attr,
+                                         const char *authz_attr_test_suite,
+                                         const char *authz_attr_wrong_realm,
+                                         const char *authz_attr_new_realm)
+{
+    test_baton_t *tb;
+    handler_baton_t handler_ctx[2];
+    int num_requests_sent, num_requests_recvd;
+    test_server_message_t message_list[5];
+    test_server_action_t action_list[5];
+    apr_pool_t *test_pool = tc->testBaton;
+    apr_status_t status;
+
+    
+    message_list[0].text = CHUNKED_REQUEST(1, "1");
+    message_list[1].text = apr_psprintf(test_pool,
+        "GET / HTTP/1.1" CRLF
+        "Host: localhost:12345" CRLF
+        "Authorization: %s %s" CRLF
+        "Transfer-Encoding: chunked" CRLF
+        CRLF
+        "1" CRLF
+        "1" CRLF
+        "0" CRLF CRLF, scheme, authz_attr_test_suite);
+    message_list[2].text = apr_psprintf(test_pool,
+        "GET / HTTP/1.1" CRLF
+        "Host: localhost:12345" CRLF
+        "Authorization: %s %s" CRLF
+        "Transfer-Encoding: chunked" CRLF
+        CRLF
+        "1" CRLF
+        "2" CRLF
+        "0" CRLF CRLF, scheme, authz_attr_test_suite);
+    /* The client doesn't know that /newrealm/ is in another realm, so it
+       reuses the credentials cached on the connection. */
+    message_list[3].text = apr_psprintf(test_pool,
+        "GET /newrealm/index.html HTTP/1.1" CRLF
+        "Host: localhost:12345" CRLF
+        "Authorization: %s %s" CRLF
+        "Transfer-Encoding: chunked" CRLF
+        CRLF
+        "1" CRLF
+        "3" CRLF
+        "0" CRLF CRLF, scheme, authz_attr_wrong_realm);
+    message_list[4].text = apr_psprintf(test_pool,
+        "GET /newrealm/index.html HTTP/1.1" CRLF
+        "Host: localhost:12345" CRLF
+        "Authorization: %s %s" CRLF
+        "Transfer-Encoding: chunked" CRLF
+        CRLF
+        "1" CRLF
+        "3" CRLF
+        "0" CRLF CRLF, scheme, authz_attr_new_realm);
+
+    action_list[0].kind = SERVER_RESPOND;
+    action_list[0].text = apr_psprintf(test_pool,
+        "HTTP/1.1 401 Unauthorized" CRLF
+        "Transfer-Encoding: chunked" CRLF
+        "WWW-Authenticate: %s realm=""Test Suite""%s" CRLF
+        CRLF
+        "1" CRLF CRLF
+        "0" CRLF CRLF, scheme, authn_attr);
+    action_list[1].kind = SERVER_RESPOND;
+    action_list[1].text = CHUNKED_EMPTY_RESPONSE;
+    action_list[2].kind = SERVER_RESPOND;
+    action_list[2].text = CHUNKED_EMPTY_RESPONSE;
+    action_list[3].kind = SERVER_RESPOND;
+    action_list[3].text = apr_psprintf(test_pool,
+        "HTTP/1.1 401 Unauthorized" CRLF
+        "Transfer-Encoding: chunked" CRLF
+        "WWW-Authenticate: %s realm=""New Realm""%s" CRLF
+        CRLF
+        "1" CRLF CRLF
+        "0" CRLF CRLF, scheme, authn_attr);
+    action_list[4].kind = SERVER_RESPOND;
+    action_list[4].text = CHUNKED_EMPTY_RESPONSE;
+
+    
+    /* Set up a test context with a server */
+    status = test_http_server_setup(&tb,
+                                    message_list, 5,
+                                    action_list, 5, 0, NULL,
+                                    test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    serf_config_authn_types(tb->context, SERF_AUTHN_BASIC | SERF_AUTHN_DIGEST);
+    serf_config_credentials_callback(tb->context,
+                                     switched_realm_authn_callback);
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+
+    /* Test that a request is retried and authentication headers are set
+     correctly. */
+    num_requests_sent = 1;
+    num_requests_recvd = 2;
+
+    tb->user_baton = "<http://localhost:12345> Test Suite";
+    status = test_helper_run_requests_no_check(tc, tb, num_requests_sent,
+                                               handler_ctx, test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    CuAssertIntEquals(tc, num_requests_recvd, tb->sent_requests->nelts);
+    CuAssertIntEquals(tc, num_requests_recvd, tb->accepted_requests->nelts);
+    CuAssertIntEquals(tc, num_requests_sent, tb->handled_requests->nelts);
+
+    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_AUTHNCB_CALLED);
+
+    /* Test that credentials were cached by asserting that the authn callback
+       wasn't called again. */
+    tb->result_flags = 0;
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 2);
+    status = test_helper_run_requests_no_check(tc, tb, num_requests_sent,
+                                               handler_ctx, test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    CuAssertTrue(tc, !(tb->result_flags & TEST_RESULT_AUTHNCB_CALLED));
+
+    /* Switch realms. Test that serf asks the application for new
+       credentials. */
+    tb->result_flags = 0;
+    tb->user_baton = "<http://localhost:12345> New Realm";
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/newrealm/index.html", 3);
+    status = test_helper_run_requests_no_check(tc, tb, num_requests_sent,
+                                               handler_ctx, test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_AUTHNCB_CALLED);
+}
+
+static void test_basic_switch_realms(CuTest *tc)
+{
+    authentication_switch_realms(tc, "Basic", "", "c2VyZjpzZXJmdGVzdA==",
+                                 "c2VyZjpzZXJmdGVzdA==",
+                                 "c2VyZl9uZXdyZWFsbTpzZXJmdGVzdA==");
+}
+
+static void test_digest_switch_realms(CuTest *tc)
+{
+    authentication_switch_realms(tc, "Digest", ",nonce=\"ABCDEF1234567890\","
+ "opaque=\"myopaque\", algorithm=\"MD5\",qop-options=\"auth\"",
+ /* response hdr attribute for Test Suite realm, uri / */
+ "realm=\"Test Suite\", username=\"serf\", nonce=\"ABCDEF1234567890\", "
+ "uri=\"/\", response=\"3511a71fec5c02ab1c9212711a8baa58\", "
+ "opaque=\"myopaque\", algorithm=\"MD5\"",
+ /* response hdr attribute for Test Suite realm, uri /newrealm/index.html */
+ "realm=\"Test Suite\", username=\"serf\", nonce=\"ABCDEF1234567890\", "
+ "uri=\"/newrealm/index.html\", response=\"c6b673cf44ad16ef379930856b607344\", "
+ "opaque=\"myopaque\", algorithm=\"MD5\"",
+ /* response hdr attribute for New Realm realm, uri /newrealm/index.html */
+ "realm=\"New Realm\", username=\"serf_newrealm\", nonce=\"ABCDEF1234567890\", "
+ "uri=\"/newrealm/index.html\", response=\"f93f07d1412e53c421f66741a89198cb\", "
+ "opaque=\"myopaque\", algorithm=\"MD5\"");
+}
+
+static void test_auth_on_HEAD(CuTest *tc)
+{
+    test_baton_t *tb;
+    handler_baton_t handler_ctx[2];
+    int num_requests_sent, num_requests_recvd;
+    apr_status_t status;
+    apr_pool_t *test_pool = tc->testBaton;
+
+    test_server_message_t message_list[] = {
+        { 
+            "HEAD / HTTP/1.1" CRLF
+            "Host: localhost:12345" CRLF
+            CRLF
+        },
+        {
+            "HEAD / HTTP/1.1" CRLF
+            "Host: localhost:12345" CRLF
+            "Authorization: Basic c2VyZjpzZXJmdGVzdA==" CRLF
+            CRLF
+        },
+    };
+    test_server_action_t action_list[] = {
+        {
+            SERVER_RESPOND,
+            "HTTP/1.1 401 Unauthorized" CRLF
+            "WWW-Authenticate: Basic Realm=""Test Suite""" CRLF
+            CRLF
+        },
+        {
+            SERVER_RESPOND,
+            "HTTP/1.1 200 Ok" CRLF
+            "Content-Type: text/html" CRLF
+            CRLF
+        },
+    };
+
+    /* Set up a test context with a server */
+    status = test_http_server_setup(&tb,
+                                    message_list, 2,
+                                    action_list, 2, 0, NULL,
+                                    test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    serf_config_authn_types(tb->context, SERF_AUTHN_BASIC);
+    serf_config_credentials_callback(tb->context, basic_authn_callback);
+
+    create_new_request(tb, &handler_ctx[0], "HEAD", "/", -1);
+
+    /* Test that a request is retried and authentication headers are set
+       correctly. */
+    num_requests_sent = 1;
+    num_requests_recvd = 2;
+
+    status = test_helper_run_requests_no_check(tc, tb, num_requests_sent,
+                                               handler_ctx, test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    CuAssertIntEquals(tc, num_requests_recvd, tb->sent_requests->nelts);
+    CuAssertIntEquals(tc, num_requests_recvd, tb->accepted_requests->nelts);
+    CuAssertIntEquals(tc, num_requests_sent, tb->handled_requests->nelts);
+
+    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_AUTHNCB_CALLED);
+}
+
+/*****************************************************************************/
+CuSuite *test_auth(void)
+{
+    CuSuite *suite = CuSuiteNew();
+
+    CuSuiteSetSetupTeardownCallbacks(suite, test_setup, test_teardown);
+
+    SUITE_ADD_TEST(suite, test_authentication_disabled);
+    SUITE_ADD_TEST(suite, test_unsupported_authentication);
+    SUITE_ADD_TEST(suite, test_basic_authentication);
+    SUITE_ADD_TEST(suite, test_basic_authentication_keepalive_off);
+    SUITE_ADD_TEST(suite, test_digest_authentication);
+    SUITE_ADD_TEST(suite, test_digest_authentication_keepalive_off);
+    SUITE_ADD_TEST(suite, test_basic_switch_realms);
+    SUITE_ADD_TEST(suite, test_digest_switch_realms);
+    SUITE_ADD_TEST(suite, test_auth_on_HEAD);
+
+    return suite;
+}

Deleted: vendor/serf/1.3.9/test/test_buckets.c
===================================================================
--- vendor/serf/dist/test/test_buckets.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/test/test_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,1601 +0,0 @@
-/* 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 <apr_random.h>
-#include <zlib.h>
-
-#include "serf.h"
-#include "test_serf.h"
-
-/* test case has access to internal functions. */
-#include "serf_private.h"
-#include "serf_bucket_util.h"
-
-static apr_status_t read_all(serf_bucket_t *bkt,
-                             char *buf,
-                             apr_size_t buf_len,
-                             apr_size_t *read_len)
-{
-    const char *data;
-    apr_size_t data_len;
-    apr_status_t status;
-    apr_size_t read;
-
-    read = 0;
-
-    do
-    {
-        status = serf_bucket_read(bkt, SERF_READ_ALL_AVAIL, &data, &data_len);
-
-        if (!SERF_BUCKET_READ_ERROR(status))
-        {
-            if (data_len > buf_len - read)
-            {
-                /* Buffer is not large enough to read all data */
-                data_len = buf_len - read;
-                status = SERF_ERROR_ISSUE_IN_TESTSUITE;
-            }
-            memcpy(buf + read, data, data_len);
-            read += data_len;
-        }
-    } while(status == APR_SUCCESS);
-
-    *read_len = read;
-    return status;
-}
-
-/* Reads bucket until EOF found and compares read data with zero terminated
-   string expected. Report all failures using CuTest. */
-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);
-}
-
-/* Reads bucket with serf_bucket_readline until EOF found and compares:
-   - actual line endings with expected line endings
-   - actual data with zero terminated string expected.
-   Reports all failures using CuTest. */
-void readlines_and_check_bucket(CuTest *tc, serf_bucket_t *bkt,
-                                int acceptable,
-                                const char *expected,
-                                int expected_nr_of_lines)
-{
-    apr_status_t status;
-    int actual_nr_of_lines = 0;
-
-    do
-    {
-        const char *data;
-        apr_size_t len;
-        int found;
-
-        status = serf_bucket_readline(bkt, acceptable, &found,
-                                      &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;
-
-        if (found == SERF_NEWLINE_CRLF_SPLIT)
-            continue;
-
-        if (found != SERF_NEWLINE_NONE)
-        {
-            actual_nr_of_lines++;
-
-            CuAssert(tc, "Unexpected line ending type!",
-                     found & acceptable);
-            if (found & SERF_NEWLINE_CR)
-                CuAssert(tc, "CR Line ending was reported but not in data!",
-                         strncmp(data + len - 1, "\r", 1) == 0);
-            if (found & SERF_NEWLINE_LF)
-                CuAssert(tc, "LF Line ending was reported but not in data!",
-                         strncmp(data + len - 1, "\n", 1) == 0);
-            if (found & SERF_NEWLINE_CRLF)
-                CuAssert(tc, "CRLF Line ending was reported but not in data!",
-                         strncmp(data + len - 2, "\r\n", 2) == 0);
-        } else
-        {
-            if (status == APR_EOF && len)
-                actual_nr_of_lines++;
-
-            if (acceptable & SERF_NEWLINE_CR)
-                CuAssert(tc, "CR Line ending was not reported but in data!",
-                         strncmp(data + len - 1, "\r", 1) != 0);
-            if (acceptable & SERF_NEWLINE_LF)
-                CuAssert(tc, "LF Line ending was not reported but in data!",
-                         strncmp(data + len - 1, "\n", 1) != 0);
-            if (acceptable & SERF_NEWLINE_CRLF)
-                CuAssert(tc, "CRLF Line ending was not reported but in data!",
-                         strncmp(data + len - 2, "\r\n", 2) != 0);
-        }
-    } while(!APR_STATUS_IS_EOF(status));
-
-    CuAssertIntEquals(tc, expected_nr_of_lines, actual_nr_of_lines);
-    CuAssert(tc, "Read less data than expected.", strlen(expected) == 0);
-}
-
-
-/******************************** TEST CASES **********************************/
-
-static void test_simple_bucket_readline(CuTest *tc)
-{
-    apr_status_t status;
-    serf_bucket_t *bkt;
-    const char *data;
-    int found;
-    apr_size_t len;
-    const char *body;
-    
-    apr_pool_t *test_pool = tc->testBaton;
-    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
-                                                              NULL);
-
-    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);
-
-    /* acceptable line types should be reported */
-    bkt = SERF_BUCKET_SIMPLE_STRING("line1" CRLF, alloc);
-    readlines_and_check_bucket(tc, bkt, SERF_NEWLINE_CRLF, "line1" CRLF, 1);
-    bkt = SERF_BUCKET_SIMPLE_STRING("line1" LF, alloc);
-    readlines_and_check_bucket(tc, bkt, SERF_NEWLINE_LF, "line1" LF, 1);
-    bkt = SERF_BUCKET_SIMPLE_STRING("line1" LF, alloc);
-    readlines_and_check_bucket(tc, bkt, SERF_NEWLINE_LF, "line1" LF, 1);
-    /* special cases, but acceptable */
-    bkt = SERF_BUCKET_SIMPLE_STRING("line1" CRLF, alloc);
-    readlines_and_check_bucket(tc, bkt, SERF_NEWLINE_CR, "line1" CRLF, 2);
-    bkt = SERF_BUCKET_SIMPLE_STRING("line1" CRLF, alloc);
-    readlines_and_check_bucket(tc, bkt, SERF_NEWLINE_LF, "line1" CRLF, 1);
-
-    /* Unacceptable line types should not be reported */
-    bkt = SERF_BUCKET_SIMPLE_STRING("line1" LF, alloc);
-    readlines_and_check_bucket(tc, bkt, SERF_NEWLINE_CR, "line1" LF, 1);
-    bkt = SERF_BUCKET_SIMPLE_STRING("line1" LF, alloc);
-    readlines_and_check_bucket(tc, bkt, SERF_NEWLINE_CRLF, "line1" LF, 1);
-    bkt = SERF_BUCKET_SIMPLE_STRING("line1" CR, alloc);
-    readlines_and_check_bucket(tc, bkt, SERF_NEWLINE_LF, "line1" CR, 1);
-#if 0
-    /* TODO: looks like a bug, CRLF acceptable on buffer with CR returns
-       SERF_NEWLINE_CRLF_SPLIT, but here that CR comes at the end of the 
-       buffer (APR_EOF), so should have been SERF_NEWLINE_NONE! */
-    bkt = SERF_BUCKET_SIMPLE_STRING("line1" CR, alloc);
-    readlines_and_check_bucket(tc, bkt, SERF_NEWLINE_CRLF, "line1" CR, 1);
-#endif
-
-    body = "12345678901234567890" CRLF
-           "12345678901234567890" CRLF
-           "12345678901234567890" CRLF;
-    bkt = SERF_BUCKET_SIMPLE_STRING(body, alloc);
-    readlines_and_check_bucket(tc, bkt, SERF_NEWLINE_LF, body, 3);
-}
-
-static void test_response_bucket_read(CuTest *tc)
-{
-    serf_bucket_t *bkt, *tmp;
-
-    apr_pool_t *test_pool = tc->testBaton;
-    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
-                                                              NULL);
-
-    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_headers(CuTest *tc)
-{
-    serf_bucket_t *bkt, *tmp, *hdr;
-
-    apr_pool_t *test_pool = tc->testBaton;
-    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
-                                                              NULL);
-
-    tmp = SERF_BUCKET_SIMPLE_STRING(
-        "HTTP/1.1 405 Method Not Allowed" CRLF
-        "Date: Sat, 12 Jun 2010 14:17:10 GMT"  CRLF
-        "Server: Apache"  CRLF
-        "Allow: "  CRLF
-        "Content-Length: 7"  CRLF
-        "Content-Type: text/html; charset=iso-8859-1" CRLF
-        "NoSpace:" 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");
-
-    hdr = serf_bucket_response_get_headers(bkt);
-    CuAssertStrEquals(tc,
-        "",
-        serf_bucket_headers_get(hdr, "Allow"));
-    CuAssertStrEquals(tc,
-        "7",
-        serf_bucket_headers_get(hdr, "Content-Length"));
-    CuAssertStrEquals(tc,
-        "",
-        serf_bucket_headers_get(hdr, "NoSpace"));
-}
-
-static void test_response_bucket_chunked_read(CuTest *tc)
-{
-    serf_bucket_t *bkt, *tmp, *hdrs;
-
-    apr_pool_t *test_pool = tc->testBaton;
-    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
-                                                              NULL);
-
-    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)
-{
-    apr_pool_t *test_pool = tc->testBaton;
-    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"));
-
-    serf_bucket_headers_set(hdrs, "Foo", "test");
-
-    CuAssertStrEquals(tc, "bar,baz,test", serf_bucket_headers_get(hdrs, "Foo"));
-
-    /* headers are case insensitive. */
-    CuAssertStrEquals(tc, "bar,baz,test", serf_bucket_headers_get(hdrs, "fOo"));
-}
-
-
-static void test_iovec_buckets(CuTest *tc)
-{
-    apr_status_t status;
-    serf_bucket_t *bkt, *iobkt;
-    const char *data;
-    apr_size_t len;
-    struct iovec vecs[32];
-    struct iovec tgt_vecs[32];
-    int i;
-    int vecs_used;
-
-    apr_pool_t *test_pool = tc->testBaton;
-    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
-                                                              NULL);
-
-    /* Test 1: Read a single string in an iovec, store it in a iovec_bucket
-       and then read it back. */
-    bkt = SERF_BUCKET_SIMPLE_STRING(
-        "line1" CRLF
-        "line2",
-        alloc);
-
-    status = serf_bucket_read_iovec(bkt, SERF_READ_ALL_AVAIL, 32, vecs,
-                                    &vecs_used);
-
-    iobkt = serf_bucket_iovec_create(vecs, vecs_used, alloc);
-
-    /* Check available data */
-    status = serf_bucket_peek(iobkt, &data, &len);
-    CuAssertIntEquals(tc, APR_EOF, status);
-    CuAssertIntEquals(tc, strlen("line1" CRLF "line2"), len);
-
-    /* Try to read only a few bytes (less than what's in the first buffer). */
-    status = serf_bucket_read_iovec(iobkt, 3, 32, tgt_vecs, &vecs_used);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-    CuAssertIntEquals(tc, 1, vecs_used);
-    CuAssertIntEquals(tc, 3, tgt_vecs[0].iov_len);
-    CuAssert(tc, tgt_vecs[0].iov_base,
-             strncmp("lin", tgt_vecs[0].iov_base, tgt_vecs[0].iov_len) == 0);
-
-    /* Read the rest of the data. */
-    status = serf_bucket_read_iovec(iobkt, SERF_READ_ALL_AVAIL, 32, tgt_vecs,
-                                    &vecs_used);
-    CuAssertIntEquals(tc, APR_EOF, status);
-    CuAssertIntEquals(tc, 1, vecs_used);
-    CuAssertIntEquals(tc, strlen("e1" CRLF "line2"), tgt_vecs[0].iov_len);
-    CuAssert(tc, tgt_vecs[0].iov_base,
-             strncmp("e1" CRLF "line2", tgt_vecs[0].iov_base, tgt_vecs[0].iov_len - 3) == 0);
-
-    /* Bucket should now be empty */
-    status = serf_bucket_peek(iobkt, &data, &len);
-    CuAssertIntEquals(tc, APR_EOF, status);
-    CuAssertIntEquals(tc, 0, len);
-
-    /* Test 2: Read multiple character bufs in an iovec, then read them back
-       in bursts. */
-    for (i = 0; i < 32 ; i++) {
-        vecs[i].iov_base = apr_psprintf(test_pool, "data %02d 901234567890", i);
-        vecs[i].iov_len = strlen(vecs[i].iov_base);
-    }
-
-    iobkt = serf_bucket_iovec_create(vecs, 32, alloc);
-
-    /* Check that some data is in the buffer. Don't verify the actual data, the
-       amount of data returned is not guaranteed to be the full buffer. */
-    status = serf_bucket_peek(iobkt, &data, &len);
-    CuAssertTrue(tc, len > 0);
-    CuAssertIntEquals(tc, APR_SUCCESS, status); /* this assumes not all data is
-                                                   returned at once,
-                                                   not guaranteed! */
-
-    /* Read 1 buf.   20 = sizeof("data %2d 901234567890") */
-    status = serf_bucket_read_iovec(iobkt, 1 * 20, 32,
-                                    tgt_vecs, &vecs_used);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-    CuAssertIntEquals(tc, 1, vecs_used);
-    CuAssert(tc, tgt_vecs[0].iov_base,
-             strncmp("data 00 901234567890", tgt_vecs[0].iov_base, tgt_vecs[0].iov_len) == 0);
-
-    /* Read 2 bufs. */
-    status = serf_bucket_read_iovec(iobkt, 2 * 20, 32,
-                                    tgt_vecs, &vecs_used);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-    CuAssertIntEquals(tc, 2, vecs_used);
-
-    /* Read the remaining 29 bufs. */
-    vecs_used = 400;  /* test if iovec code correctly resets vecs_used */
-    status = serf_bucket_read_iovec(iobkt, SERF_READ_ALL_AVAIL, 32,
-                                    tgt_vecs, &vecs_used);
-    CuAssertIntEquals(tc, APR_EOF, status);
-    CuAssertIntEquals(tc, 29, vecs_used);
-
-    /* Test 3: use serf_bucket_read */
-    for (i = 0; i < 32 ; i++) {
-        vecs[i].iov_base = apr_psprintf(test_pool, "DATA %02d 901234567890", i);
-        vecs[i].iov_len = strlen(vecs[i].iov_base);
-    }
-
-    iobkt = serf_bucket_iovec_create(vecs, 32, alloc);
-
-    status = serf_bucket_read(iobkt, 10, &data, &len);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-    CuAssertIntEquals(tc, 10, len);
-    CuAssert(tc, data,
-             strncmp("DATA 00 90", data, len) == 0);
-
-    status = serf_bucket_read(iobkt, 10, &data, &len);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-    CuAssertIntEquals(tc, 10, len);
-    CuAssert(tc, tgt_vecs[0].iov_base,
-             strncmp("1234567890", data, len) == 0);
-
-    for (i = 1; i < 31 ; i++) {
-        const char *exp = apr_psprintf(test_pool, "DATA %02d 901234567890", i);
-        status = serf_bucket_read(iobkt, SERF_READ_ALL_AVAIL, &data, &len);
-        CuAssertIntEquals(tc, APR_SUCCESS, status);
-        CuAssertIntEquals(tc, 20, len);
-        CuAssert(tc, data,
-                 strncmp(exp, data, len) == 0);
-
-    }
-
-    status = serf_bucket_read(iobkt, 20, &data, &len);
-    CuAssertIntEquals(tc, APR_EOF, status);
-    CuAssertIntEquals(tc, 20, len);
-    CuAssert(tc, data,
-             strncmp("DATA 31 901234567890", data, len) == 0);
-
-    /* Test 3: read an empty iovec */
-    iobkt = serf_bucket_iovec_create(vecs, 0, alloc);
-    status = serf_bucket_read_iovec(iobkt, SERF_READ_ALL_AVAIL, 32,
-                                    tgt_vecs, &vecs_used);
-    CuAssertIntEquals(tc, APR_EOF, status);
-    CuAssertIntEquals(tc, 0, vecs_used);
-
-    status = serf_bucket_read(iobkt, SERF_READ_ALL_AVAIL, &data, &len);
-    CuAssertIntEquals(tc, APR_EOF, status);
-    CuAssertIntEquals(tc, 0, len);
-
-    /* Test 4: read 0 bytes from an iovec */
-    bkt = SERF_BUCKET_SIMPLE_STRING("line1" CRLF, alloc);
-    status = serf_bucket_read_iovec(bkt, SERF_READ_ALL_AVAIL, 32, vecs,
-                                    &vecs_used);
-    iobkt = serf_bucket_iovec_create(vecs, vecs_used, alloc);
-    status = serf_bucket_read_iovec(iobkt, 0, 32,
-                                    tgt_vecs, &vecs_used);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-    CuAssertIntEquals(tc, 0, vecs_used);
-}
-
-/* Construct a header bucket with some headers, and then read from it. */
-static void test_header_buckets(CuTest *tc)
-{
-    apr_status_t status;
-    apr_pool_t *test_pool = tc->testBaton;
-    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
-                                                              NULL);
-    const char *cur;
-
-    serf_bucket_t *hdrs = serf_bucket_headers_create(alloc);
-    CuAssertTrue(tc, hdrs != NULL);
-
-    serf_bucket_headers_set(hdrs, "Content-Type", "text/plain");
-    serf_bucket_headers_set(hdrs, "Content-Length", "100");
-
-    /* Note: order not guaranteed, assume here that it's fifo. */
-    cur = "Content-Type: text/plain" CRLF
-          "Content-Length: 100" CRLF
-          CRLF
-          CRLF;
-    while (1) {
-        const char *data;
-        apr_size_t len;
-
-        status = serf_bucket_read(hdrs, SERF_READ_ALL_AVAIL, &data, &len);
-        CuAssert(tc, "Unexpected error when waiting for response headers",
-                 !SERF_BUCKET_READ_ERROR(status));
-        if (SERF_BUCKET_READ_ERROR(status) ||
-            APR_STATUS_IS_EOF(status))
-            break;
-
-        /* Check that the bytes read match with expected at current position. */
-        CuAssertStrnEquals(tc, cur, len, data);
-        cur += len;
-    }
-    CuAssertIntEquals(tc, APR_EOF, status);
-}
-
-static void test_aggregate_buckets(CuTest *tc)
-{
-    apr_status_t status;
-    serf_bucket_t *bkt, *aggbkt;
-    struct iovec tgt_vecs[32];
-    int vecs_used;
-    apr_size_t len;
-    const char *data;
-
-    apr_pool_t *test_pool = tc->testBaton;
-    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
-                                                              NULL);
-    const char *BODY = "12345678901234567890"\
-                       "12345678901234567890"\
-                       "12345678901234567890"\
-                       CRLF;
-
-    /* Test 1: read 0 bytes from an aggregate */
-    aggbkt = serf_bucket_aggregate_create(alloc);
-
-    bkt = SERF_BUCKET_SIMPLE_STRING(BODY, alloc);
-    serf_bucket_aggregate_append(aggbkt, bkt);
-
-    status = serf_bucket_read_iovec(aggbkt, 0, 32,
-                                    tgt_vecs, &vecs_used);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-    CuAssertIntEquals(tc, 0, vecs_used);
-
-
-    /* Test 2: peek the available bytes, should be non-0 */
-    len = SERF_READ_ALL_AVAIL;
-    status = serf_bucket_peek(aggbkt, &data, &len);
-
-    /* status should be either APR_SUCCESS or APR_EOF */
-    if (status == APR_SUCCESS)
-        CuAssertTrue(tc, len > 0 && len < strlen(BODY));
-    else if (status == APR_EOF)
-        CuAssertIntEquals(tc, strlen(BODY), len);
-    else
-        CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    /* Test 3: read the data from the bucket. */
-    read_and_check_bucket(tc, aggbkt, BODY);
-
-    /* Test 4: multiple child buckets appended. */
-    aggbkt = serf_bucket_aggregate_create(alloc);
-
-    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY, 15, alloc);
-    serf_bucket_aggregate_append(aggbkt, bkt);
-    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY+15, strlen(BODY)-15, alloc);
-    serf_bucket_aggregate_append(aggbkt, bkt);
-
-    read_and_check_bucket(tc, aggbkt, BODY);
-
-    /* Test 5: multiple child buckets prepended. */
-    aggbkt = serf_bucket_aggregate_create(alloc);
-
-    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY+15, strlen(BODY)-15, alloc);
-    serf_bucket_aggregate_prepend(aggbkt, bkt);
-    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY, 15, alloc);
-    serf_bucket_aggregate_prepend(aggbkt, bkt);
-
-    read_and_check_bucket(tc, aggbkt, BODY);
-
-    /* Test 6: ensure peek doesn't return APR_EAGAIN, or APR_EOF incorrectly. */
-    aggbkt = serf_bucket_aggregate_create(alloc);
-
-    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY, 15, alloc);
-    serf_bucket_aggregate_append(aggbkt, bkt);
-    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY+15, strlen(BODY)-15, alloc);
-    serf_bucket_aggregate_append(aggbkt, bkt);
-
-    len = 1234;
-    status = serf_bucket_peek(aggbkt, &data, &len);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-    CuAssert(tc, "Length should be positive.",
-             len > 0 && len <= strlen(BODY) );
-    CuAssert(tc, "Data should match first part of body.",
-             strncmp(BODY, data, len) == 0);
-}
-
-static void test_aggregate_bucket_readline(CuTest *tc)
-{
-    serf_bucket_t *bkt, *aggbkt;
-    apr_pool_t *test_pool = tc->testBaton;
-
-    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
-                                                              NULL);
-    const char *BODY = "12345678901234567890" CRLF
-                       "12345678901234567890" CRLF
-                       "12345678901234567890" CRLF;
-
-    /* Test 1: read lines from an aggregate bucket */
-    aggbkt = serf_bucket_aggregate_create(alloc);
-
-    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY, 22, alloc);
-    serf_bucket_aggregate_append(aggbkt, bkt); /* 1st line */
-    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY+22, strlen(BODY)-22, alloc);
-    serf_bucket_aggregate_append(aggbkt, bkt); /* 2nd and 3rd line */
-
-    bkt = SERF_BUCKET_SIMPLE_STRING(BODY, alloc);
-    readlines_and_check_bucket(tc, aggbkt, SERF_NEWLINE_CRLF, BODY, 3);
-
-    /* Test 2: start with empty bucket */
-    aggbkt = serf_bucket_aggregate_create(alloc);
-
-    bkt = SERF_BUCKET_SIMPLE_STRING_LEN("", 0, alloc);
-    serf_bucket_aggregate_append(aggbkt, bkt); /* empty bucket */
-    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY, 22, alloc);
-    serf_bucket_aggregate_append(aggbkt, bkt); /* 1st line */
-    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY+22, strlen(BODY)-22, alloc);
-    serf_bucket_aggregate_append(aggbkt, bkt); /* 2nd and 3rd line */
-
-    bkt = SERF_BUCKET_SIMPLE_STRING(BODY, alloc);
-    readlines_and_check_bucket(tc, aggbkt, SERF_NEWLINE_CRLF, BODY, 3);
-}
-
-/* Test for issue: the server aborts the connection in the middle of
-   streaming the body of the response, where the length was set with the
-   Content-Length header. Test that we get a decent error code from the
-   response bucket instead of APR_EOF. */
-static void test_response_body_too_small_cl(CuTest *tc)
-{
-    serf_bucket_t *bkt, *tmp;
-    apr_pool_t *test_pool = tc->testBaton;
-    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
-                                                              NULL);
-
-    /* Make a response of 60 bytes, but set the Content-Length to 100. */
-#define BODY "12345678901234567890"\
-             "12345678901234567890"\
-             "12345678901234567890"
-
-    tmp = SERF_BUCKET_SIMPLE_STRING("HTTP/1.1 200 OK" CRLF
-                                    "Content-Type: text/plain" CRLF
-                                    "Content-Length: 100" CRLF
-                                    CRLF
-                                    BODY,
-                                    alloc);
-    
-    bkt = serf_bucket_response_create(tmp, alloc);
-
-    {
-        const char *data;
-        apr_size_t len;
-        apr_status_t status;
-
-        status = serf_bucket_read(bkt, SERF_READ_ALL_AVAIL, &data, &len);
-
-        CuAssert(tc, "Read more data than expected.",
-                 strlen(BODY) >= len);
-        CuAssert(tc, "Read data is not equal to expected.",
-                 strncmp(BODY, data, len) == 0);
-        CuAssert(tc, "Error expected due to response body too short!",
-                 SERF_BUCKET_READ_ERROR(status));
-        CuAssertIntEquals(tc, SERF_ERROR_TRUNCATED_HTTP_RESPONSE, status);
-    }
-}
-#undef BODY
-
-/* Test for issue: the server aborts the connection in the middle of
-   streaming the body of the response, using chunked encoding. Test that we get
-   a decent error code from the response bucket instead of APR_EOF. */
-static void test_response_body_too_small_chunked(CuTest *tc)
-{
-    serf_bucket_t *bkt, *tmp;
-    apr_pool_t *test_pool = tc->testBaton;
-    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
-                                                              NULL);
-
-    /* Make a response of 60 bytes, but set the chunk size to 60 and don't end
-       with chunk of length 0. */
-#define BODY "12345678901234567890"\
-"12345678901234567890"\
-"12345678901234567890"
-
-    tmp = SERF_BUCKET_SIMPLE_STRING("HTTP/1.1 200 OK" CRLF
-                                    "Content-Type: text/plain" CRLF
-                                    "Transfer-Encoding: chunked" CRLF
-                                    CRLF
-                                    "64" CRLF BODY,
-                                    alloc);
-
-    bkt = serf_bucket_response_create(tmp, alloc);
-
-    {
-        const char *data;
-        apr_size_t len;
-        apr_status_t status;
-
-        status = serf_bucket_read(bkt, SERF_READ_ALL_AVAIL, &data, &len);
-
-        CuAssert(tc, "Read more data than expected.",
-                 strlen(BODY) >= len);
-        CuAssert(tc, "Read data is not equal to expected.",
-                 strncmp(BODY, data, len) == 0);
-        CuAssert(tc, "Error expected due to response body too short!",
-                 SERF_BUCKET_READ_ERROR(status));
-        CuAssertIntEquals(tc, SERF_ERROR_TRUNCATED_HTTP_RESPONSE, status);
-    }
-}
-#undef BODY
-
-/* Test for issue: the server aborts the connection in the middle of
-   streaming trailing CRLF after body chunk. Test that we get
-   a decent error code from the response bucket instead of APR_EOF. */
-static void test_response_body_chunked_no_crlf(CuTest *tc)
-{
-    serf_bucket_t *bkt, *tmp;
-    apr_pool_t *test_pool = tc->testBaton;
-    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
-                                                              NULL);
-
-    tmp = SERF_BUCKET_SIMPLE_STRING("HTTP/1.1 200 OK" CRLF
-                                    "Content-Type: text/plain" CRLF
-                                    "Transfer-Encoding: chunked" CRLF
-                                    CRLF
-                                    "2" CRLF
-                                    "AB",
-                                    alloc);
-
-    bkt = serf_bucket_response_create(tmp, alloc);
-
-    {
-        char buf[1024];
-        apr_size_t len;
-        apr_status_t status;
-
-        status = read_all(bkt, buf, sizeof(buf), &len);
-
-        CuAssertIntEquals(tc, SERF_ERROR_TRUNCATED_HTTP_RESPONSE, status);
-    }
-}
-
-/* Test for issue: the server aborts the connection in the middle of
-   streaming trailing CRLF after body chunk. Test that we get
-   a decent error code from the response bucket instead of APR_EOF. */
-static void test_response_body_chunked_incomplete_crlf(CuTest *tc)
-{
-    serf_bucket_t *bkt, *tmp;
-    apr_pool_t *test_pool = tc->testBaton;
-    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
-                                                              NULL);
-
-    tmp = SERF_BUCKET_SIMPLE_STRING("HTTP/1.1 200 OK" CRLF
-                                    "Content-Type: text/plain" CRLF
-                                    "Transfer-Encoding: chunked" CRLF
-                                    CRLF
-                                    "2" CRLF
-                                    "AB"
-                                    "\r",
-                                    alloc);
-
-    bkt = serf_bucket_response_create(tmp, alloc);
-
-    {
-        char buf[1024];
-        apr_size_t len;
-        apr_status_t status;
-
-        status = read_all(bkt, buf, sizeof(buf), &len);
-
-        CuAssertIntEquals(tc, SERF_ERROR_TRUNCATED_HTTP_RESPONSE, status);
-    }
-}
-
-static void test_response_body_chunked_gzip_small(CuTest *tc)
-{
-    serf_bucket_t *bkt, *tmp;
-    apr_pool_t *test_pool = tc->testBaton;
-    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
-                                                              NULL);
-
-    tmp = SERF_BUCKET_SIMPLE_STRING("HTTP/1.1 200 OK" CRLF
-                                    "Content-Type: text/plain" CRLF
-                                    "Transfer-Encoding: chunked" CRLF
-                                    "Content-Encoding: gzip" CRLF
-                                    CRLF
-                                    "2" CRLF
-                                    "A",
-                                    alloc);
-
-    bkt = serf_bucket_response_create(tmp, alloc);
-
-    {
-        char buf[1024];
-        apr_size_t len;
-        apr_status_t status;
-
-        status = read_all(bkt, buf, sizeof(buf), &len);
-
-        CuAssertIntEquals(tc, SERF_ERROR_TRUNCATED_HTTP_RESPONSE, status);
-    }
-}
-
-static void test_response_bucket_peek_at_headers(CuTest *tc)
-{
-    apr_pool_t *test_pool = tc->testBaton;
-    serf_bucket_t *resp_bkt1, *tmp, *hdrs;
-    serf_status_line sl;
-    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
-                                                              NULL);
-    const char *hdr_val, *cur;
-    apr_status_t status;
-
-#define EXP_RESPONSE "HTTP/1.1 200 OK" CRLF\
-                     "Content-Type: text/plain" CRLF\
-                     "Content-Length: 100" CRLF\
-                     CRLF\
-                     "12345678901234567890"\
-                     "12345678901234567890"\
-                     "12345678901234567890"
-
-    tmp = SERF_BUCKET_SIMPLE_STRING(EXP_RESPONSE,
-                                    alloc);
-
-    resp_bkt1 = serf_bucket_response_create(tmp, alloc);
-
-    status = serf_bucket_response_status(resp_bkt1, &sl);
-    CuAssertIntEquals(tc, 200, sl.code);
-    CuAssertStrEquals(tc, "OK", sl.reason);
-    CuAssertIntEquals(tc, SERF_HTTP_11, sl.version);
-    
-    /* Ensure that the status line & headers are read in the response_bucket. */
-    status = serf_bucket_response_wait_for_headers(resp_bkt1);
-    CuAssert(tc, "Unexpected error when waiting for response headers",
-             !SERF_BUCKET_READ_ERROR(status));
-
-    hdrs = serf_bucket_response_get_headers(resp_bkt1);
-    CuAssertPtrNotNull(tc, hdrs);
-
-    hdr_val = serf_bucket_headers_get(hdrs, "Content-Type");
-    CuAssertStrEquals(tc, "text/plain", hdr_val);
-    hdr_val = serf_bucket_headers_get(hdrs, "Content-Length");
-    CuAssertStrEquals(tc, "100", hdr_val);
-
-    /* Create a new bucket for the response which still has the original
-       status line & headers. */
-
-    status = serf_response_full_become_aggregate(resp_bkt1);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-    cur = EXP_RESPONSE;
-
-    while (1) {
-        const char *data;
-        apr_size_t len;
-        apr_status_t status;
-
-        status = serf_bucket_read(resp_bkt1, SERF_READ_ALL_AVAIL, &data, &len);
-        CuAssert(tc, "Unexpected error when waiting for response headers",
-                 !SERF_BUCKET_READ_ERROR(status));
-        if (SERF_BUCKET_READ_ERROR(status) ||
-            APR_STATUS_IS_EOF(status))
-            break;
-
-        /* Check that the bytes read match with expected at current position. */
-        CuAssertStrnEquals(tc, cur, len, data);
-        cur += len;
-    }
-
-}
-#undef EXP_RESPONSE
-
-/* ### this test is useful, but needs to switch to the new COPY bucket
-   ### to test the behavior.  */
-#if 0
-
-/* Test that the internal function serf_default_read_iovec, used by many
-   bucket types, groups multiple buffers in one iovec. */
-static void test_serf_default_read_iovec(CuTest *tc)
-{
-    apr_status_t status;
-    serf_bucket_t *bkt, *aggbkt;
-    struct iovec tgt_vecs[32];
-    int vecs_used, i;
-    apr_size_t actual_len = 0;
-
-    apr_pool_t *test_pool = tc->testBaton;
-    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
-                                                              NULL);
-    const char *BODY = "12345678901234567890"\
-                       "12345678901234567890"\
-                       "12345678901234567890"\
-                       CRLF;
-
-    /* Test 1: multiple children, should be read in one iovec. */
-    aggbkt = serf_bucket_aggregate_create(alloc);
-
-    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY, 20, alloc);
-    serf_bucket_aggregate_append(aggbkt, bkt);
-    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY+20, 20, alloc);
-    serf_bucket_aggregate_append(aggbkt, bkt);
-    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY+40, strlen(BODY)-40, alloc);
-    serf_bucket_aggregate_append(aggbkt, bkt);
-
-    status = serf_default_read_iovec(aggbkt, SERF_READ_ALL_AVAIL, 32, tgt_vecs,
-                                     &vecs_used);
-    CuAssertIntEquals(tc, APR_EOF, status);
-    for (i = 0; i < vecs_used; i++)
-        actual_len += tgt_vecs[i].iov_len;
-    CuAssertIntEquals(tc, strlen(BODY), actual_len);
-}
-
-#endif
-
-/* Test that serf doesn't hang in an endless loop when a linebuf is in
-   split-CRLF state. */
-static void test_linebuf_crlf_split(CuTest *tc)
-{
-    serf_bucket_t *mock_bkt, *bkt;
-    apr_pool_t *test_pool = tc->testBaton;
-    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
-                                                              NULL);
-
-    mockbkt_action actions[]= {
-        { 1, "HTTP/1.1 200 OK" CRLF, APR_SUCCESS },
-        { 1, "Content-Type: text/plain" CRLF
-             "Transfer-Encoding: chunked" CRLF
-             CRLF, APR_SUCCESS },
-        { 1, "6" CR, APR_SUCCESS },
-        { 1, "", APR_EAGAIN },
-        { 1,  LF "blabla" CRLF CRLF, APR_SUCCESS }, };
-    apr_status_t status;
-
-    const char *expected = "blabla";
-
-    mock_bkt = serf_bucket_mock_create(actions, 5, alloc);
-    bkt = serf_bucket_response_create(mock_bkt, alloc);
-
-    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;
-
-        if (len == 0 && status == APR_EAGAIN)
-            serf_bucket_mock_more_data_arrived(mock_bkt);
-    } while(!APR_STATUS_IS_EOF(status));
-
-    CuAssert(tc, "Read less data than expected.", strlen(expected) == 0);
-}
-
-/* Test that serf can handle lines that don't arrive completely in one go.
-   It doesn't really run random, it tries inserting APR_EAGAIN in all possible
-   places in the response message, only one currently. */
-static void test_random_eagain_in_response(CuTest *tc)
-{
-    apr_pool_t *test_pool = tc->testBaton;
-    apr_pool_t *iter_pool;
-
-#define BODY "12345678901234567890123456789012345678901234567890"\
-             "12345678901234567890123456789012345678901234567890"
-
-    const char *expected = apr_psprintf(test_pool, "%s%s", BODY, BODY);
-    const char *fullmsg = "HTTP/1.1 200 OK" CRLF
-    "Date: Fri, 12 Jul 2013 15:13:52 GMT" CRLF
-    "Server: Apache/2.2.17 (Unix) mod_ssl/2.2.17 OpenSSL/1.0.1e DAV/2 "
-    "mod_wsgi/3.4 Python/2.7.3 SVN/1.7.10" CRLF
-    "DAV: 1,2" CRLF
-    "DAV: version-control,checkout,working-resource" CRLF
-    "DAV: merge,baseline,activity,version-controlled-collection" CRLF
-    "DAV: http://subversion.tigris.org/xmlns/dav/svn/depth" CRLF
-    "DAV: http://subversion.tigris.org/xmlns/dav/svn/log-revprops" CRLF
-    "DAV: http://subversion.tigris.org/xmlns/dav/svn/atomic-revprops" CRLF
-    "DAV: http://subversion.tigris.org/xmlns/dav/svn/partial-replay" CRLF
-    "DAV: http://subversion.tigris.org/xmlns/dav/svn/mergeinfo" CRLF
-    "DAV: <http://apache.org/dav/propset/fs/1>" CRLF
-    "MS-Author-Via: DAV" CRLF
-    "Allow: OPTIONS,GET,HEAD,POST,DELETE,TRACE,PROPFIND,PROPPATCH,COPY,MOVE,"
-    "LOCK,UNLOCK,CHECKOUT" CRLF
-    "SVN-Youngest-Rev: 1502584" CRLF
-    "SVN-Repository-UUID: 13f79535-47bb-0310-9956-ffa450edef68" CRLF
-    "SVN-Repository-Root: /repos/asf" CRLF
-    "SVN-Me-Resource: /repos/asf/!svn/me" CRLF
-    "SVN-Rev-Root-Stub: /repos/asf/!svn/rvr" CRLF
-    "SVN-Rev-Stub: /repos/asf/!svn/rev" CRLF
-    "SVN-Txn-Root-Stub: /repos/asf/!svn/txr" CRLF
-    "SVN-Txn-Stub: /repos/asf/!svn/txn" CRLF
-    "SVN-VTxn-Root-Stub: /repos/asf/!svn/vtxr" CRLF
-    "SVN-VTxn-Stub: /repos/asf/!svn/vtxn" CRLF
-    "Vary: Accept-Encoding" CRLF
-    "Content-Type: text/plain" CRLF
-    "Content-Type: text/xml; charset=\"utf-8\"" CRLF
-    "Transfer-Encoding: chunked" CRLF
-    CRLF
-    "64" CRLF
-    BODY CRLF
-    "64" CRLF
-    BODY CRLF
-    "0" CRLF
-    CRLF;
-
-    const long nr_of_tests = strlen(fullmsg);
-    long i;
-
-    mockbkt_action actions[]= {
-        { 1, NULL, APR_EAGAIN },
-        { 1, NULL, APR_EAGAIN },
-    };
-
-    apr_pool_create(&iter_pool, test_pool);
-
-    for (i = 0; i < nr_of_tests; i++) {
-        serf_bucket_t *mock_bkt, *bkt;
-        serf_bucket_alloc_t *alloc;
-        const char *ptr = expected;
-        const char *part1, *part2;
-        apr_size_t cut;
-        apr_status_t status;
-
-        apr_pool_clear(iter_pool);
-
-        alloc = serf_bucket_allocator_create(iter_pool, NULL, NULL);
-
-        cut = i % strlen(fullmsg);
-        part1 = apr_pstrndup(iter_pool, fullmsg, cut);
-        part2 = apr_pstrdup(iter_pool, fullmsg + cut);
-
-        actions[0].data = part1;
-        actions[1].data = part2;
-
-        mock_bkt = serf_bucket_mock_create(actions, 2, alloc);
-        bkt = serf_bucket_response_create(mock_bkt, alloc);
-
-        do
-        {
-            const char *data, *errmsg;
-            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));
-            errmsg = apr_psprintf(iter_pool,
-                                  "Read more data than expected, EAGAIN"
-                                  " inserted at pos: %d, remainder: \"%s\"",
-                                  cut, fullmsg + cut);
-            CuAssert(tc, errmsg, strlen(ptr) >= len);
-            errmsg = apr_psprintf(iter_pool,
-                                  "Read data is not equal to expected, EAGAIN"
-                                  " inserted at pos: %d, remainder: \"%s\"",
-                                  cut, fullmsg + cut);
-            CuAssertStrnEquals_Msg(tc, errmsg, ptr, len, data);
-
-            ptr += len;
-
-            if (len == 0 && status == APR_EAGAIN)
-                serf_bucket_mock_more_data_arrived(mock_bkt);
-        } while(!APR_STATUS_IS_EOF(status));
-
-        CuAssert(tc, "Read less data than expected.", strlen(ptr) == 0);
-    }
-    apr_pool_destroy(iter_pool);
-
-}
-
-static void test_dechunk_buckets(CuTest *tc)
-{
-    serf_bucket_t *mock_bkt, *bkt;
-    apr_pool_t *test_pool = tc->testBaton;
-    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
-                                                              NULL);
-    mockbkt_action actions[]= {
-        /* one chunk */
-        { 1, "6" CRLF "blabla" CRLF, APR_SUCCESS },
-        /* EAGAIN after first chunk */
-        { 1, "6" CRLF "blabla" CRLF, APR_EAGAIN },
-        { 1, "6" CRLF "blabla" CRLF, APR_SUCCESS },
-        /* CRLF after body split */
-        { 1, "6" CRLF "blabla" CR, APR_EAGAIN },
-        { 1,  LF, APR_SUCCESS },
-        /* CRLF before body split */
-        { 1, "6" CR, APR_SUCCESS },
-        { 1, "", APR_EAGAIN },
-        { 1,  LF "blabla" CRLF, APR_SUCCESS },
-        /* empty chunk */
-        { 1, "", APR_SUCCESS },
-        /* two chunks */
-        { 1, "6" CRLF "blabla" CRLF "6" CRLF "blabla" CRLF, APR_SUCCESS },
-        /* three chunks */
-        { 1, "6" CRLF "blabla" CRLF "6" CRLF "blabla" CRLF
-             "0" CRLF "" CRLF, APR_SUCCESS },
-    };
-    const int nr_of_actions = sizeof(actions) / sizeof(mockbkt_action);
-    apr_status_t status;
-    const char *body = "blabla";
-    const char *expected = apr_psprintf(test_pool, "%s%s%s%s%s%s%s%s%s", body,
-                                        body, body, body, body, body, body,
-                                        body, body);
-
-    mock_bkt = serf_bucket_mock_create(actions, nr_of_actions, alloc);
-    bkt = serf_bucket_dechunk_create(mock_bkt, alloc);
-
-    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;
-
-        if (len == 0 && status == APR_EAGAIN)
-            serf_bucket_mock_more_data_arrived(mock_bkt);
-    } while(!APR_STATUS_IS_EOF(status));
-
-    CuAssert(tc, "Read less data than expected.", strlen(expected) == 0);
-}
-
-/* Test that the Content-Length header will be ignored when the response
-   should not have returned a body. See RFC2616, section 4.4, nbr. 1. */
-static void test_response_no_body_expected(CuTest *tc)
-{
-    serf_bucket_t *bkt, *tmp;
-    apr_pool_t *test_pool = tc->testBaton;
-    char buf[1024];
-    apr_size_t len;
-    serf_bucket_alloc_t *alloc;
-    int i;
-    apr_status_t status;
-
-    /* response bucket should consider the blablablablabla as start of the
-       next response, in all these cases it should APR_EOF after the empty
-       line. */
-    test_server_message_t message_list[] = {
-        { "HTTP/1.1 100 Continue" CRLF
-          "Content-Type: text/plain" CRLF
-          "Content-Length: 6500000" CRLF
-          CRLF
-          "blablablablabla" CRLF },
-        { "HTTP/1.1 204 No Content" CRLF
-            "Content-Type: text/plain" CRLF
-            "Content-Length: 6500000" CRLF
-            CRLF
-            "blablablablabla" CRLF },
-        { "HTTP/1.1 304 Not Modified" CRLF
-            "Content-Type: text/plain" CRLF
-            "Content-Length: 6500000" CRLF
-            CRLF
-            "blablablablabla" CRLF },
-    };
-
-    alloc = serf_bucket_allocator_create(test_pool, NULL, NULL);
-
-    /* Test 1: a response to a HEAD request. */
-    tmp = SERF_BUCKET_SIMPLE_STRING("HTTP/1.1 200 OK" CRLF
-                                    "Content-Type: text/plain" CRLF
-                                    "Content-Length: 6500000" CRLF
-                                    CRLF
-                                    "blablablablabla" CRLF,
-                                    alloc);
-
-    bkt = serf_bucket_response_create(tmp, alloc);
-    serf_bucket_response_set_head(bkt);
-
-    status = read_all(bkt, buf, sizeof(buf), &len);
-
-    CuAssertIntEquals(tc, APR_EOF, status);
-    CuAssertIntEquals(tc, 0, len);
-
-    /* Test 2: a response with status for which server must not send a body. */
-    for (i = 0; i < sizeof(message_list) / sizeof(test_server_message_t); i++) {
-
-        tmp = SERF_BUCKET_SIMPLE_STRING(message_list[i].text, alloc);
-        bkt = serf_bucket_response_create(tmp, alloc);
-
-        status = read_all(bkt, buf, sizeof(buf), &len);
-
-        CuAssertIntEquals(tc, APR_EOF, status);
-        CuAssertIntEquals(tc, 0, len);
-    }
-}
-
-static apr_status_t deflate_compress(const char **data, apr_size_t *len,
-                                     z_stream *zdestr,
-                                     const char *orig, apr_size_t orig_len,
-                                     int last,
-                                     apr_pool_t *pool)
-{
-    int zerr;
-    apr_size_t buf_size;
-    void *write_buf;
-
-    /* The largest buffer we should need is 0.1% larger than the
-       uncompressed data, + 12 bytes. This info comes from zlib.h.
-       Note: This isn't sufficient when using Z_NO_FLUSH and extremely compressed
-       data. Use a buffer bigger than what we need. */
-//    buf_size = orig_len + (orig_len / 1000) + 12;
-    buf_size = 100000;
-
-    write_buf = apr_palloc(pool, buf_size);
-
-    zdestr->next_in = (Bytef *)orig;  /* Casting away const! */
-    zdestr->avail_in = (uInt)orig_len;
-
-    zerr = Z_OK;
-    zdestr->next_out = write_buf;
-    zdestr->avail_out = (uInt)buf_size;
-
-    while ((last && zerr != Z_STREAM_END) ||
-           (!last && zdestr->avail_in > 0))
-    {
-        zerr = deflate(zdestr, last ? Z_FINISH : Z_NO_FLUSH);
-        if (zerr < 0)
-            return APR_EGENERAL;
-    }
-
-    *data = write_buf;
-    *len = buf_size - zdestr->avail_out;
-    
-    return APR_SUCCESS;
-}
-
-/* Reads bucket until EOF found and compares read data with zero terminated
- string expected. Report all failures using CuTest. */
-static void read_bucket_and_check_pattern(CuTest *tc, serf_bucket_t *bkt,
-                                          const char *pattern,
-                                          apr_size_t expected_len)
-{
-    apr_status_t status;
-    const char *expected;
-    const apr_size_t pattern_len = strlen(pattern);
-
-    apr_size_t exp_rem = 0;
-    apr_size_t actual_len = 0;
-
-    do
-    {
-        const char *data;
-        apr_size_t act_rem;
-
-        status = serf_bucket_read(bkt, SERF_READ_ALL_AVAIL, &data, &act_rem);
-
-        CuAssert(tc, "Got error during bucket reading.",
-                 !SERF_BUCKET_READ_ERROR(status));
-
-        actual_len += act_rem;
-
-        while (act_rem > 0) {
-            apr_size_t bytes_to_compare;
-
-            if (exp_rem == 0) {
-                expected = pattern;
-                exp_rem = pattern_len;
-            }
-
-            bytes_to_compare = act_rem < exp_rem ? act_rem : exp_rem;
-            CuAssert(tc, "Read data is not equal to expected.",
-                     strncmp(expected, data, bytes_to_compare) == 0);
-            data += bytes_to_compare;
-            act_rem -= bytes_to_compare;
-
-            expected += bytes_to_compare;
-            exp_rem -= bytes_to_compare;
-        }
-    } while(!APR_STATUS_IS_EOF(status));
-
-    CuAssertIntEquals_Msg(tc, "Read less data than expected.", 0, exp_rem);
-    CuAssertIntEquals_Msg(tc, "Read less/more data than expected.", actual_len,
-                          expected_len);
-}
-
-static void deflate_buckets(CuTest *tc, int nr_of_loops)
-{
-    const char *msg = "12345678901234567890123456789012345678901234567890";
-
-    test_baton_t *tb = tc->testBaton;
-    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(tb->pool, NULL,
-                                                              NULL);
-    z_stream zdestr;
-    int i;
-    const char gzip_header[10] =
-    { '\037', '\213', Z_DEFLATED, 0,
-        0, 0, 0, 0, /* mtime */
-        0, 0x03 /* Unix OS_CODE */
-    };
-
-    serf_bucket_t *aggbkt = serf_bucket_aggregate_create(alloc);
-    serf_bucket_t *defbkt = serf_bucket_deflate_create(aggbkt, alloc,
-                                                       SERF_DEFLATE_GZIP);
-    serf_bucket_t *strbkt;
-
-#if 0 /* Enable logging */
-    {
-        serf_config_t *config;
-
-        serf_context_t *ctx = serf_context_create(tb->pool);
-        /* status = */ serf__config_store_get_config(ctx, NULL, &config, tb->pool);
-
-        serf_bucket_set_config(defbkt, config);
-    }
-#endif
-
-    memset(&zdestr, 0, sizeof(z_stream));
-    /* HTTP uses raw deflate format, so windows size => -15 */
-    CuAssert(tc, "zlib init failed.",
-             deflateInit2(&zdestr, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8,
-                          Z_DEFAULT_STRATEGY) == Z_OK);
-
-    strbkt = SERF_BUCKET_SIMPLE_STRING_LEN(gzip_header, 10, alloc);
-    serf_bucket_aggregate_append(aggbkt, strbkt);
-
-    for (i = 0; i < nr_of_loops; i++) {
-        const char *data;
-        apr_size_t len;
-
-        if (i == nr_of_loops - 1) {
-            CuAssertIntEquals(tc, APR_SUCCESS,
-                              deflate_compress(&data, &len, &zdestr, msg,
-                                               strlen(msg), 1, tb->pool));
-        } else {
-            CuAssertIntEquals(tc, APR_SUCCESS,
-                              deflate_compress(&data, &len, &zdestr, msg,
-                                               strlen(msg), 0, tb->pool));
-        }
-
-        if (len == 0)
-            continue;
-
-        strbkt = SERF_BUCKET_SIMPLE_STRING_LEN(data, len, alloc);
-
-        serf_bucket_aggregate_append(aggbkt, strbkt);
-    }
-
-    tb->user_baton_l = APR_EOF;
-    read_bucket_and_check_pattern(tc, defbkt, msg, nr_of_loops * strlen(msg));
-}
-
-static void test_deflate_buckets(CuTest *tc)
-{
-    int i;
-
-    for (i = 1; i < 1000; i++) {
-        deflate_buckets(tc, i);
-    }
-}
-
-static apr_status_t discard_data(serf_bucket_t *bkt,
-                                 apr_size_t *read_len)
-{
-    const char *data;
-    apr_size_t data_len;
-    apr_status_t status;
-    apr_size_t read;
-
-    read = 0;
-
-    do
-    {
-        status = serf_bucket_read(bkt, SERF_READ_ALL_AVAIL, &data, &data_len);
-
-        if (!SERF_BUCKET_READ_ERROR(status)) {
-            read += data_len;
-        }
-    } while(status == APR_SUCCESS);
-
-    *read_len = read;
-    return status;
-}
-
-static apr_status_t hold_open(void *baton, serf_bucket_t *aggbkt)
-{
-    test_baton_t *tb = baton;
-
-    return tb->user_baton_l;
-}
-
-static void put_32bit(unsigned char *buf, unsigned long x)
-{
-    buf[0] = (unsigned char)(x & 0xFF);
-    buf[1] = (unsigned char)((x & 0xFF00) >> 8);
-    buf[2] = (unsigned char)((x & 0xFF0000) >> 16);
-    buf[3] = (unsigned char)((x & 0xFF000000) >> 24);
-}
-
-static serf_bucket_t *
-create_gzip_deflate_bucket(serf_bucket_t *stream, z_stream *outzstr,
-                           serf_bucket_alloc_t *alloc)
-{
-    serf_bucket_t *strbkt;
-    serf_bucket_t *defbkt = serf_bucket_deflate_create(stream, alloc,
-                                                       SERF_DEFLATE_GZIP);
-    int zerr;
-
-    memset(outzstr, 0, sizeof(z_stream));
-
-    const char gzip_header[10] =
-    { '\037', '\213', Z_DEFLATED, 0,
-        0, 0, 0, 0, /* mtime */
-        0, 0x03 /* Unix OS_CODE */
-    };
-
-    /* HTTP uses raw deflate format, so windows size => -15 */
-    zerr = deflateInit2(outzstr, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8,
-                            Z_DEFAULT_STRATEGY);
-    if (zerr != Z_OK)
-        return NULL;
-
-    strbkt = SERF_BUCKET_SIMPLE_STRING_LEN(gzip_header, 10, alloc);
-    serf_bucket_aggregate_append(stream, strbkt);
-
-    return defbkt;
-}
-
-/* Test for issue #152: the trailers of gzipped data only store the 4 most 
-   significant bytes of the length, so when the compressed data is >4GB
-   we can't just compare actual length with expected length. */
-static void test_deflate_4GBplus_buckets(CuTest *tc)
-{
-    test_baton_t *tb = tc->testBaton;
-    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(tb->pool, NULL,
-                                                              NULL);
-    int i;
-    unsigned char gzip_trailer[8];
-    z_stream zdestr;
-    serf_bucket_t *aggbkt = serf_bucket_aggregate_create(alloc);
-    serf_bucket_t *defbkt = create_gzip_deflate_bucket(aggbkt, &zdestr, alloc);
-    serf_bucket_t *strbkt;
-    apr_pool_t *iter_pool;
-    apr_size_t actual_size;
-    unsigned long unc_crc = 0;
-    unsigned long unc_length = 0;
-
-#define NR_OF_LOOPS 550000
-#define BUFSIZE 8096
-    unsigned char uncompressed[BUFSIZE];
-
-    serf_bucket_aggregate_hold_open(aggbkt, hold_open, tb);
-    tb->user_baton_l = APR_EAGAIN;
-
-
-#if 0 /* Enable logging */
-    {
-        serf_config_t *config;
-
-        serf_context_t *ctx = serf_context_create(tb->pool);
-        /* status = */ serf__config_store_get_config(ctx, NULL, &config, tb->pool);
-
-        serf_bucket_set_config(defbkt, config);
-    }
-#endif
-
-    apr_pool_create(&iter_pool, tb->pool);
-
-    actual_size = 0;
-    for (i = 0; i < NR_OF_LOOPS; i++) {
-        const char *data;
-        apr_size_t len;
-        apr_size_t read_len;
-        serf_bucket_alloc_t *iter_alloc;
-        apr_status_t status;
-
-        apr_pool_clear(iter_pool);
-        iter_alloc = serf_bucket_allocator_create(iter_pool, NULL, NULL);
-
-
-        if (i % 1000 == 0)
-            printf("%d\n", i);
-
-        status = apr_generate_random_bytes(uncompressed, BUFSIZE);
-        CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-        unc_crc = crc32(unc_crc, (const Bytef *)uncompressed, BUFSIZE);
-        unc_length += BUFSIZE;
-
-        if (i == NR_OF_LOOPS - 1) {
-            CuAssertIntEquals(tc, APR_SUCCESS,
-                              deflate_compress(&data, &len, &zdestr,
-                                               (const char *)uncompressed,
-                                               BUFSIZE, 1, iter_pool));
-        } else {
-            CuAssertIntEquals(tc, APR_SUCCESS,
-                              deflate_compress(&data, &len, &zdestr,
-                                               (const char *)uncompressed,
-                                               BUFSIZE, 0, iter_pool));
-        }
-
-        if (len == 0)
-            continue;
-
-        strbkt = serf_bucket_simple_copy_create(data, len, iter_alloc);
-        serf_bucket_aggregate_append(aggbkt, strbkt);
-
-        /* Start reading inflated data */
-        status = discard_data(defbkt, &read_len);
-        CuAssert(tc, "Got error during discarding of compressed data.",
-                 !SERF_BUCKET_READ_ERROR(status));
-
-        actual_size += read_len;
-    }
-
-    put_32bit(&gzip_trailer[0], unc_crc);
-    put_32bit(&gzip_trailer[4], unc_length);
-    strbkt = SERF_BUCKET_SIMPLE_STRING_LEN((const char *)gzip_trailer,
-                                           sizeof(gzip_trailer), alloc);
-    serf_bucket_aggregate_append(aggbkt, strbkt);
-
-    tb->user_baton_l = APR_EOF;
-
-    while (1) {
-        apr_size_t read_len;
-        apr_status_t status = discard_data(defbkt, &read_len);
-        CuAssert(tc, "Got error during discarding of compressed data.",
-                 !SERF_BUCKET_READ_ERROR(status));
-        actual_size += read_len;
-        if (status == APR_EOF)
-            break;
-    }
-
-    CuAssertIntEquals(tc, NR_OF_LOOPS * BUFSIZE, actual_size);
-#undef NR_OF_LOOPS
-#undef BUFSIZE
-}
-
-CuSuite *test_buckets(void)
-{
-    CuSuite *suite = CuSuiteNew();
-
-    CuSuiteSetSetupTeardownCallbacks(suite, test_setup, test_teardown);
-
-    SUITE_ADD_TEST(suite, test_simple_bucket_readline);
-    SUITE_ADD_TEST(suite, test_response_bucket_read);
-    SUITE_ADD_TEST(suite, test_response_bucket_headers);
-    SUITE_ADD_TEST(suite, test_response_bucket_chunked_read);
-    SUITE_ADD_TEST(suite, test_response_body_too_small_cl);
-    SUITE_ADD_TEST(suite, test_response_body_too_small_chunked);
-    SUITE_ADD_TEST(suite, test_response_body_chunked_no_crlf);
-    SUITE_ADD_TEST(suite, test_response_body_chunked_incomplete_crlf);
-    SUITE_ADD_TEST(suite, test_response_body_chunked_gzip_small);
-    SUITE_ADD_TEST(suite, test_response_bucket_peek_at_headers);
-    SUITE_ADD_TEST(suite, test_bucket_header_set);
-    SUITE_ADD_TEST(suite, test_iovec_buckets);
-    SUITE_ADD_TEST(suite, test_aggregate_buckets);
-    SUITE_ADD_TEST(suite, test_aggregate_bucket_readline);
-    SUITE_ADD_TEST(suite, test_header_buckets);
-    SUITE_ADD_TEST(suite, test_linebuf_crlf_split);
-    SUITE_ADD_TEST(suite, test_random_eagain_in_response);
-    SUITE_ADD_TEST(suite, test_dechunk_buckets);
-    SUITE_ADD_TEST(suite, test_response_no_body_expected);
-    SUITE_ADD_TEST(suite, test_deflate_buckets);
-#if 0
-    /* This test for issue #152 takes a lot of time generating 4GB+ of random
-       data so it's disabled by default. */
-    SUITE_ADD_TEST(suite, test_deflate_4GBplus_buckets);
-#endif
-
-#if 0
-    SUITE_ADD_TEST(suite, test_serf_default_read_iovec);
-#endif
-
-    return suite;
-}

Copied: vendor/serf/1.3.9/test/test_buckets.c (from rev 9259, vendor/serf/dist/test/test_buckets.c)
===================================================================
--- vendor/serf/1.3.9/test/test_buckets.c	                        (rev 0)
+++ vendor/serf/1.3.9/test/test_buckets.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,1640 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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 <apr_random.h>
+#include <zlib.h>
+
+#include "serf.h"
+#include "test_serf.h"
+
+/* test case has access to internal functions. */
+#include "serf_private.h"
+#include "serf_bucket_util.h"
+
+static apr_status_t read_all(serf_bucket_t *bkt,
+                             char *buf,
+                             apr_size_t buf_len,
+                             apr_size_t *read_len)
+{
+    const char *data;
+    apr_size_t data_len;
+    apr_status_t status;
+    apr_size_t read;
+
+    read = 0;
+
+    do
+    {
+        status = serf_bucket_read(bkt, SERF_READ_ALL_AVAIL, &data, &data_len);
+
+        if (!SERF_BUCKET_READ_ERROR(status))
+        {
+            if (data_len > buf_len - read)
+            {
+                /* Buffer is not large enough to read all data */
+                data_len = buf_len - read;
+                status = SERF_ERROR_ISSUE_IN_TESTSUITE;
+            }
+            memcpy(buf + read, data, data_len);
+            read += data_len;
+        }
+    } while(status == APR_SUCCESS);
+
+    *read_len = read;
+    return status;
+}
+
+/* Reads bucket until EOF found and compares read data with zero terminated
+   string expected. Report all failures using CuTest. */
+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);
+}
+
+/* Reads bucket with serf_bucket_readline until EOF found and compares:
+   - actual line endings with expected line endings
+   - actual data with zero terminated string expected.
+   Reports all failures using CuTest. */
+void readlines_and_check_bucket(CuTest *tc, serf_bucket_t *bkt,
+                                int acceptable,
+                                const char *expected,
+                                int expected_nr_of_lines)
+{
+    apr_status_t status;
+    int actual_nr_of_lines = 0;
+
+    do
+    {
+        const char *data;
+        apr_size_t len;
+        int found;
+
+        status = serf_bucket_readline(bkt, acceptable, &found,
+                                      &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;
+
+        if (found == SERF_NEWLINE_CRLF_SPLIT)
+            continue;
+
+        if (found != SERF_NEWLINE_NONE)
+        {
+            actual_nr_of_lines++;
+
+            CuAssert(tc, "Unexpected line ending type!",
+                     found & acceptable);
+            if (found & SERF_NEWLINE_CR)
+                CuAssert(tc, "CR Line ending was reported but not in data!",
+                         strncmp(data + len - 1, "\r", 1) == 0);
+            if (found & SERF_NEWLINE_LF)
+                CuAssert(tc, "LF Line ending was reported but not in data!",
+                         strncmp(data + len - 1, "\n", 1) == 0);
+            if (found & SERF_NEWLINE_CRLF)
+                CuAssert(tc, "CRLF Line ending was reported but not in data!",
+                         strncmp(data + len - 2, "\r\n", 2) == 0);
+        } else
+        {
+            if (status == APR_EOF && len)
+                actual_nr_of_lines++;
+
+            if (acceptable & SERF_NEWLINE_CR)
+                CuAssert(tc, "CR Line ending was not reported but in data!",
+                         strncmp(data + len - 1, "\r", 1) != 0);
+            if (acceptable & SERF_NEWLINE_LF)
+                CuAssert(tc, "LF Line ending was not reported but in data!",
+                         strncmp(data + len - 1, "\n", 1) != 0);
+            if (acceptable & SERF_NEWLINE_CRLF)
+                CuAssert(tc, "CRLF Line ending was not reported but in data!",
+                         strncmp(data + len - 2, "\r\n", 2) != 0);
+        }
+    } while(!APR_STATUS_IS_EOF(status));
+
+    CuAssertIntEquals(tc, expected_nr_of_lines, actual_nr_of_lines);
+    CuAssert(tc, "Read less data than expected.", strlen(expected) == 0);
+}
+
+
+/******************************** TEST CASES **********************************/
+
+static void test_simple_bucket_readline(CuTest *tc)
+{
+    apr_status_t status;
+    serf_bucket_t *bkt;
+    const char *data;
+    int found;
+    apr_size_t len;
+    const char *body;
+    
+    apr_pool_t *test_pool = tc->testBaton;
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+                                                              NULL);
+
+    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);
+
+    /* acceptable line types should be reported */
+    bkt = SERF_BUCKET_SIMPLE_STRING("line1" CRLF, alloc);
+    readlines_and_check_bucket(tc, bkt, SERF_NEWLINE_CRLF, "line1" CRLF, 1);
+    bkt = SERF_BUCKET_SIMPLE_STRING("line1" LF, alloc);
+    readlines_and_check_bucket(tc, bkt, SERF_NEWLINE_LF, "line1" LF, 1);
+    bkt = SERF_BUCKET_SIMPLE_STRING("line1" LF, alloc);
+    readlines_and_check_bucket(tc, bkt, SERF_NEWLINE_LF, "line1" LF, 1);
+    /* special cases, but acceptable */
+    bkt = SERF_BUCKET_SIMPLE_STRING("line1" CRLF, alloc);
+    readlines_and_check_bucket(tc, bkt, SERF_NEWLINE_CR, "line1" CRLF, 2);
+    bkt = SERF_BUCKET_SIMPLE_STRING("line1" CRLF, alloc);
+    readlines_and_check_bucket(tc, bkt, SERF_NEWLINE_LF, "line1" CRLF, 1);
+
+    /* Unacceptable line types should not be reported */
+    bkt = SERF_BUCKET_SIMPLE_STRING("line1" LF, alloc);
+    readlines_and_check_bucket(tc, bkt, SERF_NEWLINE_CR, "line1" LF, 1);
+    bkt = SERF_BUCKET_SIMPLE_STRING("line1" LF, alloc);
+    readlines_and_check_bucket(tc, bkt, SERF_NEWLINE_CRLF, "line1" LF, 1);
+    bkt = SERF_BUCKET_SIMPLE_STRING("line1" CR, alloc);
+    readlines_and_check_bucket(tc, bkt, SERF_NEWLINE_LF, "line1" CR, 1);
+#if 0
+    /* TODO: looks like a bug, CRLF acceptable on buffer with CR returns
+       SERF_NEWLINE_CRLF_SPLIT, but here that CR comes at the end of the 
+       buffer (APR_EOF), so should have been SERF_NEWLINE_NONE! */
+    bkt = SERF_BUCKET_SIMPLE_STRING("line1" CR, alloc);
+    readlines_and_check_bucket(tc, bkt, SERF_NEWLINE_CRLF, "line1" CR, 1);
+#endif
+
+    body = "12345678901234567890" CRLF
+           "12345678901234567890" CRLF
+           "12345678901234567890" CRLF;
+    bkt = SERF_BUCKET_SIMPLE_STRING(body, alloc);
+    readlines_and_check_bucket(tc, bkt, SERF_NEWLINE_LF, body, 3);
+}
+
+static void test_response_bucket_read(CuTest *tc)
+{
+    serf_bucket_t *bkt, *tmp;
+
+    apr_pool_t *test_pool = tc->testBaton;
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+                                                              NULL);
+
+    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_headers(CuTest *tc)
+{
+    serf_bucket_t *bkt, *tmp, *hdr;
+
+    apr_pool_t *test_pool = tc->testBaton;
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+                                                              NULL);
+
+    tmp = SERF_BUCKET_SIMPLE_STRING(
+        "HTTP/1.1 405 Method Not Allowed" CRLF
+        "Date: Sat, 12 Jun 2010 14:17:10 GMT"  CRLF
+        "Server: Apache"  CRLF
+        "Allow: "  CRLF
+        "Content-Length: 7"  CRLF
+        "Content-Type: text/html; charset=iso-8859-1" CRLF
+        "NoSpace:" 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");
+
+    hdr = serf_bucket_response_get_headers(bkt);
+    CuAssertStrEquals(tc,
+        "",
+        serf_bucket_headers_get(hdr, "Allow"));
+    CuAssertStrEquals(tc,
+        "7",
+        serf_bucket_headers_get(hdr, "Content-Length"));
+    CuAssertStrEquals(tc,
+        "",
+        serf_bucket_headers_get(hdr, "NoSpace"));
+}
+
+static void test_response_bucket_chunked_read(CuTest *tc)
+{
+    serf_bucket_t *bkt, *tmp, *hdrs;
+
+    apr_pool_t *test_pool = tc->testBaton;
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+                                                              NULL);
+
+    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)
+{
+    apr_pool_t *test_pool = tc->testBaton;
+    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"));
+
+    serf_bucket_headers_set(hdrs, "Foo", "test");
+
+    CuAssertStrEquals(tc, "bar,baz,test", serf_bucket_headers_get(hdrs, "Foo"));
+
+    /* headers are case insensitive. */
+    CuAssertStrEquals(tc, "bar,baz,test", serf_bucket_headers_get(hdrs, "fOo"));
+}
+
+
+static void test_iovec_buckets(CuTest *tc)
+{
+    apr_status_t status;
+    serf_bucket_t *bkt, *iobkt;
+    const char *data;
+    apr_size_t len;
+    struct iovec vecs[32];
+    struct iovec tgt_vecs[32];
+    int i;
+    int vecs_used;
+
+    apr_pool_t *test_pool = tc->testBaton;
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+                                                              NULL);
+
+    /* Test 1: Read a single string in an iovec, store it in a iovec_bucket
+       and then read it back. */
+    bkt = SERF_BUCKET_SIMPLE_STRING(
+        "line1" CRLF
+        "line2",
+        alloc);
+
+    status = serf_bucket_read_iovec(bkt, SERF_READ_ALL_AVAIL, 32, vecs,
+                                    &vecs_used);
+
+    iobkt = serf_bucket_iovec_create(vecs, vecs_used, alloc);
+
+    /* Check available data */
+    status = serf_bucket_peek(iobkt, &data, &len);
+    CuAssertIntEquals(tc, APR_EOF, status);
+    CuAssertIntEquals(tc, strlen("line1" CRLF "line2"), len);
+
+    /* Try to read only a few bytes (less than what's in the first buffer). */
+    status = serf_bucket_read_iovec(iobkt, 3, 32, tgt_vecs, &vecs_used);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    CuAssertIntEquals(tc, 1, vecs_used);
+    CuAssertIntEquals(tc, 3, tgt_vecs[0].iov_len);
+    CuAssert(tc, tgt_vecs[0].iov_base,
+             strncmp("lin", tgt_vecs[0].iov_base, tgt_vecs[0].iov_len) == 0);
+
+    /* Read the rest of the data. */
+    status = serf_bucket_read_iovec(iobkt, SERF_READ_ALL_AVAIL, 32, tgt_vecs,
+                                    &vecs_used);
+    CuAssertIntEquals(tc, APR_EOF, status);
+    CuAssertIntEquals(tc, 1, vecs_used);
+    CuAssertIntEquals(tc, strlen("e1" CRLF "line2"), tgt_vecs[0].iov_len);
+    CuAssert(tc, tgt_vecs[0].iov_base,
+             strncmp("e1" CRLF "line2", tgt_vecs[0].iov_base, tgt_vecs[0].iov_len - 3) == 0);
+
+    /* Bucket should now be empty */
+    status = serf_bucket_peek(iobkt, &data, &len);
+    CuAssertIntEquals(tc, APR_EOF, status);
+    CuAssertIntEquals(tc, 0, len);
+
+    /* Test 2: Read multiple character bufs in an iovec, then read them back
+       in bursts. */
+    for (i = 0; i < 32 ; i++) {
+        vecs[i].iov_base = apr_psprintf(test_pool, "data %02d 901234567890", i);
+        vecs[i].iov_len = strlen(vecs[i].iov_base);
+    }
+
+    iobkt = serf_bucket_iovec_create(vecs, 32, alloc);
+
+    /* Check that some data is in the buffer. Don't verify the actual data, the
+       amount of data returned is not guaranteed to be the full buffer. */
+    status = serf_bucket_peek(iobkt, &data, &len);
+    CuAssertTrue(tc, len > 0);
+    CuAssertIntEquals(tc, APR_SUCCESS, status); /* this assumes not all data is
+                                                   returned at once,
+                                                   not guaranteed! */
+
+    /* Read 1 buf.   20 = sizeof("data %2d 901234567890") */
+    status = serf_bucket_read_iovec(iobkt, 1 * 20, 32,
+                                    tgt_vecs, &vecs_used);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    CuAssertIntEquals(tc, 1, vecs_used);
+    CuAssert(tc, tgt_vecs[0].iov_base,
+             strncmp("data 00 901234567890", tgt_vecs[0].iov_base, tgt_vecs[0].iov_len) == 0);
+
+    /* Read 2 bufs. */
+    status = serf_bucket_read_iovec(iobkt, 2 * 20, 32,
+                                    tgt_vecs, &vecs_used);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    CuAssertIntEquals(tc, 2, vecs_used);
+
+    /* Read the remaining 29 bufs. */
+    vecs_used = 400;  /* test if iovec code correctly resets vecs_used */
+    status = serf_bucket_read_iovec(iobkt, SERF_READ_ALL_AVAIL, 32,
+                                    tgt_vecs, &vecs_used);
+    CuAssertIntEquals(tc, APR_EOF, status);
+    CuAssertIntEquals(tc, 29, vecs_used);
+
+    /* Test 3: use serf_bucket_read */
+    for (i = 0; i < 32 ; i++) {
+        vecs[i].iov_base = apr_psprintf(test_pool, "DATA %02d 901234567890", i);
+        vecs[i].iov_len = strlen(vecs[i].iov_base);
+    }
+
+    iobkt = serf_bucket_iovec_create(vecs, 32, alloc);
+
+    status = serf_bucket_read(iobkt, 10, &data, &len);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    CuAssertIntEquals(tc, 10, len);
+    CuAssert(tc, data,
+             strncmp("DATA 00 90", data, len) == 0);
+
+    status = serf_bucket_read(iobkt, 10, &data, &len);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    CuAssertIntEquals(tc, 10, len);
+    CuAssert(tc, tgt_vecs[0].iov_base,
+             strncmp("1234567890", data, len) == 0);
+
+    for (i = 1; i < 31 ; i++) {
+        const char *exp = apr_psprintf(test_pool, "DATA %02d 901234567890", i);
+        status = serf_bucket_read(iobkt, SERF_READ_ALL_AVAIL, &data, &len);
+        CuAssertIntEquals(tc, APR_SUCCESS, status);
+        CuAssertIntEquals(tc, 20, len);
+        CuAssert(tc, data,
+                 strncmp(exp, data, len) == 0);
+
+    }
+
+    status = serf_bucket_read(iobkt, 20, &data, &len);
+    CuAssertIntEquals(tc, APR_EOF, status);
+    CuAssertIntEquals(tc, 20, len);
+    CuAssert(tc, data,
+             strncmp("DATA 31 901234567890", data, len) == 0);
+
+    /* Test 3: read an empty iovec */
+    iobkt = serf_bucket_iovec_create(vecs, 0, alloc);
+    status = serf_bucket_read_iovec(iobkt, SERF_READ_ALL_AVAIL, 32,
+                                    tgt_vecs, &vecs_used);
+    CuAssertIntEquals(tc, APR_EOF, status);
+    CuAssertIntEquals(tc, 0, vecs_used);
+
+    status = serf_bucket_read(iobkt, SERF_READ_ALL_AVAIL, &data, &len);
+    CuAssertIntEquals(tc, APR_EOF, status);
+    CuAssertIntEquals(tc, 0, len);
+
+    /* Test 4: read 0 bytes from an iovec */
+    bkt = SERF_BUCKET_SIMPLE_STRING("line1" CRLF, alloc);
+    status = serf_bucket_read_iovec(bkt, SERF_READ_ALL_AVAIL, 32, vecs,
+                                    &vecs_used);
+    iobkt = serf_bucket_iovec_create(vecs, vecs_used, alloc);
+    status = serf_bucket_read_iovec(iobkt, 0, 32,
+                                    tgt_vecs, &vecs_used);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    CuAssertIntEquals(tc, 0, vecs_used);
+}
+
+/* Construct a header bucket with some headers, and then read from it. */
+static void test_header_buckets(CuTest *tc)
+{
+    apr_status_t status;
+    apr_pool_t *test_pool = tc->testBaton;
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+                                                              NULL);
+    const char *cur;
+
+    serf_bucket_t *hdrs = serf_bucket_headers_create(alloc);
+    CuAssertTrue(tc, hdrs != NULL);
+
+    serf_bucket_headers_set(hdrs, "Content-Type", "text/plain");
+    serf_bucket_headers_set(hdrs, "Content-Length", "100");
+
+    /* Note: order not guaranteed, assume here that it's fifo. */
+    cur = "Content-Type: text/plain" CRLF
+          "Content-Length: 100" CRLF
+          CRLF
+          CRLF;
+    while (1) {
+        const char *data;
+        apr_size_t len;
+
+        status = serf_bucket_read(hdrs, SERF_READ_ALL_AVAIL, &data, &len);
+        CuAssert(tc, "Unexpected error when waiting for response headers",
+                 !SERF_BUCKET_READ_ERROR(status));
+        if (SERF_BUCKET_READ_ERROR(status) ||
+            APR_STATUS_IS_EOF(status))
+            break;
+
+        /* Check that the bytes read match with expected at current position. */
+        CuAssertStrnEquals(tc, cur, len, data);
+        cur += len;
+    }
+    CuAssertIntEquals(tc, APR_EOF, status);
+}
+
+static void test_aggregate_buckets(CuTest *tc)
+{
+    apr_status_t status;
+    serf_bucket_t *bkt, *aggbkt;
+    struct iovec tgt_vecs[32];
+    int vecs_used;
+    apr_size_t len;
+    const char *data;
+
+    apr_pool_t *test_pool = tc->testBaton;
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+                                                              NULL);
+    const char *BODY = "12345678901234567890"\
+                       "12345678901234567890"\
+                       "12345678901234567890"\
+                       CRLF;
+
+    /* Test 1: read 0 bytes from an aggregate */
+    aggbkt = serf_bucket_aggregate_create(alloc);
+
+    bkt = SERF_BUCKET_SIMPLE_STRING(BODY, alloc);
+    serf_bucket_aggregate_append(aggbkt, bkt);
+
+    status = serf_bucket_read_iovec(aggbkt, 0, 32,
+                                    tgt_vecs, &vecs_used);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    CuAssertIntEquals(tc, 0, vecs_used);
+
+
+    /* Test 2: peek the available bytes, should be non-0 */
+    len = SERF_READ_ALL_AVAIL;
+    status = serf_bucket_peek(aggbkt, &data, &len);
+
+    /* status should be either APR_SUCCESS or APR_EOF */
+    if (status == APR_SUCCESS)
+        CuAssertTrue(tc, len > 0 && len < strlen(BODY));
+    else if (status == APR_EOF)
+        CuAssertIntEquals(tc, strlen(BODY), len);
+    else
+        CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    /* Test 3: read the data from the bucket. */
+    read_and_check_bucket(tc, aggbkt, BODY);
+
+    /* Test 4: multiple child buckets appended. */
+    aggbkt = serf_bucket_aggregate_create(alloc);
+
+    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY, 15, alloc);
+    serf_bucket_aggregate_append(aggbkt, bkt);
+    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY+15, strlen(BODY)-15, alloc);
+    serf_bucket_aggregate_append(aggbkt, bkt);
+
+    read_and_check_bucket(tc, aggbkt, BODY);
+
+    /* Test 5: multiple child buckets prepended. */
+    aggbkt = serf_bucket_aggregate_create(alloc);
+
+    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY+15, strlen(BODY)-15, alloc);
+    serf_bucket_aggregate_prepend(aggbkt, bkt);
+    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY, 15, alloc);
+    serf_bucket_aggregate_prepend(aggbkt, bkt);
+
+    read_and_check_bucket(tc, aggbkt, BODY);
+
+    /* Test 6: ensure peek doesn't return APR_EAGAIN, or APR_EOF incorrectly. */
+    aggbkt = serf_bucket_aggregate_create(alloc);
+
+    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY, 15, alloc);
+    serf_bucket_aggregate_append(aggbkt, bkt);
+    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY+15, strlen(BODY)-15, alloc);
+    serf_bucket_aggregate_append(aggbkt, bkt);
+
+    len = 1234;
+    status = serf_bucket_peek(aggbkt, &data, &len);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    CuAssert(tc, "Length should be positive.",
+             len > 0 && len <= strlen(BODY) );
+    CuAssert(tc, "Data should match first part of body.",
+             strncmp(BODY, data, len) == 0);
+}
+
+static void test_aggregate_bucket_readline(CuTest *tc)
+{
+    serf_bucket_t *bkt, *aggbkt;
+    apr_pool_t *test_pool = tc->testBaton;
+
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+                                                              NULL);
+    const char *BODY = "12345678901234567890" CRLF
+                       "12345678901234567890" CRLF
+                       "12345678901234567890" CRLF;
+
+    /* Test 1: read lines from an aggregate bucket */
+    aggbkt = serf_bucket_aggregate_create(alloc);
+
+    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY, 22, alloc);
+    serf_bucket_aggregate_append(aggbkt, bkt); /* 1st line */
+    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY+22, strlen(BODY)-22, alloc);
+    serf_bucket_aggregate_append(aggbkt, bkt); /* 2nd and 3rd line */
+
+    bkt = SERF_BUCKET_SIMPLE_STRING(BODY, alloc);
+    readlines_and_check_bucket(tc, aggbkt, SERF_NEWLINE_CRLF, BODY, 3);
+
+    /* Test 2: start with empty bucket */
+    aggbkt = serf_bucket_aggregate_create(alloc);
+
+    bkt = SERF_BUCKET_SIMPLE_STRING_LEN("", 0, alloc);
+    serf_bucket_aggregate_append(aggbkt, bkt); /* empty bucket */
+    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY, 22, alloc);
+    serf_bucket_aggregate_append(aggbkt, bkt); /* 1st line */
+    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY+22, strlen(BODY)-22, alloc);
+    serf_bucket_aggregate_append(aggbkt, bkt); /* 2nd and 3rd line */
+
+    bkt = SERF_BUCKET_SIMPLE_STRING(BODY, alloc);
+    readlines_and_check_bucket(tc, aggbkt, SERF_NEWLINE_CRLF, BODY, 3);
+}
+
+/* Test for issue: the server aborts the connection in the middle of
+   streaming the body of the response, where the length was set with the
+   Content-Length header. Test that we get a decent error code from the
+   response bucket instead of APR_EOF. */
+static void test_response_body_too_small_cl(CuTest *tc)
+{
+    serf_bucket_t *bkt, *tmp;
+    apr_pool_t *test_pool = tc->testBaton;
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+                                                              NULL);
+
+    /* Make a response of 60 bytes, but set the Content-Length to 100. */
+#define BODY "12345678901234567890"\
+             "12345678901234567890"\
+             "12345678901234567890"
+
+    tmp = SERF_BUCKET_SIMPLE_STRING("HTTP/1.1 200 OK" CRLF
+                                    "Content-Type: text/plain" CRLF
+                                    "Content-Length: 100" CRLF
+                                    CRLF
+                                    BODY,
+                                    alloc);
+    
+    bkt = serf_bucket_response_create(tmp, alloc);
+
+    {
+        const char *data;
+        apr_size_t len;
+        apr_status_t status;
+
+        status = serf_bucket_read(bkt, SERF_READ_ALL_AVAIL, &data, &len);
+
+        CuAssert(tc, "Read more data than expected.",
+                 strlen(BODY) >= len);
+        CuAssert(tc, "Read data is not equal to expected.",
+                 strncmp(BODY, data, len) == 0);
+        CuAssert(tc, "Error expected due to response body too short!",
+                 SERF_BUCKET_READ_ERROR(status));
+        CuAssertIntEquals(tc, SERF_ERROR_TRUNCATED_HTTP_RESPONSE, status);
+    }
+}
+#undef BODY
+
+/* Test for issue: the server aborts the connection in the middle of
+   streaming the body of the response, using chunked encoding. Test that we get
+   a decent error code from the response bucket instead of APR_EOF. */
+static void test_response_body_too_small_chunked(CuTest *tc)
+{
+    serf_bucket_t *bkt, *tmp;
+    apr_pool_t *test_pool = tc->testBaton;
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+                                                              NULL);
+
+    /* Make a response of 60 bytes, but set the chunk size to 60 and don't end
+       with chunk of length 0. */
+#define BODY "12345678901234567890"\
+"12345678901234567890"\
+"12345678901234567890"
+
+    tmp = SERF_BUCKET_SIMPLE_STRING("HTTP/1.1 200 OK" CRLF
+                                    "Content-Type: text/plain" CRLF
+                                    "Transfer-Encoding: chunked" CRLF
+                                    CRLF
+                                    "64" CRLF BODY,
+                                    alloc);
+
+    bkt = serf_bucket_response_create(tmp, alloc);
+
+    {
+        const char *data;
+        apr_size_t len;
+        apr_status_t status;
+
+        status = serf_bucket_read(bkt, SERF_READ_ALL_AVAIL, &data, &len);
+
+        CuAssert(tc, "Read more data than expected.",
+                 strlen(BODY) >= len);
+        CuAssert(tc, "Read data is not equal to expected.",
+                 strncmp(BODY, data, len) == 0);
+        CuAssert(tc, "Error expected due to response body too short!",
+                 SERF_BUCKET_READ_ERROR(status));
+        CuAssertIntEquals(tc, SERF_ERROR_TRUNCATED_HTTP_RESPONSE, status);
+    }
+}
+#undef BODY
+
+/* Test for issue: the server aborts the connection in the middle of
+   streaming trailing CRLF after body chunk. Test that we get
+   a decent error code from the response bucket instead of APR_EOF. */
+static void test_response_body_chunked_no_crlf(CuTest *tc)
+{
+    serf_bucket_t *bkt, *tmp;
+    apr_pool_t *test_pool = tc->testBaton;
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+                                                              NULL);
+
+    tmp = SERF_BUCKET_SIMPLE_STRING("HTTP/1.1 200 OK" CRLF
+                                    "Content-Type: text/plain" CRLF
+                                    "Transfer-Encoding: chunked" CRLF
+                                    CRLF
+                                    "2" CRLF
+                                    "AB",
+                                    alloc);
+
+    bkt = serf_bucket_response_create(tmp, alloc);
+
+    {
+        char buf[1024];
+        apr_size_t len;
+        apr_status_t status;
+
+        status = read_all(bkt, buf, sizeof(buf), &len);
+
+        CuAssertIntEquals(tc, SERF_ERROR_TRUNCATED_HTTP_RESPONSE, status);
+    }
+}
+
+/* Test for issue: the server aborts the connection in the middle of
+   streaming trailing CRLF after body chunk. Test that we get
+   a decent error code from the response bucket instead of APR_EOF. */
+static void test_response_body_chunked_incomplete_crlf(CuTest *tc)
+{
+    serf_bucket_t *bkt, *tmp;
+    apr_pool_t *test_pool = tc->testBaton;
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+                                                              NULL);
+
+    tmp = SERF_BUCKET_SIMPLE_STRING("HTTP/1.1 200 OK" CRLF
+                                    "Content-Type: text/plain" CRLF
+                                    "Transfer-Encoding: chunked" CRLF
+                                    CRLF
+                                    "2" CRLF
+                                    "AB"
+                                    "\r",
+                                    alloc);
+
+    bkt = serf_bucket_response_create(tmp, alloc);
+
+    {
+        char buf[1024];
+        apr_size_t len;
+        apr_status_t status;
+
+        status = read_all(bkt, buf, sizeof(buf), &len);
+
+        CuAssertIntEquals(tc, SERF_ERROR_TRUNCATED_HTTP_RESPONSE, status);
+    }
+}
+
+static void test_response_body_chunked_gzip_small(CuTest *tc)
+{
+    serf_bucket_t *bkt, *tmp;
+    apr_pool_t *test_pool = tc->testBaton;
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+                                                              NULL);
+
+    tmp = SERF_BUCKET_SIMPLE_STRING("HTTP/1.1 200 OK" CRLF
+                                    "Content-Type: text/plain" CRLF
+                                    "Transfer-Encoding: chunked" CRLF
+                                    "Content-Encoding: gzip" CRLF
+                                    CRLF
+                                    "2" CRLF
+                                    "A",
+                                    alloc);
+
+    bkt = serf_bucket_response_create(tmp, alloc);
+
+    {
+        char buf[1024];
+        apr_size_t len;
+        apr_status_t status;
+
+        status = read_all(bkt, buf, sizeof(buf), &len);
+
+        CuAssertIntEquals(tc, SERF_ERROR_TRUNCATED_HTTP_RESPONSE, status);
+    }
+}
+
+static void test_response_bucket_peek_at_headers(CuTest *tc)
+{
+    apr_pool_t *test_pool = tc->testBaton;
+    serf_bucket_t *resp_bkt1, *tmp, *hdrs;
+    serf_status_line sl;
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+                                                              NULL);
+    const char *hdr_val, *cur;
+    apr_status_t status;
+
+#define EXP_RESPONSE "HTTP/1.1 200 OK" CRLF\
+                     "Content-Type: text/plain" CRLF\
+                     "Content-Length: 100" CRLF\
+                     CRLF\
+                     "12345678901234567890"\
+                     "12345678901234567890"\
+                     "12345678901234567890"
+
+    tmp = SERF_BUCKET_SIMPLE_STRING(EXP_RESPONSE,
+                                    alloc);
+
+    resp_bkt1 = serf_bucket_response_create(tmp, alloc);
+
+    status = serf_bucket_response_status(resp_bkt1, &sl);
+    CuAssertIntEquals(tc, 200, sl.code);
+    CuAssertStrEquals(tc, "OK", sl.reason);
+    CuAssertIntEquals(tc, SERF_HTTP_11, sl.version);
+    
+    /* Ensure that the status line & headers are read in the response_bucket. */
+    status = serf_bucket_response_wait_for_headers(resp_bkt1);
+    CuAssert(tc, "Unexpected error when waiting for response headers",
+             !SERF_BUCKET_READ_ERROR(status));
+
+    hdrs = serf_bucket_response_get_headers(resp_bkt1);
+    CuAssertPtrNotNull(tc, hdrs);
+
+    hdr_val = serf_bucket_headers_get(hdrs, "Content-Type");
+    CuAssertStrEquals(tc, "text/plain", hdr_val);
+    hdr_val = serf_bucket_headers_get(hdrs, "Content-Length");
+    CuAssertStrEquals(tc, "100", hdr_val);
+
+    /* Create a new bucket for the response which still has the original
+       status line & headers. */
+
+    status = serf_response_full_become_aggregate(resp_bkt1);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    cur = EXP_RESPONSE;
+
+    while (1) {
+        const char *data;
+        apr_size_t len;
+        apr_status_t status;
+
+        status = serf_bucket_read(resp_bkt1, SERF_READ_ALL_AVAIL, &data, &len);
+        CuAssert(tc, "Unexpected error when waiting for response headers",
+                 !SERF_BUCKET_READ_ERROR(status));
+        if (SERF_BUCKET_READ_ERROR(status) ||
+            APR_STATUS_IS_EOF(status))
+            break;
+
+        /* Check that the bytes read match with expected at current position. */
+        CuAssertStrnEquals(tc, cur, len, data);
+        cur += len;
+    }
+
+}
+#undef EXP_RESPONSE
+
+/* ### this test is useful, but needs to switch to the new COPY bucket
+   ### to test the behavior.  */
+#if 0
+
+/* Test that the internal function serf_default_read_iovec, used by many
+   bucket types, groups multiple buffers in one iovec. */
+static void test_serf_default_read_iovec(CuTest *tc)
+{
+    apr_status_t status;
+    serf_bucket_t *bkt, *aggbkt;
+    struct iovec tgt_vecs[32];
+    int vecs_used, i;
+    apr_size_t actual_len = 0;
+
+    apr_pool_t *test_pool = tc->testBaton;
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+                                                              NULL);
+    const char *BODY = "12345678901234567890"\
+                       "12345678901234567890"\
+                       "12345678901234567890"\
+                       CRLF;
+
+    /* Test 1: multiple children, should be read in one iovec. */
+    aggbkt = serf_bucket_aggregate_create(alloc);
+
+    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY, 20, alloc);
+    serf_bucket_aggregate_append(aggbkt, bkt);
+    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY+20, 20, alloc);
+    serf_bucket_aggregate_append(aggbkt, bkt);
+    bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY+40, strlen(BODY)-40, alloc);
+    serf_bucket_aggregate_append(aggbkt, bkt);
+
+    status = serf_default_read_iovec(aggbkt, SERF_READ_ALL_AVAIL, 32, tgt_vecs,
+                                     &vecs_used);
+    CuAssertIntEquals(tc, APR_EOF, status);
+    for (i = 0; i < vecs_used; i++)
+        actual_len += tgt_vecs[i].iov_len;
+    CuAssertIntEquals(tc, strlen(BODY), actual_len);
+}
+
+#endif
+
+/* Test that serf doesn't hang in an endless loop when a linebuf is in
+   split-CRLF state. */
+static void test_linebuf_crlf_split(CuTest *tc)
+{
+    serf_bucket_t *mock_bkt, *bkt;
+    apr_pool_t *test_pool = tc->testBaton;
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+                                                              NULL);
+
+    mockbkt_action actions[]= {
+        { 1, "HTTP/1.1 200 OK" CRLF, APR_SUCCESS },
+        { 1, "Content-Type: text/plain" CRLF
+             "Transfer-Encoding: chunked" CRLF
+             CRLF, APR_SUCCESS },
+        { 1, "6" CR, APR_SUCCESS },
+        { 1, "", APR_EAGAIN },
+        { 1,  LF "blabla" CRLF CRLF, APR_SUCCESS }, };
+    apr_status_t status;
+
+    const char *expected = "blabla";
+
+    mock_bkt = serf_bucket_mock_create(actions, 5, alloc);
+    bkt = serf_bucket_response_create(mock_bkt, alloc);
+
+    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;
+
+        if (len == 0 && status == APR_EAGAIN)
+            serf_bucket_mock_more_data_arrived(mock_bkt);
+    } while(!APR_STATUS_IS_EOF(status));
+
+    CuAssert(tc, "Read less data than expected.", strlen(expected) == 0);
+}
+
+/* Test handling responses without a reason by response buckets. */
+static void test_response_bucket_no_reason(CuTest *tc)
+{
+    test_baton_t *tb = tc->testBaton;
+    serf_bucket_t *bkt, *tmp;
+    serf_status_line sline;
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(tb->pool, NULL,
+                                                              NULL);
+
+    tmp = SERF_BUCKET_SIMPLE_STRING("HTTP/1.1 401" CRLF
+                                    "Content-Type: text/plain" CRLF
+                                    "Content-Length: 2" CRLF
+                                    CRLF
+                                    "AB",
+                                    alloc);
+
+    bkt = serf_bucket_response_create(tmp, alloc);
+
+    read_and_check_bucket(tc, bkt, "AB");
+
+    serf_bucket_response_status(bkt, &sline);
+    CuAssertTrue(tc, sline.version == SERF_HTTP_11);
+    CuAssertIntEquals(tc, 401, sline.code);
+
+    /* Probably better to have just "Logon failed" as reason. But current
+       behavior is also acceptable.*/
+    CuAssertStrEquals(tc, "", sline.reason);
+}
+
+/* Test that serf can handle lines that don't arrive completely in one go.
+   It doesn't really run random, it tries inserting APR_EAGAIN in all possible
+   places in the response message, only one currently. */
+static void test_random_eagain_in_response(CuTest *tc)
+{
+    apr_pool_t *test_pool = tc->testBaton;
+    apr_pool_t *iter_pool;
+
+#define BODY "12345678901234567890123456789012345678901234567890"\
+             "12345678901234567890123456789012345678901234567890"
+
+    const char *expected = apr_psprintf(test_pool, "%s%s", BODY, BODY);
+    const char *fullmsg = "HTTP/1.1 200 OK" CRLF
+    "Date: Fri, 12 Jul 2013 15:13:52 GMT" CRLF
+    "Server: Apache/2.2.17 (Unix) mod_ssl/2.2.17 OpenSSL/1.0.1e DAV/2 "
+    "mod_wsgi/3.4 Python/2.7.3 SVN/1.7.10" CRLF
+    "DAV: 1,2" CRLF
+    "DAV: version-control,checkout,working-resource" CRLF
+    "DAV: merge,baseline,activity,version-controlled-collection" CRLF
+    "DAV: http://subversion.tigris.org/xmlns/dav/svn/depth" CRLF
+    "DAV: http://subversion.tigris.org/xmlns/dav/svn/log-revprops" CRLF
+    "DAV: http://subversion.tigris.org/xmlns/dav/svn/atomic-revprops" CRLF
+    "DAV: http://subversion.tigris.org/xmlns/dav/svn/partial-replay" CRLF
+    "DAV: http://subversion.tigris.org/xmlns/dav/svn/mergeinfo" CRLF
+    "DAV: <http://apache.org/dav/propset/fs/1>" CRLF
+    "MS-Author-Via: DAV" CRLF
+    "Allow: OPTIONS,GET,HEAD,POST,DELETE,TRACE,PROPFIND,PROPPATCH,COPY,MOVE,"
+    "LOCK,UNLOCK,CHECKOUT" CRLF
+    "SVN-Youngest-Rev: 1502584" CRLF
+    "SVN-Repository-UUID: 13f79535-47bb-0310-9956-ffa450edef68" CRLF
+    "SVN-Repository-Root: /repos/asf" CRLF
+    "SVN-Me-Resource: /repos/asf/!svn/me" CRLF
+    "SVN-Rev-Root-Stub: /repos/asf/!svn/rvr" CRLF
+    "SVN-Rev-Stub: /repos/asf/!svn/rev" CRLF
+    "SVN-Txn-Root-Stub: /repos/asf/!svn/txr" CRLF
+    "SVN-Txn-Stub: /repos/asf/!svn/txn" CRLF
+    "SVN-VTxn-Root-Stub: /repos/asf/!svn/vtxr" CRLF
+    "SVN-VTxn-Stub: /repos/asf/!svn/vtxn" CRLF
+    "Vary: Accept-Encoding" CRLF
+    "Content-Type: text/plain" CRLF
+    "Content-Type: text/xml; charset=\"utf-8\"" CRLF
+    "Transfer-Encoding: chunked" CRLF
+    CRLF
+    "64" CRLF
+    BODY CRLF
+    "64" CRLF
+    BODY CRLF
+    "0" CRLF
+    CRLF;
+
+    const long nr_of_tests = strlen(fullmsg);
+    long i;
+
+    mockbkt_action actions[]= {
+        { 1, NULL, APR_EAGAIN },
+        { 1, NULL, APR_EAGAIN },
+    };
+
+    apr_pool_create(&iter_pool, test_pool);
+
+    for (i = 0; i < nr_of_tests; i++) {
+        serf_bucket_t *mock_bkt, *bkt;
+        serf_bucket_alloc_t *alloc;
+        const char *ptr = expected;
+        const char *part1, *part2;
+        apr_size_t cut;
+        apr_status_t status;
+
+        apr_pool_clear(iter_pool);
+
+        alloc = serf_bucket_allocator_create(iter_pool, NULL, NULL);
+
+        cut = i % strlen(fullmsg);
+        part1 = apr_pstrndup(iter_pool, fullmsg, cut);
+        part2 = apr_pstrdup(iter_pool, fullmsg + cut);
+
+        actions[0].data = part1;
+        actions[1].data = part2;
+
+        mock_bkt = serf_bucket_mock_create(actions, 2, alloc);
+        bkt = serf_bucket_response_create(mock_bkt, alloc);
+
+        do
+        {
+            const char *data, *errmsg;
+            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));
+            errmsg = apr_psprintf(iter_pool,
+                                  "Read more data than expected, EAGAIN"
+                                  " inserted at pos: %d, remainder: \"%s\"",
+                                  cut, fullmsg + cut);
+            CuAssert(tc, errmsg, strlen(ptr) >= len);
+            errmsg = apr_psprintf(iter_pool,
+                                  "Read data is not equal to expected, EAGAIN"
+                                  " inserted at pos: %d, remainder: \"%s\"",
+                                  cut, fullmsg + cut);
+            CuAssertStrnEquals_Msg(tc, errmsg, ptr, len, data);
+
+            ptr += len;
+
+            if (len == 0 && status == APR_EAGAIN)
+                serf_bucket_mock_more_data_arrived(mock_bkt);
+        } while(!APR_STATUS_IS_EOF(status));
+
+        CuAssert(tc, "Read less data than expected.", strlen(ptr) == 0);
+    }
+    apr_pool_destroy(iter_pool);
+
+}
+
+static void test_dechunk_buckets(CuTest *tc)
+{
+    serf_bucket_t *mock_bkt, *bkt;
+    apr_pool_t *test_pool = tc->testBaton;
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+                                                              NULL);
+    mockbkt_action actions[]= {
+        /* one chunk */
+        { 1, "6" CRLF "blabla" CRLF, APR_SUCCESS },
+        /* EAGAIN after first chunk */
+        { 1, "6" CRLF "blabla" CRLF, APR_EAGAIN },
+        { 1, "6" CRLF "blabla" CRLF, APR_SUCCESS },
+        /* CRLF after body split */
+        { 1, "6" CRLF "blabla" CR, APR_EAGAIN },
+        { 1,  LF, APR_SUCCESS },
+        /* CRLF before body split */
+        { 1, "6" CR, APR_SUCCESS },
+        { 1, "", APR_EAGAIN },
+        { 1,  LF "blabla" CRLF, APR_SUCCESS },
+        /* empty chunk */
+        { 1, "", APR_SUCCESS },
+        /* two chunks */
+        { 1, "6" CRLF "blabla" CRLF "6" CRLF "blabla" CRLF, APR_SUCCESS },
+        /* three chunks */
+        { 1, "6" CRLF "blabla" CRLF "6" CRLF "blabla" CRLF
+             "0" CRLF "" CRLF, APR_SUCCESS },
+    };
+    const int nr_of_actions = sizeof(actions) / sizeof(mockbkt_action);
+    apr_status_t status;
+    const char *body = "blabla";
+    const char *expected = apr_psprintf(test_pool, "%s%s%s%s%s%s%s%s%s", body,
+                                        body, body, body, body, body, body,
+                                        body, body);
+
+    mock_bkt = serf_bucket_mock_create(actions, nr_of_actions, alloc);
+    bkt = serf_bucket_dechunk_create(mock_bkt, alloc);
+
+    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;
+
+        if (len == 0 && status == APR_EAGAIN)
+            serf_bucket_mock_more_data_arrived(mock_bkt);
+    } while(!APR_STATUS_IS_EOF(status));
+
+    CuAssert(tc, "Read less data than expected.", strlen(expected) == 0);
+}
+
+/* Test that the Content-Length header will be ignored when the response
+   should not have returned a body. See RFC2616, section 4.4, nbr. 1. */
+static void test_response_no_body_expected(CuTest *tc)
+{
+    serf_bucket_t *bkt, *tmp;
+    apr_pool_t *test_pool = tc->testBaton;
+    char buf[1024];
+    apr_size_t len;
+    serf_bucket_alloc_t *alloc;
+    int i;
+    apr_status_t status;
+
+    /* response bucket should consider the blablablablabla as start of the
+       next response, in all these cases it should APR_EOF after the empty
+       line. */
+    test_server_message_t message_list[] = {
+        { "HTTP/1.1 100 Continue" CRLF
+          "Content-Type: text/plain" CRLF
+          "Content-Length: 6500000" CRLF
+          CRLF
+          "blablablablabla" CRLF },
+        { "HTTP/1.1 204 No Content" CRLF
+            "Content-Type: text/plain" CRLF
+            "Content-Length: 6500000" CRLF
+            CRLF
+            "blablablablabla" CRLF },
+        { "HTTP/1.1 304 Not Modified" CRLF
+            "Content-Type: text/plain" CRLF
+            "Content-Length: 6500000" CRLF
+            CRLF
+            "blablablablabla" CRLF },
+    };
+
+    alloc = serf_bucket_allocator_create(test_pool, NULL, NULL);
+
+    /* Test 1: a response to a HEAD request. */
+    tmp = SERF_BUCKET_SIMPLE_STRING("HTTP/1.1 200 OK" CRLF
+                                    "Content-Type: text/plain" CRLF
+                                    "Content-Length: 6500000" CRLF
+                                    CRLF
+                                    "blablablablabla" CRLF,
+                                    alloc);
+
+    bkt = serf_bucket_response_create(tmp, alloc);
+    serf_bucket_response_set_head(bkt);
+
+    status = read_all(bkt, buf, sizeof(buf), &len);
+
+    CuAssertIntEquals(tc, APR_EOF, status);
+    CuAssertIntEquals(tc, 0, len);
+
+    /* Test 2: a response with status for which server must not send a body. */
+    for (i = 0; i < sizeof(message_list) / sizeof(test_server_message_t); i++) {
+
+        tmp = SERF_BUCKET_SIMPLE_STRING(message_list[i].text, alloc);
+        bkt = serf_bucket_response_create(tmp, alloc);
+
+        status = read_all(bkt, buf, sizeof(buf), &len);
+
+        CuAssertIntEquals(tc, APR_EOF, status);
+        CuAssertIntEquals(tc, 0, len);
+    }
+}
+
+static apr_status_t deflate_compress(const char **data, apr_size_t *len,
+                                     z_stream *zdestr,
+                                     const char *orig, apr_size_t orig_len,
+                                     int last,
+                                     apr_pool_t *pool)
+{
+    int zerr;
+    apr_size_t buf_size;
+    void *write_buf;
+
+    /* The largest buffer we should need is 0.1% larger than the
+       uncompressed data, + 12 bytes. This info comes from zlib.h.
+       buf_size = orig_len + (orig_len / 1000) + 12;
+       Note: This isn't sufficient when using Z_NO_FLUSH and extremely compressed
+       data. Use a buffer bigger than what we need. */
+    buf_size = 100000;
+
+    write_buf = apr_palloc(pool, buf_size);
+
+    zdestr->next_in = (Bytef *)orig;  /* Casting away const! */
+    zdestr->avail_in = (uInt)orig_len;
+
+    zerr = Z_OK;
+    zdestr->next_out = write_buf;
+    zdestr->avail_out = (uInt)buf_size;
+
+    while ((last && zerr != Z_STREAM_END) ||
+           (!last && zdestr->avail_in > 0))
+    {
+        zerr = deflate(zdestr, last ? Z_FINISH : Z_NO_FLUSH);
+        if (zerr < 0)
+            return APR_EGENERAL;
+    }
+
+    *data = write_buf;
+    *len = buf_size - zdestr->avail_out;
+    
+    return APR_SUCCESS;
+}
+
+/* Reads bucket until EOF found and compares read data with zero terminated
+ string expected. Report all failures using CuTest. */
+static void read_bucket_and_check_pattern(CuTest *tc, serf_bucket_t *bkt,
+                                          const char *pattern,
+                                          apr_size_t expected_len)
+{
+    apr_status_t status;
+    const char *expected;
+    const apr_size_t pattern_len = strlen(pattern);
+
+    apr_size_t exp_rem = 0;
+    apr_size_t actual_len = 0;
+
+    do
+    {
+        const char *data;
+        apr_size_t act_rem;
+
+        status = serf_bucket_read(bkt, SERF_READ_ALL_AVAIL, &data, &act_rem);
+
+        CuAssert(tc, "Got error during bucket reading.",
+                 !SERF_BUCKET_READ_ERROR(status));
+
+        actual_len += act_rem;
+
+        while (act_rem > 0) {
+            apr_size_t bytes_to_compare;
+
+            if (exp_rem == 0) {
+                expected = pattern;
+                exp_rem = pattern_len;
+            }
+
+            bytes_to_compare = act_rem < exp_rem ? act_rem : exp_rem;
+            CuAssert(tc, "Read data is not equal to expected.",
+                     strncmp(expected, data, bytes_to_compare) == 0);
+            data += bytes_to_compare;
+            act_rem -= bytes_to_compare;
+
+            expected += bytes_to_compare;
+            exp_rem -= bytes_to_compare;
+        }
+    } while(!APR_STATUS_IS_EOF(status));
+
+    CuAssertIntEquals_Msg(tc, "Read less data than expected.", 0, exp_rem);
+    CuAssertIntEquals_Msg(tc, "Read less/more data than expected.", actual_len,
+                          expected_len);
+}
+
+static void deflate_buckets(CuTest *tc, int nr_of_loops, apr_pool_t *pool)
+{
+    const char *msg = "12345678901234567890123456789012345678901234567890";
+
+    test_baton_t *tb = tc->testBaton;
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(pool, NULL,
+                                                              NULL);
+    z_stream zdestr;
+    int i;
+    const char gzip_header[10] =
+    { '\037', '\213', Z_DEFLATED, 0,
+        0, 0, 0, 0, /* mtime */
+        0, 0x03 /* Unix OS_CODE */
+    };
+
+    serf_bucket_t *aggbkt = serf_bucket_aggregate_create(alloc);
+    serf_bucket_t *defbkt = serf_bucket_deflate_create(aggbkt, alloc,
+                                                       SERF_DEFLATE_GZIP);
+    serf_bucket_t *strbkt;
+
+#if 0 /* Enable logging */
+    {
+        serf_config_t *config;
+
+        serf_context_t *ctx = serf_context_create(pool);
+        /* status = */ serf__config_store_get_config(ctx, NULL, &config, pool);
+
+        serf_bucket_set_config(defbkt, config);
+    }
+#endif
+
+    memset(&zdestr, 0, sizeof(z_stream));
+    /* HTTP uses raw deflate format, so windows size => -15 */
+    CuAssert(tc, "zlib init failed.",
+             deflateInit2(&zdestr, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8,
+                          Z_DEFAULT_STRATEGY) == Z_OK);
+
+    strbkt = SERF_BUCKET_SIMPLE_STRING_LEN(gzip_header, 10, alloc);
+    serf_bucket_aggregate_append(aggbkt, strbkt);
+
+    for (i = 0; i < nr_of_loops; i++) {
+        const char *data = NULL;
+        apr_size_t len = 0;
+
+        if (i == nr_of_loops - 1) {
+            CuAssertIntEquals(tc, APR_SUCCESS,
+                              deflate_compress(&data, &len, &zdestr, msg,
+                                               strlen(msg), 1, pool));
+        } else {
+            CuAssertIntEquals(tc, APR_SUCCESS,
+                              deflate_compress(&data, &len, &zdestr, msg,
+                                               strlen(msg), 0, pool));
+        }
+
+        if (len == 0)
+            continue;
+
+        strbkt = SERF_BUCKET_SIMPLE_STRING_LEN(data, len, alloc);
+
+        serf_bucket_aggregate_append(aggbkt, strbkt);
+    }
+
+    tb->user_baton_l = APR_EOF;
+    read_bucket_and_check_pattern(tc, defbkt, msg, nr_of_loops * strlen(msg));
+}
+
+static void test_deflate_buckets(CuTest *tc)
+{
+    int i;
+    apr_pool_t *iterpool;
+    test_baton_t *tb = tc->testBaton;
+
+    apr_pool_create(&iterpool, tb->pool);
+    for (i = 1; i < 1000; i++) {
+        apr_pool_clear(iterpool);
+        deflate_buckets(tc, i, iterpool);
+    }
+    apr_pool_destroy(iterpool);
+}
+
+static apr_status_t discard_data(serf_bucket_t *bkt,
+                                 apr_size_t *read_len)
+{
+    const char *data;
+    apr_size_t data_len;
+    apr_status_t status;
+    apr_size_t read;
+
+    read = 0;
+
+    do
+    {
+        status = serf_bucket_read(bkt, SERF_READ_ALL_AVAIL, &data, &data_len);
+
+        if (!SERF_BUCKET_READ_ERROR(status)) {
+            read += data_len;
+        }
+    } while(status == APR_SUCCESS);
+
+    *read_len = read;
+    return status;
+}
+
+static apr_status_t hold_open(void *baton, serf_bucket_t *aggbkt)
+{
+    test_baton_t *tb = baton;
+
+    return tb->user_baton_l;
+}
+
+static void put_32bit(unsigned char *buf, unsigned long x)
+{
+    buf[0] = (unsigned char)(x & 0xFF);
+    buf[1] = (unsigned char)((x & 0xFF00) >> 8);
+    buf[2] = (unsigned char)((x & 0xFF0000) >> 16);
+    buf[3] = (unsigned char)((x & 0xFF000000) >> 24);
+}
+
+static serf_bucket_t *
+create_gzip_deflate_bucket(serf_bucket_t *stream, z_stream *outzstr,
+                           serf_bucket_alloc_t *alloc)
+{
+    serf_bucket_t *strbkt;
+    serf_bucket_t *defbkt = serf_bucket_deflate_create(stream, alloc,
+                                                       SERF_DEFLATE_GZIP);
+    int zerr;
+    const char gzip_header[10] =
+    { '\037', '\213', Z_DEFLATED, 0,
+        0, 0, 0, 0, /* mtime */
+        0, 0x03 /* Unix OS_CODE */
+    };
+
+    memset(outzstr, 0, sizeof(z_stream));
+
+    /* HTTP uses raw deflate format, so windows size => -15 */
+    zerr = deflateInit2(outzstr, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8,
+                        Z_DEFAULT_STRATEGY);
+    if (zerr != Z_OK)
+        return NULL;
+
+    strbkt = SERF_BUCKET_SIMPLE_STRING_LEN(gzip_header, 10, alloc);
+    serf_bucket_aggregate_append(stream, strbkt);
+
+    return defbkt;
+}
+
+/* Test for issue #152: the trailers of gzipped data only store the 4 most 
+   significant bytes of the length, so when the compressed data is >4GB
+   we can't just compare actual length with expected length. */
+static void test_deflate_4GBplus_buckets(CuTest *tc)
+{
+    test_baton_t *tb = tc->testBaton;
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(tb->pool, NULL,
+                                                              NULL);
+    int i;
+    unsigned char gzip_trailer[8];
+    z_stream zdestr;
+    serf_bucket_t *aggbkt = serf_bucket_aggregate_create(alloc);
+    serf_bucket_t *defbkt = create_gzip_deflate_bucket(aggbkt, &zdestr, alloc);
+    serf_bucket_t *strbkt;
+    apr_pool_t *iter_pool;
+    apr_size_t actual_size;
+    unsigned long unc_crc = 0;
+    unsigned long unc_length = 0;
+
+#define NR_OF_LOOPS 550000
+#define BUFSIZE 8096
+    unsigned char uncompressed[BUFSIZE];
+
+    serf_bucket_aggregate_hold_open(aggbkt, hold_open, tb);
+    tb->user_baton_l = APR_EAGAIN;
+
+
+#if 0 /* Enable logging */
+    {
+        serf_config_t *config;
+
+        serf_context_t *ctx = serf_context_create(tb->pool);
+        /* status = */ serf__config_store_get_config(ctx, NULL, &config, tb->pool);
+
+        serf_bucket_set_config(defbkt, config);
+    }
+#endif
+
+    apr_pool_create(&iter_pool, tb->pool);
+
+    actual_size = 0;
+    for (i = 0; i < NR_OF_LOOPS; i++) {
+        const char *data;
+        apr_size_t len;
+        apr_size_t read_len;
+        serf_bucket_alloc_t *iter_alloc;
+        apr_status_t status;
+
+        apr_pool_clear(iter_pool);
+        iter_alloc = serf_bucket_allocator_create(iter_pool, NULL, NULL);
+
+
+        if (i % 1000 == 0)
+            printf("%d\n", i);
+
+        status = apr_generate_random_bytes(uncompressed, BUFSIZE);
+        CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+        unc_crc = crc32(unc_crc, (const Bytef *)uncompressed, BUFSIZE);
+        unc_length += BUFSIZE;
+
+        if (i == NR_OF_LOOPS - 1) {
+            CuAssertIntEquals(tc, APR_SUCCESS,
+                              deflate_compress(&data, &len, &zdestr,
+                                               (const char *)uncompressed,
+                                               BUFSIZE, 1, iter_pool));
+        } else {
+            CuAssertIntEquals(tc, APR_SUCCESS,
+                              deflate_compress(&data, &len, &zdestr,
+                                               (const char *)uncompressed,
+                                               BUFSIZE, 0, iter_pool));
+        }
+
+        if (len == 0)
+            continue;
+
+        strbkt = serf_bucket_simple_copy_create(data, len, iter_alloc);
+        serf_bucket_aggregate_append(aggbkt, strbkt);
+
+        /* Start reading inflated data */
+        status = discard_data(defbkt, &read_len);
+        CuAssert(tc, "Got error during discarding of compressed data.",
+                 !SERF_BUCKET_READ_ERROR(status));
+
+        actual_size += read_len;
+    }
+
+    put_32bit(&gzip_trailer[0], unc_crc);
+    put_32bit(&gzip_trailer[4], unc_length);
+    strbkt = SERF_BUCKET_SIMPLE_STRING_LEN((const char *)gzip_trailer,
+                                           sizeof(gzip_trailer), alloc);
+    serf_bucket_aggregate_append(aggbkt, strbkt);
+
+    tb->user_baton_l = APR_EOF;
+
+    while (1) {
+        apr_size_t read_len;
+        apr_status_t status = discard_data(defbkt, &read_len);
+        CuAssert(tc, "Got error during discarding of compressed data.",
+                 !SERF_BUCKET_READ_ERROR(status));
+        actual_size += read_len;
+        if (status == APR_EOF)
+            break;
+    }
+
+    CuAssertTrue(tc, actual_size == (apr_size_t)NR_OF_LOOPS * BUFSIZE);
+#undef NR_OF_LOOPS
+#undef BUFSIZE
+}
+
+CuSuite *test_buckets(void)
+{
+    CuSuite *suite = CuSuiteNew();
+
+    CuSuiteSetSetupTeardownCallbacks(suite, test_setup, test_teardown);
+
+    SUITE_ADD_TEST(suite, test_simple_bucket_readline);
+    SUITE_ADD_TEST(suite, test_response_bucket_read);
+    SUITE_ADD_TEST(suite, test_response_bucket_headers);
+    SUITE_ADD_TEST(suite, test_response_bucket_chunked_read);
+    SUITE_ADD_TEST(suite, test_response_body_too_small_cl);
+    SUITE_ADD_TEST(suite, test_response_body_too_small_chunked);
+    SUITE_ADD_TEST(suite, test_response_body_chunked_no_crlf);
+    SUITE_ADD_TEST(suite, test_response_body_chunked_incomplete_crlf);
+    SUITE_ADD_TEST(suite, test_response_body_chunked_gzip_small);
+    SUITE_ADD_TEST(suite, test_response_bucket_peek_at_headers);
+    SUITE_ADD_TEST(suite, test_response_bucket_no_reason);
+    SUITE_ADD_TEST(suite, test_bucket_header_set);
+    SUITE_ADD_TEST(suite, test_iovec_buckets);
+    SUITE_ADD_TEST(suite, test_aggregate_buckets);
+    SUITE_ADD_TEST(suite, test_aggregate_bucket_readline);
+    SUITE_ADD_TEST(suite, test_header_buckets);
+    SUITE_ADD_TEST(suite, test_linebuf_crlf_split);
+    SUITE_ADD_TEST(suite, test_random_eagain_in_response);
+    SUITE_ADD_TEST(suite, test_dechunk_buckets);
+    SUITE_ADD_TEST(suite, test_response_no_body_expected);
+    SUITE_ADD_TEST(suite, test_deflate_buckets);
+#if 0
+    /* This test for issue #152 takes a lot of time generating 4GB+ of random
+       data so it's disabled by default. */
+    SUITE_ADD_TEST(suite, test_deflate_4GBplus_buckets);
+#endif
+
+#if 0
+    SUITE_ADD_TEST(suite, test_serf_default_read_iovec);
+#endif
+
+    return suite;
+}

Deleted: vendor/serf/1.3.9/test/test_context.c
===================================================================
--- vendor/serf/dist/test/test_context.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/test/test_context.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,2302 +0,0 @@
-/* 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 "serf_private.h"
-
-#include "test_serf.h"
-#include "server/test_server.h"
-
-/* 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;
-    handler_baton_t handler_ctx[2];
-    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-    apr_status_t status;
-    int i;
-    test_server_message_t message_list[] = {
-        {CHUNKED_REQUEST(1, "1")},
-        {CHUNKED_REQUEST(1, "2")},
-    };
-
-    test_server_action_t action_list[] = {
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-    };
-
-    apr_pool_t *test_pool = tc->testBaton;
-
-    /* Set up a test context with a server */
-    status = test_http_server_setup(&tb,
-                                    message_list, num_requests,
-                                    action_list, num_requests, 0, NULL,
-                                    test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
-    create_new_request(tb, &handler_ctx[1], "GET", "/", 2);
-
-    test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
-                                       test_pool);
-
-    /* Check that the requests were sent in the order we created them */
-    for (i = 0; i < tb->sent_requests->nelts; i++) {
-        int req_nr = APR_ARRAY_IDX(tb->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 < tb->handled_requests->nelts; i++) {
-        int req_nr = APR_ARRAY_IDX(tb->handled_requests, i, int);
-        CuAssertIntEquals(tc, i + 1, req_nr);
-    }
-}
-
-/* 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;
-    handler_baton_t handler_ctx[3];
-    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-    apr_status_t status;
-    int i;
-
-    test_server_message_t message_list[] = {
-        {CHUNKED_REQUEST(1, "1")},
-        {CHUNKED_REQUEST(1, "2")},
-        {CHUNKED_REQUEST(1, "3")},
-    };
-
-    test_server_action_t action_list[] = {
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-    };
-
-    apr_pool_t *test_pool = tc->testBaton;
-
-    /* Set up a test context with a server */
-    status = test_http_server_setup(&tb,
-                                    message_list, num_requests,
-                                    action_list, num_requests, 0, NULL,
-                                    test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 2);
-    create_new_request(tb, &handler_ctx[1], "GET", "/", 3);
-    create_new_prio_request(tb, &handler_ctx[2], "GET", "/", 1);
-
-    test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
-                                       test_pool);
-
-    /* Check that the requests were sent in the order we created them */
-    for (i = 0; i < tb->sent_requests->nelts; i++) {
-        int req_nr = APR_ARRAY_IDX(tb->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 < tb->handled_requests->nelts; i++) {
-        int req_nr = APR_ARRAY_IDX(tb->handled_requests, i, int);
-        CuAssertIntEquals(tc, i + 1, req_nr);
-    }
-}
-
-/* Test that serf correctly handles the 'Connection:close' header when the
-   server is planning to close the connection. */
-static void test_closed_connection(CuTest *tc)
-{
-    test_baton_t *tb;
-    apr_status_t status;
-    handler_baton_t handler_ctx[10];
-    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-    int done = FALSE, i;
-
-    test_server_message_t message_list[] = {
-        {CHUNKED_REQUEST(1, "1")},
-        {CHUNKED_REQUEST(1, "2")},
-        {CHUNKED_REQUEST(1, "3")},
-        {CHUNKED_REQUEST(1, "4")},
-        {CHUNKED_REQUEST(1, "5")},
-        {CHUNKED_REQUEST(1, "6")},
-        {CHUNKED_REQUEST(1, "7")},
-        {CHUNKED_REQUEST(1, "8")},
-        {CHUNKED_REQUEST(1, "9")},
-        {CHUNKED_REQUEST(2, "10")}
-        };
-
-    test_server_action_t action_list[] = {
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND,
-         "HTTP/1.1 200 OK" CRLF
-         "Transfer-Encoding: chunked" CRLF
-         "Connection: close" CRLF
-         CRLF
-         "0" CRLF
-         CRLF
-        },
-        {SERVER_IGNORE_AND_KILL_CONNECTION},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND,
-         "HTTP/1.1 200 OK" CRLF
-         "Transfer-Encoding: chunked" CRLF
-         "Connection: close" CRLF
-         CRLF
-         "0" CRLF
-         CRLF
-        },
-        {SERVER_IGNORE_AND_KILL_CONNECTION},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-    };
-
-    apr_pool_t *test_pool = tc->testBaton;
-
-    /* Set up a test context with a server. */
-    status = test_http_server_setup(&tb,
-                                    message_list, num_requests,
-                                    action_list, 12,
-                                    0,
-                                    NULL,
-                                    test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    /* Send some requests on the connections */
-    for (i = 0 ; i < num_requests ; i++) {
-        create_new_request(tb, &handler_ctx[i], "GET", "/", i+1);
-    }
-
-    while (1) {
-        status = run_test_server(tb->serv_ctx, 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, tb->sent_requests->nelts >= num_requests);
-   CuAssertIntEquals(tc, num_requests, tb->accepted_requests->nelts);
-   CuAssertIntEquals(tc, num_requests, tb->handled_requests->nelts);
-}
-
-/* Test if serf is sending the request to the proxy, not to the server
-   directly. */
-static void test_setup_proxy(CuTest *tc)
-{
-    test_baton_t *tb;
-    int i;
-    handler_baton_t handler_ctx[1];
-    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-    apr_pool_t *iter_pool;
-    apr_status_t status;
-
-    test_server_message_t message_list[] = {
-        {"GET http://localhost:" SERV_PORT_STR " HTTP/1.1" CRLF\
-         "Host: localhost:" SERV_PORT_STR CRLF\
-         "Transfer-Encoding: chunked" CRLF\
-         CRLF\
-         "1" CRLF\
-         "1" CRLF\
-         "0" CRLF\
-         CRLF}
-    };
-
-    test_server_action_t action_list_proxy[] = {
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-    };
-
-    apr_pool_t *test_pool = tc->testBaton;
-
-    /* Set up a test context with a server, no messages expected. */
-    status = test_server_proxy_setup(&tb,
-                                     /* server messages and actions */
-                                     NULL, 0,
-                                     NULL, 0,
-                                     /* server messages and actions */
-                                     message_list, 1,
-                                     action_list_proxy, 1,
-                                     0,
-                                     NULL, test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
-
-    apr_pool_create(&iter_pool, test_pool);
-
-    while (!handler_ctx[0].done)
-    {
-        apr_pool_clear(iter_pool);
-
-        status = run_test_server(tb->serv_ctx, 0, iter_pool);
-        if (APR_STATUS_IS_TIMEUP(status))
-            status = APR_SUCCESS;
-        CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-        status = run_test_server(tb->proxy_ctx, 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, num_requests, tb->sent_requests->nelts);
-    CuAssertIntEquals(tc, num_requests, tb->accepted_requests->nelts);
-    CuAssertIntEquals(tc, num_requests, tb->handled_requests->nelts);
-
-
-    /* Check that the requests were sent in the order we created them */
-    for (i = 0; i < tb->sent_requests->nelts; i++) {
-        int req_nr = APR_ARRAY_IDX(tb->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 < tb->handled_requests->nelts; i++) {
-        int req_nr = APR_ARRAY_IDX(tb->handled_requests, i, int);
-        CuAssertIntEquals(tc, i + 1, req_nr);
-    }
-}
-
-/*****************************************************************************
- * 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_status_t status;
-    handler_baton_t handler_ctx[SEND_REQUESTS];
-    int done = FALSE, i;
-
-    test_server_message_t message_list[] = {
-        {CHUNKED_REQUEST(1, "1")},
-        {CHUNKED_REQUEST(1, "1")},
-        {CHUNKED_REQUEST(1, "1")},
-        {CHUNKED_REQUEST(1, "2")},
-        {CHUNKED_REQUEST(1, "3")},
-        {CHUNKED_REQUEST(1, "4")},
-        {CHUNKED_REQUEST(1, "5")},
-    };
-
-    test_server_action_t action_list[] = {
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-    };
-
-    apr_pool_t *test_pool = tc->testBaton;
-
-    /* Set up a test context with a server. */
-    status = test_http_server_setup(&tb,
-                                    message_list, RCVD_REQUESTS,
-                                    action_list, RCVD_REQUESTS, 0, NULL,
-                                    test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    for (i = 0 ; i < SEND_REQUESTS ; i++) {
-        create_new_request_with_resp_hdlr(tb, &handler_ctx[i], "GET", "/", i+1,
-                                          handle_response_keepalive_limit);
-        /* TODO: don't think this needs to be done in the loop. */
-        serf_connection_set_max_outstanding_requests(tb->connection, 1);
-    }
-
-    while (1) {
-        status = run_test_server(tb->serv_ctx, 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, tb->sent_requests->nelts);
-    CuAssertIntEquals(tc, RCVD_REQUESTS, tb->accepted_requests->nelts);
-    CuAssertIntEquals(tc, RCVD_REQUESTS, tb->handled_requests->nelts);
-}
-#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;
-        }
-
-        if (APR_STATUS_IS_EAGAIN(status)) {
-            return status;
-        }
-    }
-
-    return APR_SUCCESS;
-}
-
-static void test_keepalive_limit_one_by_one_and_burst(CuTest *tc)
-{
-    test_baton_t *tb;
-        apr_status_t status;
-    handler_baton_t handler_ctx[SEND_REQUESTS];
-    int done = FALSE, i;
-
-    test_server_message_t message_list[] = {
-        {CHUNKED_REQUEST(1, "1")},
-        {CHUNKED_REQUEST(1, "1")},
-        {CHUNKED_REQUEST(1, "1")},
-        {CHUNKED_REQUEST(1, "2")},
-        {CHUNKED_REQUEST(1, "3")},
-        {CHUNKED_REQUEST(1, "4")},
-        {CHUNKED_REQUEST(1, "5")},
-    };
-
-    test_server_action_t action_list[] = {
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-    };
-
-    apr_pool_t *test_pool = tc->testBaton;
-
-    /* Set up a test context with a server. */
-    status = test_http_server_setup(&tb,
-                                    message_list, RCVD_REQUESTS,
-                                    action_list, RCVD_REQUESTS, 0, NULL,
-                                    test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    for (i = 0 ; i < SEND_REQUESTS ; i++) {
-        create_new_request_with_resp_hdlr(tb, &handler_ctx[i], "GET", "/", i+1,
-                                          handle_response_keepalive_limit_burst);
-        serf_connection_set_max_outstanding_requests(tb->connection, 1);
-    }
-
-    while (1) {
-        status = run_test_server(tb->serv_ctx, 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, tb->sent_requests->nelts);
-    CuAssertIntEquals(tc, RCVD_REQUESTS, tb->accepted_requests->nelts);
-    CuAssertIntEquals(tc, RCVD_REQUESTS, tb->handled_requests->nelts);
-}
-#undef SEND_REQUESTS
-#undef RCVD_REQUESTS
-
-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 apr_status_t progress_conn_setup(apr_socket_t *skt,
-                                          serf_bucket_t **input_bkt,
-                                          serf_bucket_t **output_bkt,
-                                          void *setup_baton,
-                                          apr_pool_t *pool)
-{
-    test_baton_t *tb = setup_baton;
-    *input_bkt = serf_context_bucket_socket_create(tb->context, skt, tb->bkt_alloc);
-    return APR_SUCCESS;
-}
-
-static void test_progress_callback(CuTest *tc)
-{
-    test_baton_t *tb;
-    apr_status_t status;
-    handler_baton_t handler_ctx[5];
-    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-    int i;
-    progress_baton_t *pb;
-
-    test_server_message_t message_list[] = {
-        {CHUNKED_REQUEST(1, "1")},
-        {CHUNKED_REQUEST(1, "2")},
-        {CHUNKED_REQUEST(1, "3")},
-        {CHUNKED_REQUEST(1, "4")},
-        {CHUNKED_REQUEST(1, "5")},
-    };
-
-    test_server_action_t action_list[] = {
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND, CHUNKED_RESPONSE(1, "2")},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-    };
-
-    apr_pool_t *test_pool = tc->testBaton;
-    
-    /* Set up a test context with a server. */
-    status = test_http_server_setup(&tb,
-                                    message_list, num_requests,
-                                    action_list, num_requests, 0,
-                                    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);
-
-    /* Send some requests on the connections */
-    for (i = 0 ; i < num_requests ; i++) {
-        create_new_request(tb, &handler_ctx[i], "GET", "/", i+1);
-    }
-
-    test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
-                                       test_pool);
-
-    /* Check that progress was reported. */
-    CuAssertTrue(tc, pb->written > 0);
-    CuAssertTrue(tc, pb->read > 0);
-}
-
-/* Test that username:password components in url are ignored. */
-static void test_connection_userinfo_in_url(CuTest *tc)
-{
-    test_baton_t *tb;
-    apr_status_t status;
-    handler_baton_t handler_ctx[2];
-    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-    int i;
-    progress_baton_t *pb;
-
-    test_server_message_t message_list[] = {
-        {CHUNKED_REQUEST(1, "1")},
-        {CHUNKED_REQUEST(1, "2")},
-    };
-
-    test_server_action_t action_list[] = {
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        {SERVER_RESPOND, CHUNKED_RESPONSE(1, "2")},
-    };
-
-    apr_pool_t *test_pool = tc->testBaton;
-
-    /* Set up a test context with a server. */
-    status = test_http_server_setup(&tb,
-                                    message_list, num_requests,
-                                    action_list, num_requests, 0,
-                                    progress_conn_setup, test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    /* Create a connection using user:password at hostname syntax */
-    tb->serv_url = "http://user:password@localhost:" SERV_PORT_STR;
-    use_new_connection(tb, test_pool);
-
-    /* Send some requests on the connections */
-    for (i = 0 ; i < num_requests ; i++) {
-        create_new_request(tb, &handler_ctx[i], "GET", "/", i+1);
-    }
-
-    test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
-                                       test_pool);
-}
-
-/*****************************************************************************
- * Issue #91: test that serf correctly handle an incoming 4xx reponse while
- * the outgoing request wasn't written completely yet.
- *****************************************************************************/
-
-#define REQUEST_PART1 "PROPFIND / HTTP/1.1" CRLF\
-"Host: lgo-ubuntu.local" CRLF\
-"User-Agent: SVN/1.8.0-dev (x86_64-apple-darwin11.4.2) serf/2.0.0" CRLF\
-"Content-Type: text/xml" CRLF\
-"Transfer-Encoding: chunked" CRLF \
-CRLF\
-"12d" CRLF\
-"<?xml version=""1.0"" encoding=""utf-8""?><propfind xmlns=""DAV:""><prop>"
-
-#define REQUEST_PART2 \
-"<resourcetype xmlns=""DAV:""/><getcontentlength xmlns=""DAV:""/>"\
-"<deadprop-count xmlns=""http://subversion.tigris.org/xmlns/dav/""/>"\
-"<version-name xmlns=""DAV:""/><creationdate xmlns=""DAV:""/>"\
-"<creator-displayname xmlns=""DAV:""/></prop></propfind>" CRLF\
-"0" CRLF \
-CRLF
-
-#define RESPONSE_408 "HTTP/1.1 408 Request Time-out" CRLF\
-"Date: Wed, 14 Nov 2012 19:50:35 GMT" CRLF\
-"Server: Apache/2.2.17 (Ubuntu)" CRLF\
-"Vary: Accept-Encoding" CRLF\
-"Content-Length: 305" CRLF\
-"Connection: close" CRLF\
-"Content-Type: text/html; charset=iso-8859-1" CRLF \
-CRLF\
-"<!DOCTYPE HTML PUBLIC ""-//IETF//DTD HTML 2.0//EN""><html><head>"\
-"<title>408 Request Time-out</title></head><body><h1>Request Time-out</h1>"\
-"<p>Server timeout waiting for the HTTP request from the client.</p><hr>"\
-"<address>Apache/2.2.17 (Ubuntu) Server at lgo-ubuntu.local Port 80</address>"\
-"</body></html>"
-
-
-static apr_status_t detect_eof(void *baton, serf_bucket_t *aggregate_bucket)
-{
-    serf_bucket_t *body_bkt;
-    handler_baton_t *ctx = baton;
-
-    if (ctx->done) {
-        body_bkt = serf_bucket_simple_create(REQUEST_PART1, strlen(REQUEST_PART2),
-                                             NULL, NULL,
-                                             ctx->tb->bkt_alloc);
-        serf_bucket_aggregate_append(aggregate_bucket, body_bkt);
-    }
-
-    return APR_EAGAIN;
-}
-
-static apr_status_t setup_request_timeout(
-                                  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;
-
-    *req_bkt = serf__bucket_stream_create(serf_request_get_alloc(request),
-                                          detect_eof,
-                                          ctx);
-
-    /* create a simple body text */
-    body_bkt = serf_bucket_simple_create(REQUEST_PART1, strlen(REQUEST_PART1),
-                                         NULL, NULL,
-                                         serf_request_get_alloc(request));
-    serf_bucket_aggregate_append(*req_bkt, body_bkt);
-
-    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_timeout(
-                                    serf_request_t *request,
-                                    serf_bucket_t *response,
-                                    void *handler_baton,
-                                    apr_pool_t *pool)
-{
-    handler_baton_t *ctx = handler_baton;
-    serf_status_line sl;
-    apr_status_t status;
-
-    if (! response) {
-        serf_connection_request_create(ctx->tb->connection,
-                                       setup_request,
-                                       ctx);
-        return APR_SUCCESS;
-    }
-
-    if (serf_request_is_written(request) != APR_EBUSY) {
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    }
-
-
-    status = serf_bucket_response_status(response, &sl);
-    if (SERF_BUCKET_READ_ERROR(status)) {
-        return status;
-    }
-    if (!sl.version && (APR_STATUS_IS_EOF(status) ||
-                        APR_STATUS_IS_EAGAIN(status))) {
-        return status;
-    }
-    if (sl.code == 408) {
-        APR_ARRAY_PUSH(ctx->handled_requests, int) = ctx->req_id;
-        ctx->done = TRUE;
-    }
-
-    /* discard the rest of the body */
-    while (1) {
-        const char *data;
-        apr_size_t len;
-
-        status = serf_bucket_read(response, 2048, &data, &len);
-        if (SERF_BUCKET_READ_ERROR(status) ||
-            APR_STATUS_IS_EAGAIN(status) ||
-            APR_STATUS_IS_EOF(status))
-            return status;
-    }
-
-    return APR_SUCCESS;
-}
-
-static void test_request_timeout(CuTest *tc)
-{
-    test_baton_t *tb;
-        apr_status_t status;
-    handler_baton_t handler_ctx[1];
-    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-
-    test_server_message_t message_list[] = {
-        {REQUEST_PART1},
-        {REQUEST_PART2},
-    };
-
-    test_server_action_t action_list[] = {
-        {SERVER_RESPOND, RESPONSE_408},
-    };
-
-    apr_pool_t *test_pool = tc->testBaton;
-
-    /* Set up a test context with a server. */
-    status = test_http_server_setup(&tb,
-                                    message_list, 2,
-                                    action_list, 1, 0,
-                                    NULL, test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    /* Send some requests on the connection */
-    handler_ctx[0].method = "PROPFIND";
-    handler_ctx[0].path = "/";
-    handler_ctx[0].done = FALSE;
-
-    handler_ctx[0].acceptor = accept_response;
-    handler_ctx[0].acceptor_baton = NULL;
-    handler_ctx[0].handler = handle_response_timeout;
-    handler_ctx[0].req_id = 1;
-    handler_ctx[0].accepted_requests = tb->accepted_requests;
-    handler_ctx[0].sent_requests = tb->sent_requests;
-    handler_ctx[0].handled_requests = tb->handled_requests;
-    handler_ctx[0].tb = tb;
-
-    serf_connection_request_create(tb->connection,
-                                   setup_request_timeout,
-                                   &handler_ctx[0]);
-
-    test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
-                                       test_pool);
-}
-
-static const char *create_large_response_message(apr_pool_t *pool)
-{
-    const char *response = "HTTP/1.1 200 OK" CRLF
-                     "Transfer-Encoding: chunked" CRLF
-                     CRLF;
-    struct iovec vecs[500];
-    const int num_vecs = 500;
-    int i, j;
-    apr_size_t len;
-
-    vecs[0].iov_base = (char *)response;
-    vecs[0].iov_len = strlen(response);
-
-    for (i = 1; i < num_vecs; i++)
-    {
-        int chunk_len = 10 * i * 3;
-        char *chunk;
-        char *buf;
-
-        /* end with empty chunk */
-        if (i == num_vecs - 1)
-            chunk_len = 0;
-
-        buf = apr_pcalloc(pool, chunk_len + 1);
-        for (j = 0; j < chunk_len; j += 10)
-            memcpy(buf + j, "0123456789", 10);
-
-        chunk = apr_pstrcat(pool,
-                            apr_psprintf(pool, "%x", chunk_len),
-                            CRLF, buf, CRLF, NULL);
-        vecs[i].iov_base = chunk;
-        vecs[i].iov_len = strlen(chunk);
-    }
-
-    return apr_pstrcatv(pool, vecs, num_vecs, &len);
-}
-
-/* Validate reading a large chunked response. */
-static void test_connection_large_response(CuTest *tc)
-{
-    test_baton_t *tb;
-    handler_baton_t handler_ctx[1];
-    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-    apr_status_t status;
-    test_server_message_t message_list[] = {
-        {CHUNKED_REQUEST(1, "1")},
-    };
-    test_server_action_t action_list[1];
-
-    apr_pool_t *test_pool = tc->testBaton;
-
-    /* create large chunked response message */
-    const char *response = create_large_response_message(test_pool);
-    action_list[0].kind = SERVER_RESPOND;
-    action_list[0].text = response;
-
-    /* Set up a test context with a server */
-    status = test_http_server_setup(&tb,
-                                    message_list, num_requests,
-                                    action_list, num_requests, 0, NULL,
-                                    test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
-
-    test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
-                                       test_pool);
-}
-
-static const char *create_large_request_message(apr_pool_t *pool)
-{
-    const char *request = "GET / HTTP/1.1" CRLF
-                          "Host: localhost:12345" CRLF
-                          "Transfer-Encoding: chunked" CRLF
-                          CRLF;
-    struct iovec vecs[500];
-    const int num_vecs = 500;
-    int i, j;
-    apr_size_t len;
-
-    vecs[0].iov_base = (char *)request;
-    vecs[0].iov_len = strlen(request);
-
-    for (i = 1; i < num_vecs; i++)
-    {
-        int chunk_len = 10 * i * 3;
-        char *chunk;
-        char *buf;
-
-        /* end with empty chunk */
-        if (i == num_vecs - 1)
-            chunk_len = 0;
-
-        buf = apr_pcalloc(pool, chunk_len + 1);
-        for (j = 0; j < chunk_len; j += 10)
-            memcpy(buf + j, "0123456789", 10);
-
-        chunk = apr_pstrcat(pool,
-                            apr_psprintf(pool, "%x", chunk_len),
-                            CRLF, buf, CRLF, NULL);
-        vecs[i].iov_base = chunk;
-        vecs[i].iov_len = strlen(chunk);
-    }
-
-    return apr_pstrcatv(pool, vecs, num_vecs, &len);
-}
-
-/* Validate sending a large chunked response. */
-static void test_connection_large_request(CuTest *tc)
-{
-    test_baton_t *tb;
-    handler_baton_t handler_ctx[1];
-    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-    test_server_message_t message_list[1];
-    test_server_action_t action_list[] = {
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-    };
-    const char *request;
-    apr_status_t status;
-
-    apr_pool_t *test_pool = tc->testBaton;
-
-    /* Set up a test context with a server */
-    status = test_http_server_setup(&tb,
-                                    message_list, num_requests,
-                                    action_list, num_requests, 0, NULL,
-                                    test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    /* create large chunked request message */
-    request = create_large_request_message(test_pool);
-    message_list[0].text = request;
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
-    handler_ctx[0].request = request;
-
-    test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
-                                       test_pool);
-}
-
-/*****************************************************************************
- * SSL handshake tests
- *****************************************************************************/
-static const char *server_certs[] = {
-    "test/server/serfservercert.pem",
-    "test/server/serfcacert.pem",
-    NULL };
-
-static const char *all_server_certs[] = {
-    "test/server/serfservercert.pem",
-    "test/server/serfcacert.pem",
-    "test/server/serfrootcacert.pem",
-    NULL };
-
-static apr_status_t validate_servercert(const serf_ssl_certificate_t *cert,
-                                        apr_pool_t *pool)
-{
-    apr_hash_t *subject;
-    subject = serf_ssl_cert_subject(cert, pool);
-    if (strcmp("localhost",
-               apr_hash_get(subject, "CN", APR_HASH_KEY_STRING)) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    if (strcmp("Test Suite Server",
-               apr_hash_get(subject, "OU", APR_HASH_KEY_STRING)) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    if (strcmp("In Serf we trust, Inc.",
-               apr_hash_get(subject, "O", APR_HASH_KEY_STRING)) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    if (strcmp("Mechelen",
-               apr_hash_get(subject, "L", APR_HASH_KEY_STRING)) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    if (strcmp("Antwerp",
-               apr_hash_get(subject, "ST", APR_HASH_KEY_STRING)) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    if (strcmp("BE",
-               apr_hash_get(subject, "C", APR_HASH_KEY_STRING)) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    if (strcmp("serfserver at example.com",
-               apr_hash_get(subject, "E", APR_HASH_KEY_STRING)) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t validate_cacert(const serf_ssl_certificate_t *cert,
-                                    apr_pool_t *pool)
-{
-    apr_hash_t *subject;
-    subject = serf_ssl_cert_subject(cert, pool);
-    if (strcmp("Serf CA",
-               apr_hash_get(subject, "CN", APR_HASH_KEY_STRING)) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    if (strcmp("Test Suite CA",
-               apr_hash_get(subject, "OU", APR_HASH_KEY_STRING)) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    if (strcmp("In Serf we trust, Inc.",
-               apr_hash_get(subject, "O", APR_HASH_KEY_STRING)) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    if (strcmp("Mechelen",
-               apr_hash_get(subject, "L", APR_HASH_KEY_STRING)) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    if (strcmp("Antwerp",
-               apr_hash_get(subject, "ST", APR_HASH_KEY_STRING)) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    if (strcmp("BE",
-               apr_hash_get(subject, "C", APR_HASH_KEY_STRING)) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    if (strcmp("serfca at example.com",
-               apr_hash_get(subject, "E", APR_HASH_KEY_STRING)) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t validate_rootcacert(const serf_ssl_certificate_t *cert,
-                                        apr_pool_t *pool)
-{
-    apr_hash_t *subject;
-    subject = serf_ssl_cert_subject(cert, pool);
-    if (strcmp("Serf Root CA",
-               apr_hash_get(subject, "CN", APR_HASH_KEY_STRING)) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    if (strcmp("Test Suite Root CA",
-               apr_hash_get(subject, "OU", APR_HASH_KEY_STRING)) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    if (strcmp("In Serf we trust, Inc.",
-               apr_hash_get(subject, "O", APR_HASH_KEY_STRING)) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    if (strcmp("Mechelen",
-               apr_hash_get(subject, "L", APR_HASH_KEY_STRING)) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    if (strcmp("Antwerp",
-               apr_hash_get(subject, "ST", APR_HASH_KEY_STRING)) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    if (strcmp("BE",
-               apr_hash_get(subject, "C", APR_HASH_KEY_STRING)) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    if (strcmp("serfrootca at example.com",
-               apr_hash_get(subject, "E", APR_HASH_KEY_STRING)) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t
-ssl_server_cert_cb_expect_failures(void *baton, int failures,
-                                   const serf_ssl_certificate_t *cert)
-{
-    test_baton_t *tb = baton;
-    int expected_failures = *(int *)tb->user_baton;
-
-    tb->result_flags |= TEST_RESULT_SERVERCERTCB_CALLED;
-
-    /* We expect an error from the certificate validation function. */
-    if (failures & expected_failures)
-        return APR_SUCCESS;
-    else
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-}
-
-static apr_status_t
-ssl_server_cert_cb_expect_allok(void *baton, int failures,
-                                const serf_ssl_certificate_t *cert)
-{
-    test_baton_t *tb = baton;
-    tb->result_flags |= TEST_RESULT_SERVERCERTCB_CALLED;
-
-    /* No error expected, certificate is valid. */
-    if (failures)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    else
-        return APR_SUCCESS;
-}
-
-static apr_status_t
-ssl_server_cert_cb_reject(void *baton, int failures,
-                          const serf_ssl_certificate_t *cert)
-{
-    return SERF_ERROR_ISSUE_IN_TESTSUITE;
-}
-
-/* Validate that we can connect successfully to an https server. This
-   certificate is not trusted, so a cert validation failure is expected. */
-static void test_ssl_handshake(CuTest *tc)
-{
-    test_baton_t *tb;
-    handler_baton_t handler_ctx[1];
-    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-    int expected_failures;
-    apr_status_t status;
-    test_server_message_t message_list[] = {
-        {CHUNKED_REQUEST(1, "1")},
-    };
-
-    test_server_action_t action_list[] = {
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-    };
-    static const char *server_cert[] = { "test/server/serfservercert.pem",
-        NULL };
-
-
-    /* Set up a test context with a server */
-    apr_pool_t *test_pool = tc->testBaton;
-
-    status = test_https_server_setup(&tb,
-                                     message_list, num_requests,
-                                     action_list, num_requests, 0,
-                                     NULL, /* default conn setup */
-                                     "test/server/serfserverkey.pem",
-                                     server_cert,
-                                     NULL, /* no client cert */
-                                     ssl_server_cert_cb_expect_failures,
-                                     test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    /* This unknown failures is X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE, 
-       meaning the chain has only the server cert. A good candidate for its
-       own failure code. */
-    expected_failures = SERF_SSL_CERT_UNKNOWNCA;
-    tb->user_baton = &expected_failures;
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
-
-    test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
-                                       test_pool);
-}
-
-/* Set up the ssl context with the CA and root CA certificates needed for
-   successful valiation of the server certificate. */
-static apr_status_t
-https_set_root_ca_conn_setup(apr_socket_t *skt,
-                             serf_bucket_t **input_bkt,
-                             serf_bucket_t **output_bkt,
-                             void *setup_baton,
-                             apr_pool_t *pool)
-{
-    serf_ssl_certificate_t *rootcacert;
-    test_baton_t *tb = setup_baton;
-    apr_status_t status;
-
-    status = default_https_conn_setup(skt, input_bkt, output_bkt,
-                                      setup_baton, pool);
-    if (status)
-        return status;
-
-    status = serf_ssl_load_cert_file(&rootcacert,
-                                     "test/server/serfrootcacert.pem",
-                                     pool);
-    if (status)
-        return status;
-    status = serf_ssl_trust_cert(tb->ssl_context, rootcacert);
-    if (status)
-        return status;
-
-    return status;
-}
-
-/* Validate that server certificate validation is ok when we
-   explicitly trust our self-signed root ca. */
-static void test_ssl_trust_rootca(CuTest *tc)
-{
-    test_baton_t *tb;
-    handler_baton_t handler_ctx[1];
-    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-    apr_status_t status;
-    test_server_message_t message_list[] = {
-        {CHUNKED_REQUEST(1, "1")},
-    };
-
-    test_server_action_t action_list[] = {
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-    };
-
-    /* Set up a test context with a server */
-    apr_pool_t *test_pool = tc->testBaton;
-    status = test_https_server_setup(&tb,
-                                     message_list, num_requests,
-                                     action_list, num_requests, 0,
-                                     https_set_root_ca_conn_setup,
-                                     "test/server/serfserverkey.pem",
-                                     server_certs,
-                                     NULL, /* no client cert */
-                                     ssl_server_cert_cb_expect_allok,
-                                     test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
-
-    test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
-                                       test_pool);
-}
-
-/* Validate that when the application rejects the cert, the context loop
-   bails out with an error. */
-static void test_ssl_application_rejects_cert(CuTest *tc)
-{
-    test_baton_t *tb;
-    handler_baton_t handler_ctx[1];
-    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-    apr_status_t status;
-    test_server_message_t message_list[] = {
-        {CHUNKED_REQUEST(1, "1")},
-    };
-
-    test_server_action_t action_list[] = {
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-    };
-
-    /* Set up a test context with a server */
-    apr_pool_t *test_pool = tc->testBaton;
-
-    /* The certificate is valid, but we tell serf to reject it. */
-    status = test_https_server_setup(&tb,
-                                     message_list, num_requests,
-                                     action_list, num_requests, 0,
-                                     https_set_root_ca_conn_setup,
-                                     "test/server/serfserverkey.pem",
-                                     server_certs,
-                                     NULL, /* no client cert */
-                                     ssl_server_cert_cb_reject,
-                                     test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
-
-    status = test_helper_run_requests_no_check(tc, tb, num_requests,
-                                               handler_ctx, test_pool);
-    /* We expect an error from the certificate validation function. */
-    CuAssert(tc, "Application told serf the certificate should be rejected,"
-                 " expected error!", status != APR_SUCCESS);
-}
-
-/* Test for ssl certificate chain callback. */
-static apr_status_t
-cert_chain_cb(void *baton,
-              int failures,
-              int error_depth,
-              const serf_ssl_certificate_t * const * certs,
-              apr_size_t certs_len)
-{
-    test_baton_t *tb = baton;
-    apr_status_t status;
-
-    tb->result_flags |= TEST_RESULT_SERVERCERTCHAINCB_CALLED;
-
-    if (failures)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-
-    if (certs_len != 3)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-
-    status = validate_rootcacert(certs[2], tb->pool);
-    if (status)
-        return status;
-
-    status = validate_cacert(certs[1], tb->pool);
-    if (status)
-        return status;
-
-    status = validate_servercert(certs[0], tb->pool);
-    if (status)
-        return status;
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t
-chain_rootca_callback_conn_setup(apr_socket_t *skt,
-                                 serf_bucket_t **input_bkt,
-                                 serf_bucket_t **output_bkt,
-                                 void *setup_baton,
-                                 apr_pool_t *pool)
-{
-    test_baton_t *tb = setup_baton;
-    apr_status_t status;
-
-    status = https_set_root_ca_conn_setup(skt, input_bkt, output_bkt,
-                                          setup_baton, pool);
-    if (status)
-        return status;
-
-    serf_ssl_server_cert_chain_callback_set(tb->ssl_context,
-                                            ssl_server_cert_cb_expect_allok,
-                                            cert_chain_cb,
-                                            tb);
-
-    return APR_SUCCESS;
-}
-
-/* Make the server return a partial certificate chain (server cert, CA cert),
-   the root CA cert is trusted explicitly in the client. Test the chain
-   callback. */
-static void test_ssl_certificate_chain_with_anchor(CuTest *tc)
-{
-    test_baton_t *tb;
-    handler_baton_t handler_ctx[1];
-    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-    apr_status_t status;
-    test_server_message_t message_list[] = {
-        {CHUNKED_REQUEST(1, "1")},
-    };
-
-    test_server_action_t action_list[] = {
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-    };
-
-    /* Set up a test context with a server */
-    apr_pool_t *test_pool = tc->testBaton;
-
-    status = test_https_server_setup(&tb,
-                                     message_list, num_requests,
-                                     action_list, num_requests, 0,
-                                     chain_rootca_callback_conn_setup,
-                                     "test/server/serfserverkey.pem",
-                                     server_certs,
-                                     NULL, /* no client cert */
-                                     ssl_server_cert_cb_expect_allok,
-                                     test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
-
-    test_helper_run_requests_expect_ok(tc, tb, num_requests,
-                                       handler_ctx, test_pool);
-
-    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_SERVERCERTCB_CALLED);
-    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_SERVERCERTCHAINCB_CALLED);
-}
-
-static apr_status_t
-cert_chain_all_certs_cb(void *baton,
-                        int failures,
-                        int error_depth,
-                        const serf_ssl_certificate_t * const * certs,
-                        apr_size_t certs_len)
-{
-    /* Root CA cert is selfsigned, ignore this 'failure'. */
-    failures &= ~SERF_SSL_CERT_SELF_SIGNED;
-
-    return cert_chain_cb(baton, failures, error_depth, certs, certs_len);
-}
-
-static apr_status_t
-chain_callback_conn_setup(apr_socket_t *skt,
-                          serf_bucket_t **input_bkt,
-                          serf_bucket_t **output_bkt,
-                          void *setup_baton,
-                          apr_pool_t *pool)
-{
-    test_baton_t *tb = setup_baton;
-    apr_status_t status;
-
-    status = default_https_conn_setup(skt, input_bkt, output_bkt,
-                                      setup_baton, pool);
-    if (status)
-        return status;
-
-    serf_ssl_server_cert_chain_callback_set(tb->ssl_context,
-                                            ssl_server_cert_cb_expect_allok,
-                                            cert_chain_all_certs_cb,
-                                            tb);
-
-    return APR_SUCCESS;
-}
-
-/* Make the server return the complete certificate chain (server cert, CA cert
-   and root CA cert). Test the chain callback. */
-static void test_ssl_certificate_chain_all_from_server(CuTest *tc)
-{
-    test_baton_t *tb;
-    handler_baton_t handler_ctx[1];
-    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-    apr_status_t status;
-    test_server_message_t message_list[] = {
-        {CHUNKED_REQUEST(1, "1")},
-    };
-
-    test_server_action_t action_list[] = {
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-    };
-
-    /* Set up a test context with a server */
-    apr_pool_t *test_pool = tc->testBaton;
-
-    status = test_https_server_setup(&tb,
-                                     message_list, num_requests,
-                                     action_list, num_requests, 0,
-                                     chain_callback_conn_setup,
-                                     "test/server/serfserverkey.pem",
-                                     all_server_certs,
-                                     NULL, /* no client cert */
-                                     ssl_server_cert_cb_expect_allok,
-                                     test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
-
-    test_helper_run_requests_expect_ok(tc, tb, num_requests,
-                                       handler_ctx, test_pool);
-
-    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_SERVERCERTCB_CALLED);
-    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_SERVERCERTCHAINCB_CALLED);
-}
-
-/* Validate that the ssl handshake succeeds if no application callbacks
-   are set, and the ssl server certificate chains is ok. */
-static void test_ssl_no_servercert_callback_allok(CuTest *tc)
-{
-    test_baton_t *tb;
-    handler_baton_t handler_ctx[1];
-    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-    test_server_message_t message_list[] = {
-        {CHUNKED_REQUEST(1, "1")},
-    };
-    test_server_action_t action_list[] = {
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-    };
-    apr_status_t status;
-
-    /* Set up a test context with a server */
-    apr_pool_t *test_pool = tc->testBaton;
-
-    status = test_https_server_setup(&tb,
-                                     message_list, num_requests,
-                                     action_list, num_requests, 0,
-                                     https_set_root_ca_conn_setup,
-                                     "test/server/serfserverkey.pem",
-                                     server_certs,
-                                     NULL, /* no client cert */
-                                     NULL, /* No server cert callback */
-                                     test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
-
-    test_helper_run_requests_expect_ok(tc, tb, num_requests,
-                                       handler_ctx, test_pool);
-}
-
-/* Validate that the ssl handshake fails if no application callbacks
- are set, and the ssl server certificate chains is NOT ok. */
-static void test_ssl_no_servercert_callback_fail(CuTest *tc)
-{
-    test_baton_t *tb;
-    handler_baton_t handler_ctx[1];
-    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-    test_server_message_t message_list[] = {
-        {CHUNKED_REQUEST(1, "1")},
-    };
-    test_server_action_t action_list[] = {
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-    };
-    apr_status_t status;
-
-    /* Set up a test context with a server */
-    apr_pool_t *test_pool = tc->testBaton;
-
-    status = test_https_server_setup(&tb,
-                                     message_list, num_requests,
-                                     action_list, num_requests, 0,
-                                     NULL, /* default conn setup, no certs */
-                                     "test/server/serfserverkey.pem",
-                                     server_certs,
-                                     NULL, /* no client cert */
-                                     NULL, /* No server cert callback */
-                                     test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
-
-    status = test_helper_run_requests_no_check(tc, tb, num_requests,
-                                               handler_ctx, test_pool);
-    /* We expect an error from the certificate validation function. */
-    CuAssertIntEquals(tc, SERF_ERROR_SSL_CERT_FAILED, status);
-}
-
-/* Similar to test_connection_large_response, validate reading a large
-   chunked response over SSL. */
-static void test_ssl_large_response(CuTest *tc)
-{
-    test_baton_t *tb;
-    handler_baton_t handler_ctx[1];
-    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-    test_server_message_t message_list[] = {
-        {CHUNKED_REQUEST(1, "1")},
-    };
-    test_server_action_t action_list[1];
-    apr_status_t status;
-
-    /* Set up a test context with a server */
-    apr_pool_t *test_pool = tc->testBaton;
-    const char *response;
-
-    status = test_https_server_setup(&tb,
-                                     message_list, num_requests,
-                                     action_list, num_requests, 0,
-                                     https_set_root_ca_conn_setup,
-                                     "test/server/serfserverkey.pem",
-                                     server_certs,
-                                     NULL, /* no client cert */
-                                     NULL, /* No server cert callback */
-                                     test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    /* create large chunked response message */
-    response = create_large_response_message(test_pool);
-    action_list[0].kind = SERVER_RESPOND;
-    action_list[0].text = response;
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
-
-    test_helper_run_requests_expect_ok(tc, tb, num_requests,
-                                       handler_ctx, test_pool);
-}
-
-/* Similar to test_connection_large_request, validate sending a large
-   chunked request over SSL. */
-static void test_ssl_large_request(CuTest *tc)
-{
-    test_baton_t *tb;
-    handler_baton_t handler_ctx[1];
-    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-    test_server_message_t message_list[1];
-    test_server_action_t action_list[] = {
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-    };
-    const char *request;
-    apr_status_t status;
-
-    /* Set up a test context with a server */
-    apr_pool_t *test_pool = tc->testBaton;
-
-    status = test_https_server_setup(&tb,
-                                     message_list, num_requests,
-                                     action_list, num_requests, 0,
-                                     https_set_root_ca_conn_setup,
-                                     "test/server/serfserverkey.pem",
-                                     server_certs,
-                                     NULL, /* no client cert */
-                                     NULL, /* No server cert callback */
-                                     test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    /* create large chunked request message */
-    request = create_large_request_message(test_pool);
-    message_list[0].text = request;
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
-    handler_ctx[0].request = request;
-
-    test_helper_run_requests_expect_ok(tc, tb, num_requests,
-                                       handler_ctx, test_pool);
-}
-
-static apr_status_t client_cert_cb(void *data, const char **cert_path)
-{
-    test_baton_t *tb = data;
-
-    tb->result_flags |= TEST_RESULT_CLIENT_CERTCB_CALLED;
-
-    *cert_path = "test/server/serfclientcert.p12";
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t client_cert_pw_cb(void *data,
-                                      const char *cert_path,
-                                      const char **password)
-{
-    test_baton_t *tb = data;
-
-    tb->result_flags |= TEST_RESULT_CLIENT_CERTPWCB_CALLED;
-    
-    if (strcmp(cert_path, "test/server/serfclientcert.p12") == 0)
-    {
-        *password = "serftest";
-        return APR_SUCCESS;
-    }
-
-    return SERF_ERROR_ISSUE_IN_TESTSUITE;
-}
-
-static apr_status_t
-client_cert_conn_setup(apr_socket_t *skt,
-                       serf_bucket_t **input_bkt,
-                       serf_bucket_t **output_bkt,
-                       void *setup_baton,
-                       apr_pool_t *pool)
-{
-    test_baton_t *tb = setup_baton;
-    apr_status_t status;
-
-    status = https_set_root_ca_conn_setup(skt, input_bkt, output_bkt,
-                                          setup_baton, pool);
-    if (status)
-        return status;
-
-    serf_ssl_client_cert_provider_set(tb->ssl_context,
-                                      client_cert_cb,
-                                      tb,
-                                      pool);
-
-    serf_ssl_client_cert_password_set(tb->ssl_context,
-                                      client_cert_pw_cb,
-                                      tb,
-                                      pool);
-
-    return APR_SUCCESS;
-}
-
-static void test_ssl_client_certificate(CuTest *tc)
-{
-    test_baton_t *tb;
-    handler_baton_t handler_ctx[1];
-    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-    test_server_message_t message_list[] = {
-        {CHUNKED_REQUEST(1, "1")},
-    };
-    test_server_action_t action_list[] = {
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-    };
-    apr_status_t status;
-
-    /* Set up a test context with a server */
-    apr_pool_t *test_pool = tc->testBaton;
-
-    /* The SSL server the complete certificate chain to validate the client
-       certificate. */
-    status = test_https_server_setup(&tb,
-                                     message_list, num_requests,
-                                     action_list, num_requests, 0,
-                                     client_cert_conn_setup,
-                                     "test/server/serfserverkey.pem",
-                                     all_server_certs,
-                                     "Serf Client",
-                                     NULL, /* No server cert callback */
-                                     test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
-
-    test_helper_run_requests_expect_ok(tc, tb, num_requests,
-                                       handler_ctx, test_pool);
-
-    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_CLIENT_CERTCB_CALLED);
-    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_CLIENT_CERTPWCB_CALLED);
-}
-
-/* Validate that the expired certificate is reported as failure in the
-   callback. */
-static void test_ssl_expired_server_cert(CuTest *tc)
-{
-    test_baton_t *tb;
-    handler_baton_t handler_ctx[1];
-    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-    int expected_failures;
-    apr_status_t status;
-    test_server_message_t message_list[] = {
-        {CHUNKED_REQUEST(1, "1")},
-    };
-
-    test_server_action_t action_list[] = {
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-    };
-    static const char *expired_server_certs[] = {
-        "test/server/serfserver_expired_cert.pem",
-        "test/server/serfcacert.pem",
-        "test/server/serfrootcacert.pem",
-        NULL };
-
-    /* Set up a test context with a server */
-    apr_pool_t *test_pool = tc->testBaton;
-
-    status = test_https_server_setup(&tb,
-                                     message_list, num_requests,
-                                     action_list, num_requests, 0,
-                                     NULL, /* default conn setup */
-                                     "test/server/serfserverkey.pem",
-                                     expired_server_certs,
-                                     NULL, /* no client cert */
-                                     ssl_server_cert_cb_expect_failures,
-                                     test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    expected_failures = SERF_SSL_CERT_SELF_SIGNED |
-                        SERF_SSL_CERT_EXPIRED;
-    tb->user_baton = &expected_failures;
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
-
-    test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
-                                       test_pool);
-}
-
-/* Validate that the expired certificate is reported as failure in the
- callback. */
-static void test_ssl_future_server_cert(CuTest *tc)
-{
-    test_baton_t *tb;
-    handler_baton_t handler_ctx[1];
-    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-    int expected_failures;
-    apr_status_t status;
-    test_server_message_t message_list[] = {
-        {CHUNKED_REQUEST(1, "1")},
-    };
-
-    test_server_action_t action_list[] = {
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-    };
-    static const char *future_server_certs[] = {
-        "test/server/serfserver_future_cert.pem",
-        "test/server/serfcacert.pem",
-        "test/server/serfrootcacert.pem",
-        NULL };
-
-    /* Set up a test context with a server */
-    apr_pool_t *test_pool = tc->testBaton;
-
-    status = test_https_server_setup(&tb,
-                                     message_list, num_requests,
-                                     action_list, num_requests, 0,
-                                     NULL, /* default conn setup */
-                                     "test/server/serfserverkey.pem",
-                                     future_server_certs,
-                                     NULL, /* no client cert */
-                                     ssl_server_cert_cb_expect_failures,
-                                     test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    expected_failures = SERF_SSL_CERT_SELF_SIGNED |
-                        SERF_SSL_CERT_NOTYETVALID;
-    tb->user_baton = &expected_failures;
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
-
-    test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
-                                       test_pool);
-}
-
-
-/* Test if serf is sets up an SSL tunnel to the proxy and doesn't contact the
- https server directly. */
-static void test_setup_ssltunnel(CuTest *tc)
-{
-    test_baton_t *tb;
-    int i;
-    handler_baton_t handler_ctx[1];
-    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-    apr_status_t status;
-
-    /* TODO: issue 83: should be relative uri instead of absolute. */
-    test_server_message_t message_list_server[] = {
-        {"GET / HTTP/1.1" CRLF\
-            "Host: localhost:" SERV_PORT_STR CRLF\
-            "Transfer-Encoding: chunked" CRLF\
-            CRLF\
-            "1" CRLF\
-            "1" CRLF\
-            "0" CRLF\
-            CRLF}
-    };
-    test_server_action_t action_list_server[] = {
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-    };
-    test_server_message_t message_list_proxy[] = {
-        {"CONNECT localhost:" SERV_PORT_STR " HTTP/1.1" CRLF\
-         "Host: localhost:" SERV_PORT_STR CRLF\
-         CRLF },
-        { NULL }
-    };
-    test_server_action_t action_list_proxy[] = {
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        /* Forward the remainder of the data to the server without validation */
-        {PROXY_FORWARD, "https://localhost:" SERV_PORT_STR},
-    };
-
-    apr_pool_t *test_pool = tc->testBaton;
-
-    /* Set up a test context with a server and a proxy. Serf should send a
-       CONNECT request to the server. */
-    status = test_https_server_proxy_setup(&tb,
-                                           /* server messages and actions */
-                                           message_list_server, 1,
-                                           action_list_server, 1,
-                                           /* proxy messages and actions */
-                                           message_list_proxy, 2,
-                                           action_list_proxy, 2,
-                                           0,
-                                           https_set_root_ca_conn_setup,
-                                           "test/server/serfserverkey.pem",
-                                           server_certs,
-                                           NULL, /* no client cert */
-                                           NULL, /* No server cert callback */
-                                           test_pool);
-                                     
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
-
-    test_helper_run_requests_expect_ok(tc, tb, num_requests,
-                                       handler_ctx, test_pool);
-
-    /* Check that the requests were sent in the order we created them */
-    for (i = 0; i < tb->sent_requests->nelts; i++) {
-        int req_nr = APR_ARRAY_IDX(tb->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 < tb->handled_requests->nelts; i++) {
-        int req_nr = APR_ARRAY_IDX(tb->handled_requests, i, int);
-        CuAssertIntEquals(tc, i + 1, req_nr);
-    }
-}
-
-/* Test error if no creds callback */
-static void test_ssltunnel_no_creds_cb(CuTest *tc)
-{
-    test_baton_t *tb;
-    handler_baton_t handler_ctx[1];
-    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-    apr_status_t status;
-
-    test_server_message_t message_list_proxy[] = {
-        {"CONNECT localhost:" SERV_PORT_STR " HTTP/1.1" CRLF\
-            "Host: localhost:" SERV_PORT_STR CRLF\
-            CRLF },
-    };
-    test_server_action_t action_list_proxy[] = {
-        {SERVER_RESPOND, "HTTP/1.1 407 Unauthorized" CRLF
-            "Transfer-Encoding: chunked" CRLF
-            "Proxy-Authenticate: Basic realm=""Test Suite Proxy""" CRLF
-            CRLF
-            "1" CRLF CRLF
-            "0" CRLF CRLF},
-    };
-
-    apr_pool_t *test_pool = tc->testBaton;
-
-    /* Set up a test context with a server and a proxy. Serf should send a
-     CONNECT request to the server. */
-    status = test_https_server_proxy_setup(&tb,
-                                           /* server messages and actions */
-                                           NULL, 0,
-                                           NULL, 0,
-                                           /* proxy messages and actions */
-                                           message_list_proxy, 1,
-                                           action_list_proxy, 1,
-                                           0,
-                                           https_set_root_ca_conn_setup,
-                                           "test/server/serfserverkey.pem",
-                                           server_certs,
-                                           NULL, /* no client cert */
-                                           NULL, /* No server cert callback */
-                                           test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    /* No credentials callback configured. */
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
-
-    status = test_helper_run_requests_no_check(tc, tb, num_requests,
-                                               handler_ctx, test_pool);
-    CuAssertIntEquals(tc, SERF_ERROR_SSLTUNNEL_SETUP_FAILED, status);
-}
-
-static apr_status_t
-ssltunnel_basic_authn_callback(char **username,
-                               char **password,
-                               serf_request_t *request, void *baton,
-                               int code, const char *authn_type,
-                               const char *realm,
-                               apr_pool_t *pool)
-{
-    handler_baton_t *handler_ctx = baton;
-    test_baton_t *tb = handler_ctx->tb;
-
-    serf__log(TEST_VERBOSE, __FILE__, "ssltunnel_basic_authn_callback\n");
-
-    tb->result_flags |= TEST_RESULT_AUTHNCB_CALLED;
-
-    if (strcmp("Basic", authn_type) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-
-    if (code == 401) {
-        if (strcmp("<https://localhost:12345> Test Suite", realm) != 0)
-            return SERF_ERROR_ISSUE_IN_TESTSUITE;
-
-        *username = "serf";
-        *password = "serftest";
-    }
-    else if (code == 407) {
-        if (strcmp("<http://localhost:23456> Test Suite Proxy", realm) != 0)
-            return SERF_ERROR_ISSUE_IN_TESTSUITE;
-
-        *username = "serfproxy";
-        *password = "serftest";
-    } else
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-
-    serf__log(TEST_VERBOSE, __FILE__, "ssltunnel_basic_authn_callback finished successfully.\n");
-
-    return APR_SUCCESS;
-}
-
-/* Test if serf can successfully authenticate to a proxy used for an ssl
-   tunnel. Retry the authentication a few times to test requeueing of the 
-   CONNECT request. */
-static void ssltunnel_basic_auth(CuTest *tc, const char *server_resp_hdrs,
-                                 const char *proxy_407_resp_hdrs,
-                                 const char *proxy_200_resp_hdrs)
-{
-    test_baton_t *tb;
-    handler_baton_t handler_ctx[1];
-    int num_requests_sent, num_requests_recvd;
-    test_server_message_t message_list_server[2];
-    test_server_action_t action_list_proxy[7];
-    test_server_action_t action_list_server[2];
-    apr_pool_t *test_pool = tc->testBaton;
-    apr_status_t status;
-
-    test_server_message_t message_list_proxy[] = {
-        {"CONNECT localhost:" SERV_PORT_STR " HTTP/1.1" CRLF
-            "Host: localhost:" SERV_PORT_STR CRLF
-            CRLF },
-        {"CONNECT localhost:" SERV_PORT_STR " HTTP/1.1" CRLF
-            "Host: localhost:" SERV_PORT_STR CRLF
-            "Proxy-Authorization: Basic c2VyZnByb3h5OnNlcmZ0ZXN0" CRLF
-            CRLF },
-        {"CONNECT localhost:" SERV_PORT_STR " HTTP/1.1" CRLF
-            "Host: localhost:" SERV_PORT_STR CRLF
-            "Proxy-Authorization: Basic c2VyZnByb3h5OnNlcmZ0ZXN0" CRLF
-            CRLF },
-        {"CONNECT localhost:" SERV_PORT_STR " HTTP/1.1" CRLF
-            "Host: localhost:" SERV_PORT_STR CRLF
-            "Proxy-Authorization: Basic c2VyZnByb3h5OnNlcmZ0ZXN0" CRLF
-            CRLF },
-        {"CONNECT localhost:" SERV_PORT_STR " HTTP/1.1" CRLF
-            "Host: localhost:" SERV_PORT_STR CRLF
-            "Proxy-Authorization: Basic c2VyZnByb3h5OnNlcmZ0ZXN0" CRLF
-            CRLF },
-    };
-
-    action_list_proxy[0].kind = SERVER_RESPOND;
-    action_list_proxy[0].text = apr_psprintf(test_pool,
-        "HTTP/1.1 407 Unauthorized" CRLF
-        "Transfer-Encoding: chunked" CRLF
-        "Proxy-Authenticate: Basic realm=""Test Suite Proxy""" CRLF
-        "%s"
-        CRLF
-        "1" CRLF CRLF
-        "0" CRLF CRLF, proxy_407_resp_hdrs);
-    action_list_proxy[1].kind = SERVER_RESPOND;
-    action_list_proxy[1].text = apr_psprintf(test_pool,
-        "HTTP/1.1 407 Unauthorized" CRLF
-        "Transfer-Encoding: chunked" CRLF
-        "Proxy-Authenticate: Basic realm=""Test Suite Proxy""" CRLF
-        "%s"
-        CRLF
-        "1" CRLF CRLF
-        "0" CRLF CRLF, proxy_407_resp_hdrs);
-
-    action_list_proxy[2].kind = SERVER_RESPOND;
-    action_list_proxy[2].text = apr_psprintf(test_pool,
-        "HTTP/1.1 407 Unauthorized" CRLF
-        "Transfer-Encoding: chunked" CRLF
-        "Proxy-Authenticate: Basic realm=""Test Suite Proxy""" CRLF
-        "%s"
-        CRLF
-        "1" CRLF CRLF
-        "0" CRLF CRLF, proxy_407_resp_hdrs);
-
-    action_list_proxy[3].kind = SERVER_RESPOND;
-    action_list_proxy[3].text = apr_psprintf(test_pool,
-        "HTTP/1.1 200 Connection Established" CRLF
-        "%s"
-        CRLF, proxy_200_resp_hdrs);
-    /* Forward the remainder of the data to the server without validation */
-    action_list_proxy[4].kind = PROXY_FORWARD;
-    action_list_proxy[4].text = "https://localhost:" SERV_PORT_STR;
-    /* If the client or the server closes the connection, stop forwarding.*/
-    action_list_proxy[5].kind = SERVER_RESPOND;
-    action_list_proxy[5].text = CHUNKED_EMPTY_RESPONSE;
-    /* Again after disconnect. */
-    action_list_proxy[6].kind = PROXY_FORWARD;
-    action_list_proxy[6].text = "https://localhost:" SERV_PORT_STR;
-
-    /* Make the server also require Basic authentication */
-    message_list_server[0].text =
-        "GET / HTTP/1.1" CRLF
-        "Host: localhost:" SERV_PORT_STR CRLF
-        "Transfer-Encoding: chunked" CRLF
-        CRLF
-        "1" CRLF
-        "1" CRLF
-        "0" CRLF
-        CRLF;
-    message_list_server[1].text =
-        "GET / HTTP/1.1" CRLF
-        "Host: localhost:" SERV_PORT_STR CRLF
-        "Authorization: Basic c2VyZjpzZXJmdGVzdA==" CRLF
-        "Transfer-Encoding: chunked" CRLF
-        CRLF
-        "1" CRLF
-        "1" CRLF
-        "0" CRLF
-        CRLF;
-
-    action_list_server[0].kind = SERVER_RESPOND;
-    action_list_server[0].text = apr_psprintf(test_pool,
-        "HTTP/1.1 401 Unauthorized" CRLF
-        "Transfer-Encoding: chunked" CRLF
-        "WWW-Authenticate: Basic realm=""Test Suite""" CRLF
-        "%s"
-        CRLF
-        "1" CRLF CRLF
-        "0" CRLF CRLF, server_resp_hdrs);
-    action_list_server[1].kind = SERVER_RESPOND;
-    action_list_server[1].text = CHUNKED_EMPTY_RESPONSE;
-
-    /* Set up a test context with a server and a proxy. Serf should send a
-       CONNECT request to the server. */
-    status = test_https_server_proxy_setup(&tb,
-                                           /* server messages and actions */
-                                           message_list_server, 2,
-                                           action_list_server, 2,
-                                           /* proxy messages and actions */
-                                           message_list_proxy, 5,
-                                           action_list_proxy, 7,
-                                           0,
-                                           https_set_root_ca_conn_setup,
-                                           "test/server/serfserverkey.pem",
-                                           server_certs,
-                                           NULL, /* no client cert */
-                                           NULL, /* No server cert callback */
-                                           test_pool);
-
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    serf_config_authn_types(tb->context, SERF_AUTHN_BASIC);
-    serf_config_credentials_callback(tb->context, ssltunnel_basic_authn_callback);
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
-
-    /* Test that a request is retried and authentication headers are set
-     correctly. */
-    num_requests_sent = 1;
-    num_requests_recvd = 2;
-
-    status = test_helper_run_requests_no_check(tc, tb, num_requests_sent,
-                                               handler_ctx, test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-    CuAssertIntEquals(tc, num_requests_recvd, tb->sent_requests->nelts);
-    CuAssertIntEquals(tc, num_requests_recvd, tb->accepted_requests->nelts);
-    CuAssertIntEquals(tc, num_requests_sent, tb->handled_requests->nelts);
-
-    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_AUTHNCB_CALLED);
-}
-
-static void test_ssltunnel_basic_auth(CuTest *tc)
-{
-    /* KeepAlive On for both proxy and server */
-    ssltunnel_basic_auth(tc, "", "", "");
-}
-
-static void test_ssltunnel_basic_auth_server_has_keepalive_off(CuTest *tc)
-{
-    /* Add Connection:Close header to server response */
-    ssltunnel_basic_auth(tc, "Connection: close" CRLF, "", "");
-}
-
-static void test_ssltunnel_basic_auth_proxy_has_keepalive_off(CuTest *tc)
-{
-    /* Add Connection:Close header to proxy 407 response */
-    ssltunnel_basic_auth(tc, "", "Connection: close" CRLF, "");
-}
-
-static void test_ssltunnel_basic_auth_proxy_close_conn_on_200resp(CuTest *tc)
-{
-    /* Add Connection:Close header to proxy 200 Conn. Establ. response  */
-    ssltunnel_basic_auth(tc, "", "", "Connection: close" CRLF);
-}
-
-static apr_status_t
-proxy_digest_authn_callback(char **username,
-                            char **password,
-                            serf_request_t *request, void *baton,
-                            int code, const char *authn_type,
-                            const char *realm,
-                            apr_pool_t *pool)
-{
-    handler_baton_t *handler_ctx = baton;
-    test_baton_t *tb = handler_ctx->tb;
-
-    tb->result_flags |= TEST_RESULT_AUTHNCB_CALLED;
-
-    if (code != 407)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    if (strcmp("Digest", authn_type) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-    if (strcmp("<http://localhost:23456> Test Suite Proxy", realm) != 0)
-        return SERF_ERROR_ISSUE_IN_TESTSUITE;
-
-    *username = "serf";
-    *password = "serftest";
-
-    return APR_SUCCESS;
-}
-
-/* Test if serf can successfully authenticate to a proxy used for an ssl
-   tunnel. */
-static void test_ssltunnel_digest_auth(CuTest *tc)
-{
-    test_baton_t *tb;
-    handler_baton_t handler_ctx[1];
-    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-    apr_status_t status;
-
-    test_server_message_t message_list_server[] = {
-        {"GET /test/index.html HTTP/1.1" CRLF\
-            "Host: localhost:" SERV_PORT_STR CRLF\
-            "Transfer-Encoding: chunked" CRLF\
-            CRLF\
-            "1" CRLF\
-            "1" CRLF\
-            "0" CRLF\
-            CRLF}
-    };
-    test_server_action_t action_list_server[] = {
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-    };
-
-#define CONNECT_REQ\
-    "CONNECT localhost:" SERV_PORT_STR " HTTP/1.1" CRLF\
-    "Host: localhost:" SERV_PORT_STR CRLF
-
-    test_server_message_t message_list_proxy[] = {
-        { CONNECT_REQ CRLF },
-        { CONNECT_REQ
-            "Proxy-Authorization: Digest realm=\"Test Suite Proxy\", "
-            "username=\"serf\", "
-            "nonce=\"ABCDEF1234567890\", uri=\"localhost:" SERV_PORT_STR "\", "
-            "response=\"15b1841822273b0fd44d2f6457f64213\", opaque=\"myopaque\", "
-            "algorithm=\"MD5\"" CRLF
-          CRLF },
-    };
-    /* Add a Basic header before Digest header, to test that serf uses the most
-       secure authentication scheme first, instead of following the order of
-       the headers. */
-    /* Use non standard case for Proxy-Authenticate header to test case
-       insensitivity for http headers. */
-    test_server_action_t action_list_proxy[] = {
-        {SERVER_RESPOND, "HTTP/1.1 407 Unauthorized" CRLF
-            "Transfer-Encoding: chunked" CRLF
-            "Proxy-Authenticate: Basic c2VyZjpzZXJmdGVzdA==" CRLF
-            "Proxy-Authenticate: NonExistent blablablabla" CRLF
-            "proXy-Authenticate: Digest realm=\"Test Suite Proxy\","
-            "nonce=\"ABCDEF1234567890\",opaque=\"myopaque\","
-            "algorithm=\"MD5\",qop-options=\"auth\"" CRLF
-            CRLF
-            "1" CRLF CRLF
-            "0" CRLF CRLF},
-        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
-        /* Forward the remainder of the data to the server without validation */
-        {PROXY_FORWARD, "https://localhost:" SERV_PORT_STR},
-    };
-
-    apr_pool_t *test_pool = tc->testBaton;
-
-    /* Set up a test context with a server and a proxy. Serf should send a
-       CONNECT request to the server. */
-    status = test_https_server_proxy_setup(&tb,
-                                           /* server messages and actions */
-                                           message_list_server, 1,
-                                           action_list_server, 1,
-                                           /* proxy messages and actions */
-                                           message_list_proxy, 2,
-                                           action_list_proxy, 3,
-                                           0,
-                                           https_set_root_ca_conn_setup,
-                                           "test/server/serfserverkey.pem",
-                                           server_certs,
-                                           NULL, /* no client cert */
-                                           NULL, /* No server cert callback */
-                                           test_pool);
-
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    serf_config_authn_types(tb->context, SERF_AUTHN_BASIC | SERF_AUTHN_DIGEST);
-    serf_config_credentials_callback(tb->context, proxy_digest_authn_callback);
-
-    create_new_request(tb, &handler_ctx[0], "GET", "/test/index.html", 1);
-    test_helper_run_requests_expect_ok(tc, tb, num_requests,
-                                       handler_ctx, test_pool);
-
-    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_AUTHNCB_CALLED);
-}
-
-/*****************************************************************************/
-CuSuite *test_context(void)
-{
-    CuSuite *suite = CuSuiteNew();
-
-    CuSuiteSetSetupTeardownCallbacks(suite, test_setup, test_teardown);
-
-    SUITE_ADD_TEST(suite, test_serf_connection_request_create);
-    SUITE_ADD_TEST(suite, test_serf_connection_priority_request_create);
-    SUITE_ADD_TEST(suite, test_closed_connection);
-    SUITE_ADD_TEST(suite, test_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_progress_callback);
-    SUITE_ADD_TEST(suite, test_request_timeout);
-    SUITE_ADD_TEST(suite, test_connection_large_response);
-    SUITE_ADD_TEST(suite, test_connection_large_request);
-    SUITE_ADD_TEST(suite, test_connection_userinfo_in_url);
-    SUITE_ADD_TEST(suite, test_ssl_handshake);
-    SUITE_ADD_TEST(suite, test_ssl_trust_rootca);
-    SUITE_ADD_TEST(suite, test_ssl_application_rejects_cert);
-    SUITE_ADD_TEST(suite, test_ssl_certificate_chain_with_anchor);
-    SUITE_ADD_TEST(suite, test_ssl_certificate_chain_all_from_server);
-    SUITE_ADD_TEST(suite, test_ssl_no_servercert_callback_allok);
-    SUITE_ADD_TEST(suite, test_ssl_no_servercert_callback_fail);
-    SUITE_ADD_TEST(suite, test_ssl_large_response);
-    SUITE_ADD_TEST(suite, test_ssl_large_request);
-    SUITE_ADD_TEST(suite, test_ssl_client_certificate);
-    SUITE_ADD_TEST(suite, test_ssl_expired_server_cert);
-    SUITE_ADD_TEST(suite, test_ssl_future_server_cert);
-    SUITE_ADD_TEST(suite, test_setup_ssltunnel);
-    SUITE_ADD_TEST(suite, test_ssltunnel_no_creds_cb);
-    SUITE_ADD_TEST(suite, test_ssltunnel_basic_auth);
-    SUITE_ADD_TEST(suite, test_ssltunnel_basic_auth_server_has_keepalive_off);
-    SUITE_ADD_TEST(suite, test_ssltunnel_basic_auth_proxy_has_keepalive_off);
-    SUITE_ADD_TEST(suite, test_ssltunnel_basic_auth_proxy_close_conn_on_200resp);
-    SUITE_ADD_TEST(suite, test_ssltunnel_digest_auth);
-
-    return suite;
-}

Copied: vendor/serf/1.3.9/test/test_context.c (from rev 9259, vendor/serf/dist/test/test_context.c)
===================================================================
--- vendor/serf/1.3.9/test/test_context.c	                        (rev 0)
+++ vendor/serf/1.3.9/test/test_context.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,2324 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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 "serf_private.h"
+
+#include "test_serf.h"
+#include "server/test_server.h"
+
+/* 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;
+    handler_baton_t handler_ctx[2];
+    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+    apr_status_t status;
+    int i;
+    test_server_message_t message_list[] = {
+        {CHUNKED_REQUEST(1, "1")},
+        {CHUNKED_REQUEST(1, "2")},
+    };
+
+    test_server_action_t action_list[] = {
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+    };
+
+    apr_pool_t *test_pool = tc->testBaton;
+
+    /* Set up a test context with a server */
+    status = test_http_server_setup(&tb,
+                                    message_list, num_requests,
+                                    action_list, num_requests, 0, NULL,
+                                    test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+    create_new_request(tb, &handler_ctx[1], "GET", "/", 2);
+
+    test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
+                                       test_pool);
+
+    /* Check that the requests were sent in the order we created them */
+    for (i = 0; i < tb->sent_requests->nelts; i++) {
+        int req_nr = APR_ARRAY_IDX(tb->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 < tb->handled_requests->nelts; i++) {
+        int req_nr = APR_ARRAY_IDX(tb->handled_requests, i, int);
+        CuAssertIntEquals(tc, i + 1, req_nr);
+    }
+}
+
+/* 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;
+    handler_baton_t handler_ctx[3];
+    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+    apr_status_t status;
+    int i;
+
+    test_server_message_t message_list[] = {
+        {CHUNKED_REQUEST(1, "1")},
+        {CHUNKED_REQUEST(1, "2")},
+        {CHUNKED_REQUEST(1, "3")},
+    };
+
+    test_server_action_t action_list[] = {
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+    };
+
+    apr_pool_t *test_pool = tc->testBaton;
+
+    /* Set up a test context with a server */
+    status = test_http_server_setup(&tb,
+                                    message_list, num_requests,
+                                    action_list, num_requests, 0, NULL,
+                                    test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 2);
+    create_new_request(tb, &handler_ctx[1], "GET", "/", 3);
+    create_new_prio_request(tb, &handler_ctx[2], "GET", "/", 1);
+
+    test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
+                                       test_pool);
+
+    /* Check that the requests were sent in the order we created them */
+    for (i = 0; i < tb->sent_requests->nelts; i++) {
+        int req_nr = APR_ARRAY_IDX(tb->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 < tb->handled_requests->nelts; i++) {
+        int req_nr = APR_ARRAY_IDX(tb->handled_requests, i, int);
+        CuAssertIntEquals(tc, i + 1, req_nr);
+    }
+}
+
+/* Test that serf correctly handles the 'Connection:close' header when the
+   server is planning to close the connection. */
+static void test_closed_connection(CuTest *tc)
+{
+    test_baton_t *tb;
+    apr_status_t status;
+    handler_baton_t handler_ctx[10];
+    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+    int done = FALSE, i;
+
+    test_server_message_t message_list[] = {
+        {CHUNKED_REQUEST(1, "1")},
+        {CHUNKED_REQUEST(1, "2")},
+        {CHUNKED_REQUEST(1, "3")},
+        {CHUNKED_REQUEST(1, "4")},
+        {CHUNKED_REQUEST(1, "5")},
+        {CHUNKED_REQUEST(1, "6")},
+        {CHUNKED_REQUEST(1, "7")},
+        {CHUNKED_REQUEST(1, "8")},
+        {CHUNKED_REQUEST(1, "9")},
+        {CHUNKED_REQUEST(2, "10")}
+        };
+
+    test_server_action_t action_list[] = {
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND,
+         "HTTP/1.1 200 OK" CRLF
+         "Transfer-Encoding: chunked" CRLF
+         "Connection: close" CRLF
+         CRLF
+         "0" CRLF
+         CRLF
+        },
+        {SERVER_IGNORE_AND_KILL_CONNECTION},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND,
+         "HTTP/1.1 200 OK" CRLF
+         "Transfer-Encoding: chunked" CRLF
+         "Connection: close" CRLF
+         CRLF
+         "0" CRLF
+         CRLF
+        },
+        {SERVER_IGNORE_AND_KILL_CONNECTION},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+    };
+
+    apr_pool_t *test_pool = tc->testBaton;
+
+    /* Set up a test context with a server. */
+    status = test_http_server_setup(&tb,
+                                    message_list, num_requests,
+                                    action_list, 12,
+                                    0,
+                                    NULL,
+                                    test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    /* Send some requests on the connections */
+    for (i = 0 ; i < num_requests ; i++) {
+        create_new_request(tb, &handler_ctx[i], "GET", "/", i+1);
+    }
+
+    while (1) {
+        status = run_test_server(tb->serv_ctx, 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, tb->sent_requests->nelts >= num_requests);
+   CuAssertIntEquals(tc, num_requests, tb->accepted_requests->nelts);
+   CuAssertIntEquals(tc, num_requests, tb->handled_requests->nelts);
+}
+
+/* Test if serf is sending the request to the proxy, not to the server
+   directly. */
+static void test_setup_proxy(CuTest *tc)
+{
+    test_baton_t *tb;
+    int i;
+    handler_baton_t handler_ctx[1];
+    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+    apr_pool_t *iter_pool;
+    apr_status_t status;
+
+    test_server_message_t message_list[] = {
+        {"GET http://localhost:" SERV_PORT_STR " HTTP/1.1" CRLF\
+         "Host: localhost:" SERV_PORT_STR CRLF\
+         "Transfer-Encoding: chunked" CRLF\
+         CRLF\
+         "1" CRLF\
+         "1" CRLF\
+         "0" CRLF\
+         CRLF}
+    };
+
+    test_server_action_t action_list_proxy[] = {
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+    };
+
+    apr_pool_t *test_pool = tc->testBaton;
+
+    /* Set up a test context with a server, no messages expected. */
+    status = test_server_proxy_setup(&tb,
+                                     /* server messages and actions */
+                                     NULL, 0,
+                                     NULL, 0,
+                                     /* server messages and actions */
+                                     message_list, 1,
+                                     action_list_proxy, 1,
+                                     0,
+                                     NULL, test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+
+    apr_pool_create(&iter_pool, test_pool);
+
+    while (!handler_ctx[0].done)
+    {
+        apr_pool_clear(iter_pool);
+
+        status = run_test_server(tb->serv_ctx, 0, iter_pool);
+        if (APR_STATUS_IS_TIMEUP(status))
+            status = APR_SUCCESS;
+        CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+        status = run_test_server(tb->proxy_ctx, 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, num_requests, tb->sent_requests->nelts);
+    CuAssertIntEquals(tc, num_requests, tb->accepted_requests->nelts);
+    CuAssertIntEquals(tc, num_requests, tb->handled_requests->nelts);
+
+
+    /* Check that the requests were sent in the order we created them */
+    for (i = 0; i < tb->sent_requests->nelts; i++) {
+        int req_nr = APR_ARRAY_IDX(tb->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 < tb->handled_requests->nelts; i++) {
+        int req_nr = APR_ARRAY_IDX(tb->handled_requests, i, int);
+        CuAssertIntEquals(tc, i + 1, req_nr);
+    }
+}
+
+/*****************************************************************************
+ * 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_status_t status;
+    handler_baton_t handler_ctx[SEND_REQUESTS];
+    int done = FALSE, i;
+
+    test_server_message_t message_list[] = {
+        {CHUNKED_REQUEST(1, "1")},
+        {CHUNKED_REQUEST(1, "1")},
+        {CHUNKED_REQUEST(1, "1")},
+        {CHUNKED_REQUEST(1, "2")},
+        {CHUNKED_REQUEST(1, "3")},
+        {CHUNKED_REQUEST(1, "4")},
+        {CHUNKED_REQUEST(1, "5")},
+    };
+
+    test_server_action_t action_list[] = {
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+    };
+
+    apr_pool_t *test_pool = tc->testBaton;
+
+    /* Set up a test context with a server. */
+    status = test_http_server_setup(&tb,
+                                    message_list, RCVD_REQUESTS,
+                                    action_list, RCVD_REQUESTS, 0, NULL,
+                                    test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    for (i = 0 ; i < SEND_REQUESTS ; i++) {
+        create_new_request_with_resp_hdlr(tb, &handler_ctx[i], "GET", "/", i+1,
+                                          handle_response_keepalive_limit);
+        /* TODO: don't think this needs to be done in the loop. */
+        serf_connection_set_max_outstanding_requests(tb->connection, 1);
+    }
+
+    while (1) {
+        status = run_test_server(tb->serv_ctx, 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, tb->sent_requests->nelts);
+    CuAssertIntEquals(tc, RCVD_REQUESTS, tb->accepted_requests->nelts);
+    CuAssertIntEquals(tc, RCVD_REQUESTS, tb->handled_requests->nelts);
+}
+#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;
+        }
+
+        if (APR_STATUS_IS_EAGAIN(status)) {
+            return status;
+        }
+    }
+
+    return APR_SUCCESS;
+}
+
+static void test_keepalive_limit_one_by_one_and_burst(CuTest *tc)
+{
+    test_baton_t *tb;
+        apr_status_t status;
+    handler_baton_t handler_ctx[SEND_REQUESTS];
+    int done = FALSE, i;
+
+    test_server_message_t message_list[] = {
+        {CHUNKED_REQUEST(1, "1")},
+        {CHUNKED_REQUEST(1, "1")},
+        {CHUNKED_REQUEST(1, "1")},
+        {CHUNKED_REQUEST(1, "2")},
+        {CHUNKED_REQUEST(1, "3")},
+        {CHUNKED_REQUEST(1, "4")},
+        {CHUNKED_REQUEST(1, "5")},
+    };
+
+    test_server_action_t action_list[] = {
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+    };
+
+    apr_pool_t *test_pool = tc->testBaton;
+
+    /* Set up a test context with a server. */
+    status = test_http_server_setup(&tb,
+                                    message_list, RCVD_REQUESTS,
+                                    action_list, RCVD_REQUESTS, 0, NULL,
+                                    test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    for (i = 0 ; i < SEND_REQUESTS ; i++) {
+        create_new_request_with_resp_hdlr(tb, &handler_ctx[i], "GET", "/", i+1,
+                                          handle_response_keepalive_limit_burst);
+        serf_connection_set_max_outstanding_requests(tb->connection, 1);
+    }
+
+    while (1) {
+        status = run_test_server(tb->serv_ctx, 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, tb->sent_requests->nelts);
+    CuAssertIntEquals(tc, RCVD_REQUESTS, tb->accepted_requests->nelts);
+    CuAssertIntEquals(tc, RCVD_REQUESTS, tb->handled_requests->nelts);
+}
+#undef SEND_REQUESTS
+#undef RCVD_REQUESTS
+
+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 apr_status_t progress_conn_setup(apr_socket_t *skt,
+                                          serf_bucket_t **input_bkt,
+                                          serf_bucket_t **output_bkt,
+                                          void *setup_baton,
+                                          apr_pool_t *pool)
+{
+    test_baton_t *tb = setup_baton;
+    *input_bkt = serf_context_bucket_socket_create(tb->context, skt, tb->bkt_alloc);
+    return APR_SUCCESS;
+}
+
+static void test_progress_callback(CuTest *tc)
+{
+    test_baton_t *tb;
+    apr_status_t status;
+    handler_baton_t handler_ctx[5];
+    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+    int i;
+    progress_baton_t *pb;
+
+    test_server_message_t message_list[] = {
+        {CHUNKED_REQUEST(1, "1")},
+        {CHUNKED_REQUEST(1, "2")},
+        {CHUNKED_REQUEST(1, "3")},
+        {CHUNKED_REQUEST(1, "4")},
+        {CHUNKED_REQUEST(1, "5")},
+    };
+
+    test_server_action_t action_list[] = {
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND, CHUNKED_RESPONSE(1, "2")},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+    };
+
+    apr_pool_t *test_pool = tc->testBaton;
+    
+    /* Set up a test context with a server. */
+    status = test_http_server_setup(&tb,
+                                    message_list, num_requests,
+                                    action_list, num_requests, 0,
+                                    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);
+
+    /* Send some requests on the connections */
+    for (i = 0 ; i < num_requests ; i++) {
+        create_new_request(tb, &handler_ctx[i], "GET", "/", i+1);
+    }
+
+    test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
+                                       test_pool);
+
+    /* Check that progress was reported. */
+    CuAssertTrue(tc, pb->written > 0);
+    CuAssertTrue(tc, pb->read > 0);
+}
+
+/* Test that username:password components in url are ignored. */
+static void test_connection_userinfo_in_url(CuTest *tc)
+{
+    test_baton_t *tb;
+    apr_status_t status;
+    handler_baton_t handler_ctx[2];
+    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+    int i;
+    progress_baton_t *pb;
+
+    test_server_message_t message_list[] = {
+        {CHUNKED_REQUEST(1, "1")},
+        {CHUNKED_REQUEST(1, "2")},
+    };
+
+    test_server_action_t action_list[] = {
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        {SERVER_RESPOND, CHUNKED_RESPONSE(1, "2")},
+    };
+
+    apr_pool_t *test_pool = tc->testBaton;
+
+    /* Set up a test context with a server. */
+    status = test_http_server_setup(&tb,
+                                    message_list, num_requests,
+                                    action_list, num_requests, 0,
+                                    progress_conn_setup, test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    /* Create a connection using user:password at hostname syntax */
+    tb->serv_url = "http://user:password@localhost:" SERV_PORT_STR;
+    use_new_connection(tb, test_pool);
+
+    /* Send some requests on the connections */
+    for (i = 0 ; i < num_requests ; i++) {
+        create_new_request(tb, &handler_ctx[i], "GET", "/", i+1);
+    }
+
+    test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
+                                       test_pool);
+}
+
+/*****************************************************************************
+ * Issue #91: test that serf correctly handle an incoming 4xx reponse while
+ * the outgoing request wasn't written completely yet.
+ *****************************************************************************/
+
+#define REQUEST_PART1 "PROPFIND / HTTP/1.1" CRLF\
+"Host: lgo-ubuntu.local" CRLF\
+"User-Agent: SVN/1.8.0-dev (x86_64-apple-darwin11.4.2) serf/2.0.0" CRLF\
+"Content-Type: text/xml" CRLF\
+"Transfer-Encoding: chunked" CRLF \
+CRLF\
+"12d" CRLF\
+"<?xml version=""1.0"" encoding=""utf-8""?><propfind xmlns=""DAV:""><prop>"
+
+#define REQUEST_PART2 \
+"<resourcetype xmlns=""DAV:""/><getcontentlength xmlns=""DAV:""/>"\
+"<deadprop-count xmlns=""http://subversion.tigris.org/xmlns/dav/""/>"\
+"<version-name xmlns=""DAV:""/><creationdate xmlns=""DAV:""/>"\
+"<creator-displayname xmlns=""DAV:""/></prop></propfind>" CRLF\
+"0" CRLF \
+CRLF
+
+#define RESPONSE_408 "HTTP/1.1 408 Request Time-out" CRLF\
+"Date: Wed, 14 Nov 2012 19:50:35 GMT" CRLF\
+"Server: Apache/2.2.17 (Ubuntu)" CRLF\
+"Vary: Accept-Encoding" CRLF\
+"Content-Length: 305" CRLF\
+"Connection: close" CRLF\
+"Content-Type: text/html; charset=iso-8859-1" CRLF \
+CRLF\
+"<!DOCTYPE HTML PUBLIC ""-//IETF//DTD HTML 2.0//EN""><html><head>"\
+"<title>408 Request Time-out</title></head><body><h1>Request Time-out</h1>"\
+"<p>Server timeout waiting for the HTTP request from the client.</p><hr>"\
+"<address>Apache/2.2.17 (Ubuntu) Server at lgo-ubuntu.local Port 80</address>"\
+"</body></html>"
+
+
+static apr_status_t detect_eof(void *baton, serf_bucket_t *aggregate_bucket)
+{
+    serf_bucket_t *body_bkt;
+    handler_baton_t *ctx = baton;
+
+    if (ctx->done) {
+        body_bkt = serf_bucket_simple_create(REQUEST_PART1, strlen(REQUEST_PART2),
+                                             NULL, NULL,
+                                             ctx->tb->bkt_alloc);
+        serf_bucket_aggregate_append(aggregate_bucket, body_bkt);
+    }
+
+    return APR_EAGAIN;
+}
+
+static apr_status_t setup_request_timeout(
+                                  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;
+
+    *req_bkt = serf__bucket_stream_create(serf_request_get_alloc(request),
+                                          detect_eof,
+                                          ctx);
+
+    /* create a simple body text */
+    body_bkt = serf_bucket_simple_create(REQUEST_PART1, strlen(REQUEST_PART1),
+                                         NULL, NULL,
+                                         serf_request_get_alloc(request));
+    serf_bucket_aggregate_append(*req_bkt, body_bkt);
+
+    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_timeout(
+                                    serf_request_t *request,
+                                    serf_bucket_t *response,
+                                    void *handler_baton,
+                                    apr_pool_t *pool)
+{
+    handler_baton_t *ctx = handler_baton;
+    serf_status_line sl;
+    apr_status_t status;
+
+    if (! response) {
+        serf_connection_request_create(ctx->tb->connection,
+                                       setup_request,
+                                       ctx);
+        return APR_SUCCESS;
+    }
+
+    if (serf_request_is_written(request) != APR_EBUSY) {
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    }
+
+
+    status = serf_bucket_response_status(response, &sl);
+    if (SERF_BUCKET_READ_ERROR(status)) {
+        return status;
+    }
+    if (!sl.version && (APR_STATUS_IS_EOF(status) ||
+                        APR_STATUS_IS_EAGAIN(status))) {
+        return status;
+    }
+    if (sl.code == 408) {
+        APR_ARRAY_PUSH(ctx->handled_requests, int) = ctx->req_id;
+        ctx->done = TRUE;
+    }
+
+    /* discard the rest of the body */
+    while (1) {
+        const char *data;
+        apr_size_t len;
+
+        status = serf_bucket_read(response, 2048, &data, &len);
+        if (SERF_BUCKET_READ_ERROR(status) ||
+            APR_STATUS_IS_EAGAIN(status) ||
+            APR_STATUS_IS_EOF(status))
+            return status;
+    }
+
+    return APR_SUCCESS;
+}
+
+static void test_request_timeout(CuTest *tc)
+{
+    test_baton_t *tb;
+        apr_status_t status;
+    handler_baton_t handler_ctx[1];
+    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+
+    test_server_message_t message_list[] = {
+        {REQUEST_PART1},
+        {REQUEST_PART2},
+    };
+
+    test_server_action_t action_list[] = {
+        {SERVER_RESPOND, RESPONSE_408},
+    };
+
+    apr_pool_t *test_pool = tc->testBaton;
+
+    /* Set up a test context with a server. */
+    status = test_http_server_setup(&tb,
+                                    message_list, 2,
+                                    action_list, 1, 0,
+                                    NULL, test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    /* Send some requests on the connection */
+    handler_ctx[0].method = "PROPFIND";
+    handler_ctx[0].path = "/";
+    handler_ctx[0].done = FALSE;
+
+    handler_ctx[0].acceptor = accept_response;
+    handler_ctx[0].acceptor_baton = NULL;
+    handler_ctx[0].handler = handle_response_timeout;
+    handler_ctx[0].req_id = 1;
+    handler_ctx[0].accepted_requests = tb->accepted_requests;
+    handler_ctx[0].sent_requests = tb->sent_requests;
+    handler_ctx[0].handled_requests = tb->handled_requests;
+    handler_ctx[0].tb = tb;
+
+    serf_connection_request_create(tb->connection,
+                                   setup_request_timeout,
+                                   &handler_ctx[0]);
+
+    test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
+                                       test_pool);
+}
+
+static const char *create_large_response_message(apr_pool_t *pool)
+{
+    const char *response = "HTTP/1.1 200 OK" CRLF
+                     "Transfer-Encoding: chunked" CRLF
+                     CRLF;
+    struct iovec vecs[500];
+    const int num_vecs = 500;
+    int i, j;
+    apr_size_t len;
+
+    vecs[0].iov_base = (char *)response;
+    vecs[0].iov_len = strlen(response);
+
+    for (i = 1; i < num_vecs; i++)
+    {
+        int chunk_len = 10 * i * 3;
+        char *chunk;
+        char *buf;
+
+        /* end with empty chunk */
+        if (i == num_vecs - 1)
+            chunk_len = 0;
+
+        buf = apr_pcalloc(pool, chunk_len + 1);
+        for (j = 0; j < chunk_len; j += 10)
+            memcpy(buf + j, "0123456789", 10);
+
+        chunk = apr_pstrcat(pool,
+                            apr_psprintf(pool, "%x", chunk_len),
+                            CRLF, buf, CRLF, NULL);
+        vecs[i].iov_base = chunk;
+        vecs[i].iov_len = strlen(chunk);
+    }
+
+    return apr_pstrcatv(pool, vecs, num_vecs, &len);
+}
+
+/* Validate reading a large chunked response. */
+static void test_connection_large_response(CuTest *tc)
+{
+    test_baton_t *tb;
+    handler_baton_t handler_ctx[1];
+    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+    apr_status_t status;
+    test_server_message_t message_list[] = {
+        {CHUNKED_REQUEST(1, "1")},
+    };
+    test_server_action_t action_list[1];
+
+    apr_pool_t *test_pool = tc->testBaton;
+
+    /* create large chunked response message */
+    const char *response = create_large_response_message(test_pool);
+    action_list[0].kind = SERVER_RESPOND;
+    action_list[0].text = response;
+
+    /* Set up a test context with a server */
+    status = test_http_server_setup(&tb,
+                                    message_list, num_requests,
+                                    action_list, num_requests, 0, NULL,
+                                    test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+
+    test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
+                                       test_pool);
+}
+
+static const char *create_large_request_message(apr_pool_t *pool)
+{
+    const char *request = "GET / HTTP/1.1" CRLF
+                          "Host: localhost:12345" CRLF
+                          "Transfer-Encoding: chunked" CRLF
+                          CRLF;
+    struct iovec vecs[500];
+    const int num_vecs = 500;
+    int i, j;
+    apr_size_t len;
+
+    vecs[0].iov_base = (char *)request;
+    vecs[0].iov_len = strlen(request);
+
+    for (i = 1; i < num_vecs; i++)
+    {
+        int chunk_len = 10 * i * 3;
+        char *chunk;
+        char *buf;
+
+        /* end with empty chunk */
+        if (i == num_vecs - 1)
+            chunk_len = 0;
+
+        buf = apr_pcalloc(pool, chunk_len + 1);
+        for (j = 0; j < chunk_len; j += 10)
+            memcpy(buf + j, "0123456789", 10);
+
+        chunk = apr_pstrcat(pool,
+                            apr_psprintf(pool, "%x", chunk_len),
+                            CRLF, buf, CRLF, NULL);
+        vecs[i].iov_base = chunk;
+        vecs[i].iov_len = strlen(chunk);
+    }
+
+    return apr_pstrcatv(pool, vecs, num_vecs, &len);
+}
+
+/* Validate sending a large chunked response. */
+static void test_connection_large_request(CuTest *tc)
+{
+    test_baton_t *tb;
+    handler_baton_t handler_ctx[1];
+    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+    test_server_message_t message_list[1];
+    test_server_action_t action_list[] = {
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+    };
+    const char *request;
+    apr_status_t status;
+
+    apr_pool_t *test_pool = tc->testBaton;
+
+    /* Set up a test context with a server */
+    status = test_http_server_setup(&tb,
+                                    message_list, num_requests,
+                                    action_list, num_requests, 0, NULL,
+                                    test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    /* create large chunked request message */
+    request = create_large_request_message(test_pool);
+    message_list[0].text = request;
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+    handler_ctx[0].request = request;
+
+    test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
+                                       test_pool);
+}
+
+/*****************************************************************************
+ * SSL handshake tests
+ *****************************************************************************/
+static const char *server_certs[] = {
+    "test/server/serfservercert.pem",
+    "test/server/serfcacert.pem",
+    NULL };
+
+static const char *all_server_certs[] = {
+    "test/server/serfservercert.pem",
+    "test/server/serfcacert.pem",
+    "test/server/serfrootcacert.pem",
+    NULL };
+
+static const char **server_certs_srcdir(const char **certs,
+                                         apr_pool_t *result_pool)
+{
+  const char **result;
+  int i = 0;
+  while (certs[i])
+    i++;
+
+  result = apr_pcalloc(result_pool, sizeof(result[0]) * (i + 1));
+
+  while (i-- > 0)
+    result[i] = get_srcdir_file(result_pool, certs[i]);
+
+  return result;
+}
+
+static apr_status_t validate_servercert(const serf_ssl_certificate_t *cert,
+                                        apr_pool_t *pool)
+{
+    apr_hash_t *subject;
+    subject = serf_ssl_cert_subject(cert, pool);
+    if (strcmp("localhost",
+               apr_hash_get(subject, "CN", APR_HASH_KEY_STRING)) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    if (strcmp("Test Suite Server",
+               apr_hash_get(subject, "OU", APR_HASH_KEY_STRING)) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    if (strcmp("In Serf we trust, Inc.",
+               apr_hash_get(subject, "O", APR_HASH_KEY_STRING)) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    if (strcmp("Mechelen",
+               apr_hash_get(subject, "L", APR_HASH_KEY_STRING)) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    if (strcmp("Antwerp",
+               apr_hash_get(subject, "ST", APR_HASH_KEY_STRING)) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    if (strcmp("BE",
+               apr_hash_get(subject, "C", APR_HASH_KEY_STRING)) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    if (strcmp("serfserver at example.com",
+               apr_hash_get(subject, "E", APR_HASH_KEY_STRING)) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t validate_cacert(const serf_ssl_certificate_t *cert,
+                                    apr_pool_t *pool)
+{
+    apr_hash_t *subject;
+    subject = serf_ssl_cert_subject(cert, pool);
+    if (strcmp("Serf CA",
+               apr_hash_get(subject, "CN", APR_HASH_KEY_STRING)) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    if (strcmp("Test Suite CA",
+               apr_hash_get(subject, "OU", APR_HASH_KEY_STRING)) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    if (strcmp("In Serf we trust, Inc.",
+               apr_hash_get(subject, "O", APR_HASH_KEY_STRING)) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    if (strcmp("Mechelen",
+               apr_hash_get(subject, "L", APR_HASH_KEY_STRING)) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    if (strcmp("Antwerp",
+               apr_hash_get(subject, "ST", APR_HASH_KEY_STRING)) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    if (strcmp("BE",
+               apr_hash_get(subject, "C", APR_HASH_KEY_STRING)) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    if (strcmp("serfca at example.com",
+               apr_hash_get(subject, "E", APR_HASH_KEY_STRING)) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t validate_rootcacert(const serf_ssl_certificate_t *cert,
+                                        apr_pool_t *pool)
+{
+    apr_hash_t *subject;
+    subject = serf_ssl_cert_subject(cert, pool);
+    if (strcmp("Serf Root CA",
+               apr_hash_get(subject, "CN", APR_HASH_KEY_STRING)) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    if (strcmp("Test Suite Root CA",
+               apr_hash_get(subject, "OU", APR_HASH_KEY_STRING)) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    if (strcmp("In Serf we trust, Inc.",
+               apr_hash_get(subject, "O", APR_HASH_KEY_STRING)) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    if (strcmp("Mechelen",
+               apr_hash_get(subject, "L", APR_HASH_KEY_STRING)) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    if (strcmp("Antwerp",
+               apr_hash_get(subject, "ST", APR_HASH_KEY_STRING)) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    if (strcmp("BE",
+               apr_hash_get(subject, "C", APR_HASH_KEY_STRING)) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    if (strcmp("serfrootca at example.com",
+               apr_hash_get(subject, "E", APR_HASH_KEY_STRING)) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t
+ssl_server_cert_cb_expect_failures(void *baton, int failures,
+                                   const serf_ssl_certificate_t *cert)
+{
+    test_baton_t *tb = baton;
+    int expected_failures = *(int *)tb->user_baton;
+
+    tb->result_flags |= TEST_RESULT_SERVERCERTCB_CALLED;
+
+    /* We expect an error from the certificate validation function. */
+    if (failures & expected_failures)
+        return APR_SUCCESS;
+    else
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+}
+
+static apr_status_t
+ssl_server_cert_cb_expect_allok(void *baton, int failures,
+                                const serf_ssl_certificate_t *cert)
+{
+    test_baton_t *tb = baton;
+    tb->result_flags |= TEST_RESULT_SERVERCERTCB_CALLED;
+
+    /* No error expected, certificate is valid. */
+    if (failures)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    else
+        return APR_SUCCESS;
+}
+
+static apr_status_t
+ssl_server_cert_cb_reject(void *baton, int failures,
+                          const serf_ssl_certificate_t *cert)
+{
+    return SERF_ERROR_ISSUE_IN_TESTSUITE;
+}
+
+/* Validate that we can connect successfully to an https server. This
+   certificate is not trusted, so a cert validation failure is expected. */
+static void test_ssl_handshake(CuTest *tc)
+{
+    test_baton_t *tb;
+    handler_baton_t handler_ctx[1];
+    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+    int expected_failures;
+    apr_status_t status;
+    test_server_message_t message_list[] = {
+        {CHUNKED_REQUEST(1, "1")},
+    };
+
+    test_server_action_t action_list[] = {
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+    };
+    static const char *server_cert[] = { "test/server/serfservercert.pem",
+        NULL };
+
+
+    /* Set up a test context with a server */
+    apr_pool_t *test_pool = tc->testBaton;
+
+    status = test_https_server_setup(&tb,
+                                     message_list, num_requests,
+                                     action_list, num_requests, 0,
+                                     NULL, /* default conn setup */
+                                     get_srcdir_file(test_pool, "test/server/serfserverkey.pem"),
+                                     server_certs_srcdir(server_cert, test_pool),
+                                     NULL, /* no client cert */
+                                     ssl_server_cert_cb_expect_failures,
+                                     test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    /* This unknown failures is X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE, 
+       meaning the chain has only the server cert. A good candidate for its
+       own failure code. */
+    expected_failures = SERF_SSL_CERT_UNKNOWNCA;
+    tb->user_baton = &expected_failures;
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+
+    test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
+                                       test_pool);
+}
+
+/* Set up the ssl context with the CA and root CA certificates needed for
+   successful valiation of the server certificate. */
+static apr_status_t
+https_set_root_ca_conn_setup(apr_socket_t *skt,
+                             serf_bucket_t **input_bkt,
+                             serf_bucket_t **output_bkt,
+                             void *setup_baton,
+                             apr_pool_t *pool)
+{
+    serf_ssl_certificate_t *rootcacert;
+    test_baton_t *tb = setup_baton;
+    apr_status_t status;
+
+    status = default_https_conn_setup(skt, input_bkt, output_bkt,
+                                      setup_baton, pool);
+    if (status)
+        return status;
+
+    status = serf_ssl_load_cert_file(&rootcacert,
+                                     get_srcdir_file(pool,
+                                               "test/server/serfrootcacert.pem"),
+                                     pool);
+    if (status)
+        return status;
+    status = serf_ssl_trust_cert(tb->ssl_context, rootcacert);
+    if (status)
+        return status;
+
+    return status;
+}
+
+/* Validate that server certificate validation is ok when we
+   explicitly trust our self-signed root ca. */
+static void test_ssl_trust_rootca(CuTest *tc)
+{
+    test_baton_t *tb;
+    handler_baton_t handler_ctx[1];
+    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+    apr_status_t status;
+    test_server_message_t message_list[] = {
+        {CHUNKED_REQUEST(1, "1")},
+    };
+
+    test_server_action_t action_list[] = {
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+    };
+
+    /* Set up a test context with a server */
+    apr_pool_t *test_pool = tc->testBaton;
+    status = test_https_server_setup(&tb,
+                                     message_list, num_requests,
+                                     action_list, num_requests, 0,
+                                     https_set_root_ca_conn_setup,
+                                     get_srcdir_file(test_pool, "test/server/serfserverkey.pem"),
+                                     server_certs_srcdir(server_certs, test_pool),
+                                     NULL, /* no client cert */
+                                     ssl_server_cert_cb_expect_allok,
+                                     test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+
+    test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
+                                       test_pool);
+}
+
+/* Validate that when the application rejects the cert, the context loop
+   bails out with an error. */
+static void test_ssl_application_rejects_cert(CuTest *tc)
+{
+    test_baton_t *tb;
+    handler_baton_t handler_ctx[1];
+    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+    apr_status_t status;
+    test_server_message_t message_list[] = {
+        {CHUNKED_REQUEST(1, "1")},
+    };
+
+    test_server_action_t action_list[] = {
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+    };
+
+    /* Set up a test context with a server */
+    apr_pool_t *test_pool = tc->testBaton;
+
+    /* The certificate is valid, but we tell serf to reject it. */
+    status = test_https_server_setup(&tb,
+                                     message_list, num_requests,
+                                     action_list, num_requests, 0,
+                                     https_set_root_ca_conn_setup,
+                                     get_srcdir_file(test_pool, "test/server/serfserverkey.pem"),
+                                     server_certs_srcdir(server_certs, test_pool),
+                                     NULL, /* no client cert */
+                                     ssl_server_cert_cb_reject,
+                                     test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+
+    status = test_helper_run_requests_no_check(tc, tb, num_requests,
+                                               handler_ctx, test_pool);
+    /* We expect an error from the certificate validation function. */
+    CuAssert(tc, "Application told serf the certificate should be rejected,"
+                 " expected error!", status != APR_SUCCESS);
+}
+
+/* Test for ssl certificate chain callback. */
+static apr_status_t
+cert_chain_cb(void *baton,
+              int failures,
+              int error_depth,
+              const serf_ssl_certificate_t * const * certs,
+              apr_size_t certs_len)
+{
+    test_baton_t *tb = baton;
+    apr_status_t status;
+
+    tb->result_flags |= TEST_RESULT_SERVERCERTCHAINCB_CALLED;
+
+    if (failures)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+
+    if (certs_len != 3)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+
+    status = validate_rootcacert(certs[2], tb->pool);
+    if (status)
+        return status;
+
+    status = validate_cacert(certs[1], tb->pool);
+    if (status)
+        return status;
+
+    status = validate_servercert(certs[0], tb->pool);
+    if (status)
+        return status;
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t
+chain_rootca_callback_conn_setup(apr_socket_t *skt,
+                                 serf_bucket_t **input_bkt,
+                                 serf_bucket_t **output_bkt,
+                                 void *setup_baton,
+                                 apr_pool_t *pool)
+{
+    test_baton_t *tb = setup_baton;
+    apr_status_t status;
+
+    status = https_set_root_ca_conn_setup(skt, input_bkt, output_bkt,
+                                          setup_baton, pool);
+    if (status)
+        return status;
+
+    serf_ssl_server_cert_chain_callback_set(tb->ssl_context,
+                                            ssl_server_cert_cb_expect_allok,
+                                            cert_chain_cb,
+                                            tb);
+
+    return APR_SUCCESS;
+}
+
+/* Make the server return a partial certificate chain (server cert, CA cert),
+   the root CA cert is trusted explicitly in the client. Test the chain
+   callback. */
+static void test_ssl_certificate_chain_with_anchor(CuTest *tc)
+{
+    test_baton_t *tb;
+    handler_baton_t handler_ctx[1];
+    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+    apr_status_t status;
+    test_server_message_t message_list[] = {
+        {CHUNKED_REQUEST(1, "1")},
+    };
+
+    test_server_action_t action_list[] = {
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+    };
+
+    /* Set up a test context with a server */
+    apr_pool_t *test_pool = tc->testBaton;
+
+    status = test_https_server_setup(&tb,
+                                     message_list, num_requests,
+                                     action_list, num_requests, 0,
+                                     chain_rootca_callback_conn_setup,
+                                     get_srcdir_file(test_pool, "test/server/serfserverkey.pem"),
+                                     server_certs_srcdir(server_certs, test_pool),
+                                     NULL, /* no client cert */
+                                     ssl_server_cert_cb_expect_allok,
+                                     test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+
+    test_helper_run_requests_expect_ok(tc, tb, num_requests,
+                                       handler_ctx, test_pool);
+
+    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_SERVERCERTCB_CALLED);
+    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_SERVERCERTCHAINCB_CALLED);
+}
+
+static apr_status_t
+cert_chain_all_certs_cb(void *baton,
+                        int failures,
+                        int error_depth,
+                        const serf_ssl_certificate_t * const * certs,
+                        apr_size_t certs_len)
+{
+    /* Root CA cert is selfsigned, ignore this 'failure'. */
+    failures &= ~SERF_SSL_CERT_SELF_SIGNED;
+
+    return cert_chain_cb(baton, failures, error_depth, certs, certs_len);
+}
+
+static apr_status_t
+chain_callback_conn_setup(apr_socket_t *skt,
+                          serf_bucket_t **input_bkt,
+                          serf_bucket_t **output_bkt,
+                          void *setup_baton,
+                          apr_pool_t *pool)
+{
+    test_baton_t *tb = setup_baton;
+    apr_status_t status;
+
+    status = default_https_conn_setup(skt, input_bkt, output_bkt,
+                                      setup_baton, pool);
+    if (status)
+        return status;
+
+    serf_ssl_server_cert_chain_callback_set(tb->ssl_context,
+                                            ssl_server_cert_cb_expect_allok,
+                                            cert_chain_all_certs_cb,
+                                            tb);
+
+    return APR_SUCCESS;
+}
+
+/* Make the server return the complete certificate chain (server cert, CA cert
+   and root CA cert). Test the chain callback. */
+static void test_ssl_certificate_chain_all_from_server(CuTest *tc)
+{
+    test_baton_t *tb;
+    handler_baton_t handler_ctx[1];
+    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+    apr_status_t status;
+    test_server_message_t message_list[] = {
+        {CHUNKED_REQUEST(1, "1")},
+    };
+
+    test_server_action_t action_list[] = {
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+    };
+
+    /* Set up a test context with a server */
+    apr_pool_t *test_pool = tc->testBaton;
+
+    status = test_https_server_setup(&tb,
+                                     message_list, num_requests,
+                                     action_list, num_requests, 0,
+                                     chain_callback_conn_setup,
+                                     get_srcdir_file(test_pool, "test/server/serfserverkey.pem"),
+                                     server_certs_srcdir(all_server_certs, test_pool),
+                                     NULL, /* no client cert */
+                                     ssl_server_cert_cb_expect_allok,
+                                     test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+
+    test_helper_run_requests_expect_ok(tc, tb, num_requests,
+                                       handler_ctx, test_pool);
+
+    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_SERVERCERTCB_CALLED);
+    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_SERVERCERTCHAINCB_CALLED);
+}
+
+/* Validate that the ssl handshake succeeds if no application callbacks
+   are set, and the ssl server certificate chains is ok. */
+static void test_ssl_no_servercert_callback_allok(CuTest *tc)
+{
+    test_baton_t *tb;
+    handler_baton_t handler_ctx[1];
+    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+    test_server_message_t message_list[] = {
+        {CHUNKED_REQUEST(1, "1")},
+    };
+    test_server_action_t action_list[] = {
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+    };
+    apr_status_t status;
+
+    /* Set up a test context with a server */
+    apr_pool_t *test_pool = tc->testBaton;
+
+    status = test_https_server_setup(&tb,
+                                     message_list, num_requests,
+                                     action_list, num_requests, 0,
+                                     https_set_root_ca_conn_setup,
+                                     get_srcdir_file(test_pool, "test/server/serfserverkey.pem"),
+                                     server_certs_srcdir(server_certs, test_pool),
+                                     NULL, /* no client cert */
+                                     NULL, /* No server cert callback */
+                                     test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+
+    test_helper_run_requests_expect_ok(tc, tb, num_requests,
+                                       handler_ctx, test_pool);
+}
+
+/* Validate that the ssl handshake fails if no application callbacks
+ are set, and the ssl server certificate chains is NOT ok. */
+static void test_ssl_no_servercert_callback_fail(CuTest *tc)
+{
+    test_baton_t *tb;
+    handler_baton_t handler_ctx[1];
+    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+    test_server_message_t message_list[] = {
+        {CHUNKED_REQUEST(1, "1")},
+    };
+    test_server_action_t action_list[] = {
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+    };
+    apr_status_t status;
+
+    /* Set up a test context with a server */
+    apr_pool_t *test_pool = tc->testBaton;
+
+    status = test_https_server_setup(&tb,
+                                     message_list, num_requests,
+                                     action_list, num_requests, 0,
+                                     NULL, /* default conn setup, no certs */
+                                     get_srcdir_file(test_pool, "test/server/serfserverkey.pem"),
+                                     server_certs_srcdir(server_certs, test_pool),
+                                     NULL, /* no client cert */
+                                     NULL, /* No server cert callback */
+                                     test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+
+    status = test_helper_run_requests_no_check(tc, tb, num_requests,
+                                               handler_ctx, test_pool);
+    /* We expect an error from the certificate validation function. */
+    CuAssertIntEquals(tc, SERF_ERROR_SSL_CERT_FAILED, status);
+}
+
+/* Similar to test_connection_large_response, validate reading a large
+   chunked response over SSL. */
+static void test_ssl_large_response(CuTest *tc)
+{
+    test_baton_t *tb;
+    handler_baton_t handler_ctx[1];
+    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+    test_server_message_t message_list[] = {
+        {CHUNKED_REQUEST(1, "1")},
+    };
+    test_server_action_t action_list[1];
+    apr_status_t status;
+
+    /* Set up a test context with a server */
+    apr_pool_t *test_pool = tc->testBaton;
+    const char *response;
+
+    status = test_https_server_setup(&tb,
+                                     message_list, num_requests,
+                                     action_list, num_requests, 0,
+                                     https_set_root_ca_conn_setup,
+                                     get_srcdir_file(test_pool, "test/server/serfserverkey.pem"),
+                                     server_certs_srcdir(server_certs, test_pool),
+                                     NULL, /* no client cert */
+                                     NULL, /* No server cert callback */
+                                     test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    /* create large chunked response message */
+    response = create_large_response_message(test_pool);
+    action_list[0].kind = SERVER_RESPOND;
+    action_list[0].text = response;
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+
+    test_helper_run_requests_expect_ok(tc, tb, num_requests,
+                                       handler_ctx, test_pool);
+}
+
+/* Similar to test_connection_large_request, validate sending a large
+   chunked request over SSL. */
+static void test_ssl_large_request(CuTest *tc)
+{
+    test_baton_t *tb;
+    handler_baton_t handler_ctx[1];
+    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+    test_server_message_t message_list[1];
+    test_server_action_t action_list[] = {
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+    };
+    const char *request;
+    apr_status_t status;
+
+    /* Set up a test context with a server */
+    apr_pool_t *test_pool = tc->testBaton;
+
+    status = test_https_server_setup(&tb,
+                                     message_list, num_requests,
+                                     action_list, num_requests, 0,
+                                     https_set_root_ca_conn_setup,
+                                     get_srcdir_file(test_pool, "test/server/serfserverkey.pem"),
+                                     server_certs_srcdir(server_certs, test_pool),
+                                     NULL, /* no client cert */
+                                     NULL, /* No server cert callback */
+                                     test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    /* create large chunked request message */
+    request = create_large_request_message(test_pool);
+    message_list[0].text = request;
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+    handler_ctx[0].request = request;
+
+    test_helper_run_requests_expect_ok(tc, tb, num_requests,
+                                       handler_ctx, test_pool);
+}
+
+static apr_status_t client_cert_cb(void *data, const char **cert_path)
+{
+    test_baton_t *tb = data;
+
+    tb->result_flags |= TEST_RESULT_CLIENT_CERTCB_CALLED;
+
+    *cert_path = get_srcdir_file(tb->pool, "test/server/serfclientcert.p12");
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t client_cert_pw_cb(void *data,
+                                      const char *cert_path,
+                                      const char **password)
+{
+    test_baton_t *tb = data;
+
+    tb->result_flags |= TEST_RESULT_CLIENT_CERTPWCB_CALLED;
+    if (strcmp(cert_path,
+               get_srcdir_file(tb->pool, "test/server/serfclientcert.p12")) == 0)
+    {
+        *password = "serftest";
+        return APR_SUCCESS;
+    }
+
+    return SERF_ERROR_ISSUE_IN_TESTSUITE;
+}
+
+static apr_status_t
+client_cert_conn_setup(apr_socket_t *skt,
+                       serf_bucket_t **input_bkt,
+                       serf_bucket_t **output_bkt,
+                       void *setup_baton,
+                       apr_pool_t *pool)
+{
+    test_baton_t *tb = setup_baton;
+    apr_status_t status;
+
+    status = https_set_root_ca_conn_setup(skt, input_bkt, output_bkt,
+                                          setup_baton, pool);
+    if (status)
+        return status;
+
+    serf_ssl_client_cert_provider_set(tb->ssl_context,
+                                      client_cert_cb,
+                                      tb,
+                                      pool);
+
+    serf_ssl_client_cert_password_set(tb->ssl_context,
+                                      client_cert_pw_cb,
+                                      tb,
+                                      pool);
+
+    return APR_SUCCESS;
+}
+
+static void test_ssl_client_certificate(CuTest *tc)
+{
+    test_baton_t *tb;
+    handler_baton_t handler_ctx[1];
+    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+    test_server_message_t message_list[] = {
+        {CHUNKED_REQUEST(1, "1")},
+    };
+    test_server_action_t action_list[] = {
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+    };
+    apr_status_t status;
+
+    /* Set up a test context with a server */
+    apr_pool_t *test_pool = tc->testBaton;
+
+    /* The SSL server the complete certificate chain to validate the client
+       certificate. */
+    status = test_https_server_setup(&tb,
+                                     message_list, num_requests,
+                                     action_list, num_requests, 0,
+                                     client_cert_conn_setup,
+                                     get_srcdir_file(test_pool, "test/server/serfserverkey.pem"),
+                                     server_certs_srcdir(all_server_certs, test_pool),
+                                     "Serf Client",
+                                     NULL, /* No server cert callback */
+                                     test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+
+    test_helper_run_requests_expect_ok(tc, tb, num_requests,
+                                       handler_ctx, test_pool);
+
+    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_CLIENT_CERTCB_CALLED);
+    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_CLIENT_CERTPWCB_CALLED);
+}
+
+/* Validate that the expired certificate is reported as failure in the
+   callback. */
+static void test_ssl_expired_server_cert(CuTest *tc)
+{
+    test_baton_t *tb;
+    handler_baton_t handler_ctx[1];
+    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+    int expected_failures;
+    apr_status_t status;
+    test_server_message_t message_list[] = {
+        {CHUNKED_REQUEST(1, "1")},
+    };
+
+    test_server_action_t action_list[] = {
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+    };
+    static const char *expired_server_certs[] = {
+        "test/server/serfserver_expired_cert.pem",
+        "test/server/serfcacert.pem",
+        "test/server/serfrootcacert.pem",
+        NULL };
+
+    /* Set up a test context with a server */
+    apr_pool_t *test_pool = tc->testBaton;
+
+    status = test_https_server_setup(&tb,
+                                     message_list, num_requests,
+                                     action_list, num_requests, 0,
+                                     NULL, /* default conn setup */
+                                     get_srcdir_file(test_pool, "test/server/serfserverkey.pem"),
+                                     server_certs_srcdir(expired_server_certs, test_pool),
+                                     NULL, /* no client cert */
+                                     ssl_server_cert_cb_expect_failures,
+                                     test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    expected_failures = SERF_SSL_CERT_SELF_SIGNED |
+                        SERF_SSL_CERT_EXPIRED;
+    tb->user_baton = &expected_failures;
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+
+    test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
+                                       test_pool);
+}
+
+/* Validate that the expired certificate is reported as failure in the
+ callback. */
+static void test_ssl_future_server_cert(CuTest *tc)
+{
+    test_baton_t *tb;
+    handler_baton_t handler_ctx[1];
+    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+    int expected_failures;
+    apr_status_t status;
+    test_server_message_t message_list[] = {
+        {CHUNKED_REQUEST(1, "1")},
+    };
+
+    test_server_action_t action_list[] = {
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+    };
+    static const char *future_server_certs[] = {
+        "test/server/serfserver_future_cert.pem",
+        "test/server/serfcacert.pem",
+        "test/server/serfrootcacert.pem",
+        NULL };
+
+    /* Set up a test context with a server */
+    apr_pool_t *test_pool = tc->testBaton;
+
+    status = test_https_server_setup(&tb,
+                                     message_list, num_requests,
+                                     action_list, num_requests, 0,
+                                     NULL, /* default conn setup */
+                                     get_srcdir_file(test_pool, "test/server/serfserverkey.pem"),
+                                     server_certs_srcdir(future_server_certs, test_pool),
+                                     NULL, /* no client cert */
+                                     ssl_server_cert_cb_expect_failures,
+                                     test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    expected_failures = SERF_SSL_CERT_SELF_SIGNED |
+                        SERF_SSL_CERT_NOTYETVALID;
+    tb->user_baton = &expected_failures;
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+
+    test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
+                                       test_pool);
+}
+
+
+/* Test if serf is sets up an SSL tunnel to the proxy and doesn't contact the
+ https server directly. */
+static void test_setup_ssltunnel(CuTest *tc)
+{
+    test_baton_t *tb;
+    int i;
+    handler_baton_t handler_ctx[1];
+    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+    apr_status_t status;
+
+    /* TODO: issue 83: should be relative uri instead of absolute. */
+    test_server_message_t message_list_server[] = {
+        {"GET / HTTP/1.1" CRLF\
+            "Host: localhost:" SERV_PORT_STR CRLF\
+            "Transfer-Encoding: chunked" CRLF\
+            CRLF\
+            "1" CRLF\
+            "1" CRLF\
+            "0" CRLF\
+            CRLF}
+    };
+    test_server_action_t action_list_server[] = {
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+    };
+    test_server_message_t message_list_proxy[] = {
+        {"CONNECT localhost:" SERV_PORT_STR " HTTP/1.1" CRLF\
+         "Host: localhost:" SERV_PORT_STR CRLF\
+         CRLF },
+        { NULL }
+    };
+    test_server_action_t action_list_proxy[] = {
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        /* Forward the remainder of the data to the server without validation */
+        {PROXY_FORWARD, "https://localhost:" SERV_PORT_STR},
+    };
+
+    apr_pool_t *test_pool = tc->testBaton;
+
+    /* Set up a test context with a server and a proxy. Serf should send a
+       CONNECT request to the server. */
+    status = test_https_server_proxy_setup(&tb,
+                                           /* server messages and actions */
+                                           message_list_server, 1,
+                                           action_list_server, 1,
+                                           /* proxy messages and actions */
+                                           message_list_proxy, 2,
+                                           action_list_proxy, 2,
+                                           0,
+                                           https_set_root_ca_conn_setup,
+                                           get_srcdir_file(test_pool, "test/server/serfserverkey.pem"),
+                                           server_certs_srcdir(server_certs, test_pool),
+                                           NULL, /* no client cert */
+                                           NULL, /* No server cert callback */
+                                           test_pool);
+                                     
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+
+    test_helper_run_requests_expect_ok(tc, tb, num_requests,
+                                       handler_ctx, test_pool);
+
+    /* Check that the requests were sent in the order we created them */
+    for (i = 0; i < tb->sent_requests->nelts; i++) {
+        int req_nr = APR_ARRAY_IDX(tb->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 < tb->handled_requests->nelts; i++) {
+        int req_nr = APR_ARRAY_IDX(tb->handled_requests, i, int);
+        CuAssertIntEquals(tc, i + 1, req_nr);
+    }
+}
+
+/* Test error if no creds callback */
+static void test_ssltunnel_no_creds_cb(CuTest *tc)
+{
+    test_baton_t *tb;
+    handler_baton_t handler_ctx[1];
+    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+    apr_status_t status;
+
+    test_server_message_t message_list_proxy[] = {
+        {"CONNECT localhost:" SERV_PORT_STR " HTTP/1.1" CRLF\
+            "Host: localhost:" SERV_PORT_STR CRLF\
+            CRLF },
+    };
+    test_server_action_t action_list_proxy[] = {
+        {SERVER_RESPOND, "HTTP/1.1 407 Unauthorized" CRLF
+            "Transfer-Encoding: chunked" CRLF
+            "Proxy-Authenticate: Basic realm=""Test Suite Proxy""" CRLF
+            CRLF
+            "1" CRLF CRLF
+            "0" CRLF CRLF},
+    };
+
+    apr_pool_t *test_pool = tc->testBaton;
+
+    /* Set up a test context with a server and a proxy. Serf should send a
+     CONNECT request to the server. */
+    status = test_https_server_proxy_setup(&tb,
+                                           /* server messages and actions */
+                                           NULL, 0,
+                                           NULL, 0,
+                                           /* proxy messages and actions */
+                                           message_list_proxy, 1,
+                                           action_list_proxy, 1,
+                                           0,
+                                           https_set_root_ca_conn_setup,
+                                           get_srcdir_file(test_pool, "test/server/serfserverkey.pem"),
+                                           server_certs_srcdir(server_certs, test_pool),
+                                           NULL, /* no client cert */
+                                           NULL, /* No server cert callback */
+                                           test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    /* No credentials callback configured. */
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+
+    status = test_helper_run_requests_no_check(tc, tb, num_requests,
+                                               handler_ctx, test_pool);
+    CuAssertIntEquals(tc, SERF_ERROR_SSLTUNNEL_SETUP_FAILED, status);
+}
+
+static apr_status_t
+ssltunnel_basic_authn_callback(char **username,
+                               char **password,
+                               serf_request_t *request, void *baton,
+                               int code, const char *authn_type,
+                               const char *realm,
+                               apr_pool_t *pool)
+{
+    handler_baton_t *handler_ctx = baton;
+    test_baton_t *tb = handler_ctx->tb;
+
+    serf__log(TEST_VERBOSE, __FILE__, "ssltunnel_basic_authn_callback\n");
+
+    tb->result_flags |= TEST_RESULT_AUTHNCB_CALLED;
+
+    if (strcmp("Basic", authn_type) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+
+    if (code == 401) {
+        if (strcmp("<https://localhost:12345> Test Suite", realm) != 0)
+            return SERF_ERROR_ISSUE_IN_TESTSUITE;
+
+        *username = "serf";
+        *password = "serftest";
+    }
+    else if (code == 407) {
+        if (strcmp("<http://localhost:23456> Test Suite Proxy", realm) != 0)
+            return SERF_ERROR_ISSUE_IN_TESTSUITE;
+
+        *username = "serfproxy";
+        *password = "serftest";
+    } else
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+
+    serf__log(TEST_VERBOSE, __FILE__, "ssltunnel_basic_authn_callback finished successfully.\n");
+
+    return APR_SUCCESS;
+}
+
+/* Test if serf can successfully authenticate to a proxy used for an ssl
+   tunnel. Retry the authentication a few times to test requeueing of the 
+   CONNECT request. */
+static void ssltunnel_basic_auth(CuTest *tc, const char *server_resp_hdrs,
+                                 const char *proxy_407_resp_hdrs,
+                                 const char *proxy_200_resp_hdrs)
+{
+    test_baton_t *tb;
+    handler_baton_t handler_ctx[1];
+    int num_requests_sent, num_requests_recvd;
+    test_server_message_t message_list_server[2];
+    test_server_action_t action_list_proxy[7];
+    test_server_action_t action_list_server[2];
+    apr_pool_t *test_pool = tc->testBaton;
+    apr_status_t status;
+
+    test_server_message_t message_list_proxy[] = {
+        {"CONNECT localhost:" SERV_PORT_STR " HTTP/1.1" CRLF
+            "Host: localhost:" SERV_PORT_STR CRLF
+            CRLF },
+        {"CONNECT localhost:" SERV_PORT_STR " HTTP/1.1" CRLF
+            "Host: localhost:" SERV_PORT_STR CRLF
+            "Proxy-Authorization: Basic c2VyZnByb3h5OnNlcmZ0ZXN0" CRLF
+            CRLF },
+        {"CONNECT localhost:" SERV_PORT_STR " HTTP/1.1" CRLF
+            "Host: localhost:" SERV_PORT_STR CRLF
+            "Proxy-Authorization: Basic c2VyZnByb3h5OnNlcmZ0ZXN0" CRLF
+            CRLF },
+        {"CONNECT localhost:" SERV_PORT_STR " HTTP/1.1" CRLF
+            "Host: localhost:" SERV_PORT_STR CRLF
+            "Proxy-Authorization: Basic c2VyZnByb3h5OnNlcmZ0ZXN0" CRLF
+            CRLF },
+        {"CONNECT localhost:" SERV_PORT_STR " HTTP/1.1" CRLF
+            "Host: localhost:" SERV_PORT_STR CRLF
+            "Proxy-Authorization: Basic c2VyZnByb3h5OnNlcmZ0ZXN0" CRLF
+            CRLF },
+    };
+
+    action_list_proxy[0].kind = SERVER_RESPOND;
+    action_list_proxy[0].text = apr_psprintf(test_pool,
+        "HTTP/1.1 407 Unauthorized" CRLF
+        "Transfer-Encoding: chunked" CRLF
+        "Proxy-Authenticate: Basic realm=""Test Suite Proxy""" CRLF
+        "%s"
+        CRLF
+        "1" CRLF CRLF
+        "0" CRLF CRLF, proxy_407_resp_hdrs);
+    action_list_proxy[1].kind = SERVER_RESPOND;
+    action_list_proxy[1].text = apr_psprintf(test_pool,
+        "HTTP/1.1 407 Unauthorized" CRLF
+        "Transfer-Encoding: chunked" CRLF
+        "Proxy-Authenticate: Basic realm=""Test Suite Proxy""" CRLF
+        "%s"
+        CRLF
+        "1" CRLF CRLF
+        "0" CRLF CRLF, proxy_407_resp_hdrs);
+
+    action_list_proxy[2].kind = SERVER_RESPOND;
+    action_list_proxy[2].text = apr_psprintf(test_pool,
+        "HTTP/1.1 407 Unauthorized" CRLF
+        "Transfer-Encoding: chunked" CRLF
+        "Proxy-Authenticate: Basic realm=""Test Suite Proxy""" CRLF
+        "%s"
+        CRLF
+        "1" CRLF CRLF
+        "0" CRLF CRLF, proxy_407_resp_hdrs);
+
+    action_list_proxy[3].kind = SERVER_RESPOND;
+    action_list_proxy[3].text = apr_psprintf(test_pool,
+        "HTTP/1.1 200 Connection Established" CRLF
+        "%s"
+        CRLF, proxy_200_resp_hdrs);
+    /* Forward the remainder of the data to the server without validation */
+    action_list_proxy[4].kind = PROXY_FORWARD;
+    action_list_proxy[4].text = "https://localhost:" SERV_PORT_STR;
+    /* If the client or the server closes the connection, stop forwarding.*/
+    action_list_proxy[5].kind = SERVER_RESPOND;
+    action_list_proxy[5].text = CHUNKED_EMPTY_RESPONSE;
+    /* Again after disconnect. */
+    action_list_proxy[6].kind = PROXY_FORWARD;
+    action_list_proxy[6].text = "https://localhost:" SERV_PORT_STR;
+
+    /* Make the server also require Basic authentication */
+    message_list_server[0].text =
+        "GET / HTTP/1.1" CRLF
+        "Host: localhost:" SERV_PORT_STR CRLF
+        "Transfer-Encoding: chunked" CRLF
+        CRLF
+        "1" CRLF
+        "1" CRLF
+        "0" CRLF
+        CRLF;
+    message_list_server[1].text =
+        "GET / HTTP/1.1" CRLF
+        "Host: localhost:" SERV_PORT_STR CRLF
+        "Authorization: Basic c2VyZjpzZXJmdGVzdA==" CRLF
+        "Transfer-Encoding: chunked" CRLF
+        CRLF
+        "1" CRLF
+        "1" CRLF
+        "0" CRLF
+        CRLF;
+
+    action_list_server[0].kind = SERVER_RESPOND;
+    action_list_server[0].text = apr_psprintf(test_pool,
+        "HTTP/1.1 401 Unauthorized" CRLF
+        "Transfer-Encoding: chunked" CRLF
+        "WWW-Authenticate: Basic realm=""Test Suite""" CRLF
+        "%s"
+        CRLF
+        "1" CRLF CRLF
+        "0" CRLF CRLF, server_resp_hdrs);
+    action_list_server[1].kind = SERVER_RESPOND;
+    action_list_server[1].text = CHUNKED_EMPTY_RESPONSE;
+
+    /* Set up a test context with a server and a proxy. Serf should send a
+       CONNECT request to the server. */
+    status = test_https_server_proxy_setup(&tb,
+                                           /* server messages and actions */
+                                           message_list_server, 2,
+                                           action_list_server, 2,
+                                           /* proxy messages and actions */
+                                           message_list_proxy, 5,
+                                           action_list_proxy, 7,
+                                           0,
+                                           https_set_root_ca_conn_setup,
+                                           get_srcdir_file(test_pool, "test/server/serfserverkey.pem"),
+                                           server_certs_srcdir(server_certs, test_pool),
+                                           NULL, /* no client cert */
+                                           NULL, /* No server cert callback */
+                                           test_pool);
+
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    serf_config_authn_types(tb->context, SERF_AUTHN_BASIC);
+    serf_config_credentials_callback(tb->context, ssltunnel_basic_authn_callback);
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+
+    /* Test that a request is retried and authentication headers are set
+     correctly. */
+    num_requests_sent = 1;
+    num_requests_recvd = 2;
+
+    status = test_helper_run_requests_no_check(tc, tb, num_requests_sent,
+                                               handler_ctx, test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    CuAssertIntEquals(tc, num_requests_recvd, tb->sent_requests->nelts);
+    CuAssertIntEquals(tc, num_requests_recvd, tb->accepted_requests->nelts);
+    CuAssertIntEquals(tc, num_requests_sent, tb->handled_requests->nelts);
+
+    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_AUTHNCB_CALLED);
+}
+
+static void test_ssltunnel_basic_auth(CuTest *tc)
+{
+    /* KeepAlive On for both proxy and server */
+    ssltunnel_basic_auth(tc, "", "", "");
+}
+
+static void test_ssltunnel_basic_auth_server_has_keepalive_off(CuTest *tc)
+{
+    /* Add Connection:Close header to server response */
+    ssltunnel_basic_auth(tc, "Connection: close" CRLF, "", "");
+}
+
+static void test_ssltunnel_basic_auth_proxy_has_keepalive_off(CuTest *tc)
+{
+    /* Add Connection:Close header to proxy 407 response */
+    ssltunnel_basic_auth(tc, "", "Connection: close" CRLF, "");
+}
+
+static void test_ssltunnel_basic_auth_proxy_close_conn_on_200resp(CuTest *tc)
+{
+    /* Add Connection:Close header to proxy 200 Conn. Establ. response  */
+    ssltunnel_basic_auth(tc, "", "", "Connection: close" CRLF);
+}
+
+static apr_status_t
+proxy_digest_authn_callback(char **username,
+                            char **password,
+                            serf_request_t *request, void *baton,
+                            int code, const char *authn_type,
+                            const char *realm,
+                            apr_pool_t *pool)
+{
+    handler_baton_t *handler_ctx = baton;
+    test_baton_t *tb = handler_ctx->tb;
+
+    tb->result_flags |= TEST_RESULT_AUTHNCB_CALLED;
+
+    if (code != 407)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    if (strcmp("Digest", authn_type) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+    if (strcmp("<http://localhost:23456> Test Suite Proxy", realm) != 0)
+        return SERF_ERROR_ISSUE_IN_TESTSUITE;
+
+    *username = "serf";
+    *password = "serftest";
+
+    return APR_SUCCESS;
+}
+
+/* Test if serf can successfully authenticate to a proxy used for an ssl
+   tunnel. */
+static void test_ssltunnel_digest_auth(CuTest *tc)
+{
+    test_baton_t *tb;
+    handler_baton_t handler_ctx[1];
+    const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+    apr_status_t status;
+
+    test_server_message_t message_list_server[] = {
+        {"GET /test/index.html HTTP/1.1" CRLF\
+            "Host: localhost:" SERV_PORT_STR CRLF\
+            "Transfer-Encoding: chunked" CRLF\
+            CRLF\
+            "1" CRLF\
+            "1" CRLF\
+            "0" CRLF\
+            CRLF}
+    };
+    test_server_action_t action_list_server[] = {
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+    };
+
+#define CONNECT_REQ\
+    "CONNECT localhost:" SERV_PORT_STR " HTTP/1.1" CRLF\
+    "Host: localhost:" SERV_PORT_STR CRLF
+
+    test_server_message_t message_list_proxy[] = {
+        { CONNECT_REQ CRLF },
+        { CONNECT_REQ
+            "Proxy-Authorization: Digest realm=\"Test Suite Proxy\", "
+            "username=\"serf\", "
+            "nonce=\"ABCDEF1234567890\", uri=\"localhost:" SERV_PORT_STR "\", "
+            "response=\"15b1841822273b0fd44d2f6457f64213\", opaque=\"myopaque\", "
+            "algorithm=\"MD5\"" CRLF
+          CRLF },
+    };
+    /* Add a Basic header before Digest header, to test that serf uses the most
+       secure authentication scheme first, instead of following the order of
+       the headers. */
+    /* Use non standard case for Proxy-Authenticate header to test case
+       insensitivity for http headers. */
+    test_server_action_t action_list_proxy[] = {
+        {SERVER_RESPOND, "HTTP/1.1 407 Unauthorized" CRLF
+            "Transfer-Encoding: chunked" CRLF
+            "Proxy-Authenticate: Basic c2VyZjpzZXJmdGVzdA==" CRLF
+            "Proxy-Authenticate: NonExistent blablablabla" CRLF
+            "proXy-Authenticate: Digest realm=\"Test Suite Proxy\","
+            "nonce=\"ABCDEF1234567890\",opaque=\"myopaque\","
+            "algorithm=\"MD5\",qop-options=\"auth\"" CRLF
+            CRLF
+            "1" CRLF CRLF
+            "0" CRLF CRLF},
+        {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+        /* Forward the remainder of the data to the server without validation */
+        {PROXY_FORWARD, "https://localhost:" SERV_PORT_STR},
+    };
+
+    apr_pool_t *test_pool = tc->testBaton;
+
+    /* Set up a test context with a server and a proxy. Serf should send a
+       CONNECT request to the server. */
+    status = test_https_server_proxy_setup(&tb,
+                                           /* server messages and actions */
+                                           message_list_server, 1,
+                                           action_list_server, 1,
+                                           /* proxy messages and actions */
+                                           message_list_proxy, 2,
+                                           action_list_proxy, 3,
+                                           0,
+                                           https_set_root_ca_conn_setup,
+                                           get_srcdir_file(test_pool, "test/server/serfserverkey.pem"),
+                                           server_certs_srcdir(server_certs, test_pool),
+                                           NULL, /* no client cert */
+                                           NULL, /* No server cert callback */
+                                           test_pool);
+
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    serf_config_authn_types(tb->context, SERF_AUTHN_BASIC | SERF_AUTHN_DIGEST);
+    serf_config_credentials_callback(tb->context, proxy_digest_authn_callback);
+
+    create_new_request(tb, &handler_ctx[0], "GET", "/test/index.html", 1);
+    test_helper_run_requests_expect_ok(tc, tb, num_requests,
+                                       handler_ctx, test_pool);
+
+    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_AUTHNCB_CALLED);
+}
+
+/*****************************************************************************/
+CuSuite *test_context(void)
+{
+    CuSuite *suite = CuSuiteNew();
+
+    CuSuiteSetSetupTeardownCallbacks(suite, test_setup, test_teardown);
+
+    SUITE_ADD_TEST(suite, test_serf_connection_request_create);
+    SUITE_ADD_TEST(suite, test_serf_connection_priority_request_create);
+    SUITE_ADD_TEST(suite, test_closed_connection);
+    SUITE_ADD_TEST(suite, test_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_progress_callback);
+    SUITE_ADD_TEST(suite, test_request_timeout);
+    SUITE_ADD_TEST(suite, test_connection_large_response);
+    SUITE_ADD_TEST(suite, test_connection_large_request);
+    SUITE_ADD_TEST(suite, test_connection_userinfo_in_url);
+    SUITE_ADD_TEST(suite, test_ssl_handshake);
+    SUITE_ADD_TEST(suite, test_ssl_trust_rootca);
+    SUITE_ADD_TEST(suite, test_ssl_application_rejects_cert);
+    SUITE_ADD_TEST(suite, test_ssl_certificate_chain_with_anchor);
+    SUITE_ADD_TEST(suite, test_ssl_certificate_chain_all_from_server);
+    SUITE_ADD_TEST(suite, test_ssl_no_servercert_callback_allok);
+    SUITE_ADD_TEST(suite, test_ssl_no_servercert_callback_fail);
+    SUITE_ADD_TEST(suite, test_ssl_large_response);
+    SUITE_ADD_TEST(suite, test_ssl_large_request);
+    SUITE_ADD_TEST(suite, test_ssl_client_certificate);
+    SUITE_ADD_TEST(suite, test_ssl_expired_server_cert);
+    SUITE_ADD_TEST(suite, test_ssl_future_server_cert);
+    SUITE_ADD_TEST(suite, test_setup_ssltunnel);
+    SUITE_ADD_TEST(suite, test_ssltunnel_no_creds_cb);
+    SUITE_ADD_TEST(suite, test_ssltunnel_basic_auth);
+    SUITE_ADD_TEST(suite, test_ssltunnel_basic_auth_server_has_keepalive_off);
+    SUITE_ADD_TEST(suite, test_ssltunnel_basic_auth_proxy_has_keepalive_off);
+    SUITE_ADD_TEST(suite, test_ssltunnel_basic_auth_proxy_close_conn_on_200resp);
+    SUITE_ADD_TEST(suite, test_ssltunnel_digest_auth);
+
+    return suite;
+}

Deleted: vendor/serf/1.3.9/test/test_serf.h
===================================================================
--- vendor/serf/dist/test/test_serf.h	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/test/test_serf.h	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,285 +0,0 @@
-/* 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"
-#include "server/test_server.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
-
-/* CuTest declarations */
-CuSuite *getsuite(void);
-
-CuSuite *test_context(void);
-CuSuite *test_buckets(void);
-CuSuite *test_ssl(void);
-CuSuite *test_auth(void);
-CuSuite *test_mock_bucket(void);
-
-/* Test setup declarations */
-#define CRLF "\r\n"
-#define CR "\r"
-#define LF "\n"
-
-#define CHUNKED_REQUEST(len, body)\
-        "GET / HTTP/1.1" CRLF\
-        "Host: localhost:12345" CRLF\
-        "Transfer-Encoding: chunked" CRLF\
-        CRLF\
-        #len CRLF\
-        body CRLF\
-        "0" CRLF\
-        CRLF
-
-#define CHUNKED_REQUEST_URI(uri, len, body)\
-        "GET " uri " HTTP/1.1" CRLF\
-        "Host: localhost:12345" 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 {
-    /* Pool for resource allocation. */
-    apr_pool_t *pool;
-
-    serf_context_t *context;
-    serf_connection_t *connection;
-    serf_bucket_alloc_t *bkt_alloc;
-
-    serv_ctx_t *serv_ctx;
-    apr_sockaddr_t *serv_addr;
-
-    serv_ctx_t *proxy_ctx;
-    apr_sockaddr_t *proxy_addr;
-
-    /* Cache connection params here so it gets user for a test to switch to a
-       new connection. */
-    const char *serv_url;
-    serf_connection_setup_t conn_setup;
-
-    /* Extra batons which can be freely used by tests. */
-    void *user_baton;
-    long user_baton_l;
-
-    /* Flags that can be used to report situations, e.g. that a callback was
-       called. */
-    int result_flags;
-
-    apr_array_header_t *accepted_requests, *handled_requests, *sent_requests;
-
-    serf_ssl_context_t *ssl_context;
-    serf_ssl_need_server_cert_t server_cert_cb;
-} test_baton_t;
-
-apr_status_t default_https_conn_setup(apr_socket_t *skt,
-                                      serf_bucket_t **input_bkt,
-                                      serf_bucket_t **output_bkt,
-                                      void *setup_baton,
-                                      apr_pool_t *pool);
-
-apr_status_t use_new_connection(test_baton_t *tb,
-                                apr_pool_t *pool);
-
-apr_status_t test_https_server_setup(test_baton_t **tb_p,
-                                     test_server_message_t *message_list,
-                                     apr_size_t message_count,
-                                     test_server_action_t *action_list,
-                                     apr_size_t action_count,
-                                     apr_int32_t options,
-                                     serf_connection_setup_t conn_setup,
-                                     const char *keyfile,
-                                     const char **certfile,
-                                     const char *client_cn,
-                                     serf_ssl_need_server_cert_t server_cert_cb,
-                                     apr_pool_t *pool);
-
-apr_status_t test_http_server_setup(test_baton_t **tb_p,
-                                    test_server_message_t *message_list,
-                                    apr_size_t message_count,
-                                    test_server_action_t *action_list,
-                                    apr_size_t action_count,
-                                    apr_int32_t options,
-                                    serf_connection_setup_t conn_setup,
-                                    apr_pool_t *pool);
-
-apr_status_t test_server_proxy_setup(
-                 test_baton_t **tb_p,
-                 test_server_message_t *serv_message_list,
-                 apr_size_t serv_message_count,
-                 test_server_action_t *serv_action_list,
-                 apr_size_t serv_action_count,
-                 test_server_message_t *proxy_message_list,
-                 apr_size_t proxy_message_count,
-                 test_server_action_t *proxy_action_list,
-                 apr_size_t proxy_action_count,
-                 apr_int32_t options,
-                 serf_connection_setup_t conn_setup,
-                 apr_pool_t *pool);
-
-apr_status_t test_https_server_proxy_setup(
-                 test_baton_t **tb_p,
-                 test_server_message_t *serv_message_list,
-                 apr_size_t serv_message_count,
-                 test_server_action_t *serv_action_list,
-                 apr_size_t serv_action_count,
-                 test_server_message_t *proxy_message_list,
-                 apr_size_t proxy_message_count,
-                 test_server_action_t *proxy_action_list,
-                 apr_size_t proxy_action_count,
-                 apr_int32_t options,
-                 serf_connection_setup_t conn_setup,
-                 const char *keyfile,
-                 const char **certfiles,
-                 const char *client_cn,
-                 serf_ssl_need_server_cert_t server_cert_cb,
-                 apr_pool_t *pool);
-
-void *test_setup(void *baton);
-void *test_teardown(void *baton);
-
-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;
-    /* Use this for a raw request message */
-    const char *request;
-    int done;
-
-    test_baton_t *tb;
-} handler_baton_t;
-
-/* These defines are used with the test_baton_t result_flags variable. */
-#define TEST_RESULT_SERVERCERTCB_CALLED      0x0001
-#define TEST_RESULT_SERVERCERTCHAINCB_CALLED 0x0002
-#define TEST_RESULT_CLIENT_CERTCB_CALLED     0x0004
-#define TEST_RESULT_CLIENT_CERTPWCB_CALLED   0x0008
-#define TEST_RESULT_AUTHNCB_CALLED           0x001A
-
-apr_status_t
-test_helper_run_requests_no_check(CuTest *tc, test_baton_t *tb,
-                                  int num_requests,
-                                  handler_baton_t handler_ctx[],
-                                  apr_pool_t *pool);
-void
-test_helper_run_requests_expect_ok(CuTest *tc, test_baton_t *tb,
-                                   int num_requests,
-                                   handler_baton_t handler_ctx[],
-                                   apr_pool_t *pool);
-serf_bucket_t* accept_response(serf_request_t *request,
-                               serf_bucket_t *stream,
-                               void *acceptor_baton,
-                               apr_pool_t *pool);
-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);
-apr_status_t handle_response(serf_request_t *request,
-                             serf_bucket_t *response,
-                             void *handler_baton,
-                             apr_pool_t *pool);
-void setup_handler(test_baton_t *tb, handler_baton_t *handler_ctx,
-                   const char *method, const char *path,
-                   int req_id,
-                   serf_response_handler_t handler);
-void create_new_prio_request(test_baton_t *tb,
-                             handler_baton_t *handler_ctx,
-                             const char *method, const char *path,
-                             int req_id);
-void create_new_request(test_baton_t *tb,
-                        handler_baton_t *handler_ctx,
-                        const char *method, const char *path,
-                        int req_id);
-void
-create_new_request_with_resp_hdlr(test_baton_t *tb,
-                                  handler_baton_t *handler_ctx,
-                                  const char *method, const char *path,
-                                  int req_id,
-                                  serf_response_handler_t handler);
-
-/* Mock bucket type and constructor */
-typedef struct {
-    int times;
-    const char *data;
-    apr_status_t status;
-} mockbkt_action;
-
-void read_and_check_bucket(CuTest *tc, serf_bucket_t *bkt,
-                           const char *expected);
-void readlines_and_check_bucket(CuTest *tc, serf_bucket_t *bkt,
-                                int acceptable,
-                                const char *expected,
-                                int expected_nr_of_lines);
-
-extern const serf_bucket_type_t serf_bucket_type_mock;
-#define SERF_BUCKET_IS_MOCK(b) SERF_BUCKET_CHECK((b), mock)
-
-serf_bucket_t *serf_bucket_mock_create(mockbkt_action *actions,
-                                       int len,
-                                       serf_bucket_alloc_t *allocator);
-apr_status_t serf_bucket_mock_more_data_arrived(serf_bucket_t *bucket);
-
-#endif /* TEST_SERF_H */

Copied: vendor/serf/1.3.9/test/test_serf.h (from rev 9259, vendor/serf/dist/test/test_serf.h)
===================================================================
--- vendor/serf/1.3.9/test/test_serf.h	                        (rev 0)
+++ vendor/serf/1.3.9/test/test_serf.h	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,294 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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"
+#include "server/test_server.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
+
+/* CuTest declarations */
+CuSuite *getsuite(void);
+
+CuSuite *test_context(void);
+CuSuite *test_buckets(void);
+CuSuite *test_ssl(void);
+CuSuite *test_auth(void);
+CuSuite *test_mock_bucket(void);
+
+/* Test setup declarations */
+#define CRLF "\r\n"
+#define CR "\r"
+#define LF "\n"
+
+#define CHUNKED_REQUEST(len, body)\
+        "GET / HTTP/1.1" CRLF\
+        "Host: localhost:12345" CRLF\
+        "Transfer-Encoding: chunked" CRLF\
+        CRLF\
+        #len CRLF\
+        body CRLF\
+        "0" CRLF\
+        CRLF
+
+#define CHUNKED_REQUEST_URI(uri, len, body)\
+        "GET " uri " HTTP/1.1" CRLF\
+        "Host: localhost:12345" 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 {
+    /* Pool for resource allocation. */
+    apr_pool_t *pool;
+
+    serf_context_t *context;
+    serf_connection_t *connection;
+    serf_bucket_alloc_t *bkt_alloc;
+
+    serv_ctx_t *serv_ctx;
+    apr_sockaddr_t *serv_addr;
+
+    serv_ctx_t *proxy_ctx;
+    apr_sockaddr_t *proxy_addr;
+
+    /* Cache connection params here so it gets user for a test to switch to a
+       new connection. */
+    const char *serv_url;
+    serf_connection_setup_t conn_setup;
+
+    /* Extra batons which can be freely used by tests. */
+    void *user_baton;
+    long user_baton_l;
+
+    /* Flags that can be used to report situations, e.g. that a callback was
+       called. */
+    int result_flags;
+
+    apr_array_header_t *accepted_requests, *handled_requests, *sent_requests;
+
+    serf_ssl_context_t *ssl_context;
+    serf_ssl_need_server_cert_t server_cert_cb;
+} test_baton_t;
+
+apr_status_t default_https_conn_setup(apr_socket_t *skt,
+                                      serf_bucket_t **input_bkt,
+                                      serf_bucket_t **output_bkt,
+                                      void *setup_baton,
+                                      apr_pool_t *pool);
+
+apr_status_t use_new_connection(test_baton_t *tb,
+                                apr_pool_t *pool);
+
+apr_status_t test_https_server_setup(test_baton_t **tb_p,
+                                     test_server_message_t *message_list,
+                                     apr_size_t message_count,
+                                     test_server_action_t *action_list,
+                                     apr_size_t action_count,
+                                     apr_int32_t options,
+                                     serf_connection_setup_t conn_setup,
+                                     const char *keyfile,
+                                     const char **certfile,
+                                     const char *client_cn,
+                                     serf_ssl_need_server_cert_t server_cert_cb,
+                                     apr_pool_t *pool);
+
+apr_status_t test_http_server_setup(test_baton_t **tb_p,
+                                    test_server_message_t *message_list,
+                                    apr_size_t message_count,
+                                    test_server_action_t *action_list,
+                                    apr_size_t action_count,
+                                    apr_int32_t options,
+                                    serf_connection_setup_t conn_setup,
+                                    apr_pool_t *pool);
+
+apr_status_t test_server_proxy_setup(
+                 test_baton_t **tb_p,
+                 test_server_message_t *serv_message_list,
+                 apr_size_t serv_message_count,
+                 test_server_action_t *serv_action_list,
+                 apr_size_t serv_action_count,
+                 test_server_message_t *proxy_message_list,
+                 apr_size_t proxy_message_count,
+                 test_server_action_t *proxy_action_list,
+                 apr_size_t proxy_action_count,
+                 apr_int32_t options,
+                 serf_connection_setup_t conn_setup,
+                 apr_pool_t *pool);
+
+apr_status_t test_https_server_proxy_setup(
+                 test_baton_t **tb_p,
+                 test_server_message_t *serv_message_list,
+                 apr_size_t serv_message_count,
+                 test_server_action_t *serv_action_list,
+                 apr_size_t serv_action_count,
+                 test_server_message_t *proxy_message_list,
+                 apr_size_t proxy_message_count,
+                 test_server_action_t *proxy_action_list,
+                 apr_size_t proxy_action_count,
+                 apr_int32_t options,
+                 serf_connection_setup_t conn_setup,
+                 const char *keyfile,
+                 const char **certfiles,
+                 const char *client_cn,
+                 serf_ssl_need_server_cert_t server_cert_cb,
+                 apr_pool_t *pool);
+
+void *test_setup(void *baton);
+void *test_teardown(void *baton);
+
+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;
+    /* Use this for a raw request message */
+    const char *request;
+    int done;
+
+    test_baton_t *tb;
+} handler_baton_t;
+
+/* These defines are used with the test_baton_t result_flags variable. */
+#define TEST_RESULT_SERVERCERTCB_CALLED      0x0001
+#define TEST_RESULT_SERVERCERTCHAINCB_CALLED 0x0002
+#define TEST_RESULT_CLIENT_CERTCB_CALLED     0x0004
+#define TEST_RESULT_CLIENT_CERTPWCB_CALLED   0x0008
+#define TEST_RESULT_AUTHNCB_CALLED           0x001A
+
+apr_status_t
+test_helper_run_requests_no_check(CuTest *tc, test_baton_t *tb,
+                                  int num_requests,
+                                  handler_baton_t handler_ctx[],
+                                  apr_pool_t *pool);
+void
+test_helper_run_requests_expect_ok(CuTest *tc, test_baton_t *tb,
+                                   int num_requests,
+                                   handler_baton_t handler_ctx[],
+                                   apr_pool_t *pool);
+serf_bucket_t* accept_response(serf_request_t *request,
+                               serf_bucket_t *stream,
+                               void *acceptor_baton,
+                               apr_pool_t *pool);
+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);
+apr_status_t handle_response(serf_request_t *request,
+                             serf_bucket_t *response,
+                             void *handler_baton,
+                             apr_pool_t *pool);
+void setup_handler(test_baton_t *tb, handler_baton_t *handler_ctx,
+                   const char *method, const char *path,
+                   int req_id,
+                   serf_response_handler_t handler);
+void create_new_prio_request(test_baton_t *tb,
+                             handler_baton_t *handler_ctx,
+                             const char *method, const char *path,
+                             int req_id);
+void create_new_request(test_baton_t *tb,
+                        handler_baton_t *handler_ctx,
+                        const char *method, const char *path,
+                        int req_id);
+void
+create_new_request_with_resp_hdlr(test_baton_t *tb,
+                                  handler_baton_t *handler_ctx,
+                                  const char *method, const char *path,
+                                  int req_id,
+                                  serf_response_handler_t handler);
+
+/* Mock bucket type and constructor */
+typedef struct {
+    int times;
+    const char *data;
+    apr_status_t status;
+} mockbkt_action;
+
+void read_and_check_bucket(CuTest *tc, serf_bucket_t *bkt,
+                           const char *expected);
+void readlines_and_check_bucket(CuTest *tc, serf_bucket_t *bkt,
+                                int acceptable,
+                                const char *expected,
+                                int expected_nr_of_lines);
+
+extern const serf_bucket_type_t serf_bucket_type_mock;
+#define SERF_BUCKET_IS_MOCK(b) SERF_BUCKET_CHECK((b), mock)
+
+serf_bucket_t *serf_bucket_mock_create(mockbkt_action *actions,
+                                       int len,
+                                       serf_bucket_alloc_t *allocator);
+apr_status_t serf_bucket_mock_more_data_arrived(serf_bucket_t *bucket);
+
+/* Helper to get a file relative to our source directory by looking at
+ * 'srcdir' env variable. */
+const char * get_srcdir_file(apr_pool_t *pool, const char * file);
+
+#endif /* TEST_SERF_H */

Deleted: vendor/serf/1.3.9/test/test_ssl.c
===================================================================
--- vendor/serf/dist/test/test_ssl.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/test/test_ssl.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,296 +0,0 @@
-/* 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 <apr_env.h>
-
-#include "serf.h"
-#include "serf_bucket_types.h"
-
-#include "test_serf.h"
-
-#if defined(WIN32) && defined(_DEBUG)
-/* Include this file to allow running a Debug build of serf with a Release
-   build of OpenSSL. */
-#include <openssl/applink.c>
-#endif
-
-/* Test setting up the openssl library. */
-static void test_ssl_init(CuTest *tc)
-{
-    serf_bucket_t *bkt, *stream;
-    serf_ssl_context_t *ssl_context;
-    apr_status_t status;
-
-    apr_pool_t *test_pool = tc->testBaton;
-    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
-                                                              NULL);
-
-    stream = SERF_BUCKET_SIMPLE_STRING("", alloc);
-
-    bkt = serf_bucket_ssl_decrypt_create(stream, NULL,
-                                         alloc);
-    ssl_context = serf_bucket_ssl_decrypt_context_get(bkt);
-
-    bkt = serf_bucket_ssl_encrypt_create(stream, ssl_context,
-                                         alloc);
-
-    status = serf_ssl_use_default_certificates(ssl_context);
-
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-}
-
-
-static const char * get_ca_file(apr_pool_t *pool, const char * file)
-{
-    char *srcdir = "";
-
-    if (apr_env_get(&srcdir, "srcdir", pool) == APR_SUCCESS) {
-        return apr_pstrcat(pool, srcdir, "/", file, NULL);
-    }
-    else {
-        return file;
-    }
-}
-
-
-/* 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_pool_t *test_pool = tc->testBaton;
-    apr_status_t status = serf_ssl_load_cert_file(
-        &cert, get_ca_file(test_pool, "test/serftestca.pem"), test_pool);
-
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-    CuAssertPtrNotNull(tc, cert);
-}
-
-/* Test that reading the subject from a custom CA certificate file works. */
-static void test_ssl_cert_subject(CuTest *tc)
-{
-    apr_hash_t *subject;
-    serf_ssl_certificate_t *cert = NULL;
-    apr_status_t status;
-
-    apr_pool_t *test_pool = tc->testBaton;
-
-    status = serf_ssl_load_cert_file(&cert, get_ca_file(test_pool,
-                                                        "test/serftestca.pem"),
-                                     test_pool);
-
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-    CuAssertPtrNotNull(tc, cert);
-
-    subject = serf_ssl_cert_subject(cert, test_pool);
-    CuAssertPtrNotNull(tc, subject);
-
-    CuAssertStrEquals(tc, "Serf",
-                      apr_hash_get(subject, "CN", APR_HASH_KEY_STRING));
-    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 at example.com", 
-                      apr_hash_get(subject, "E", APR_HASH_KEY_STRING));
-}
-
-/* Test that reading the issuer from a custom CA certificate file works. */
-static void test_ssl_cert_issuer(CuTest *tc)
-{
-    apr_hash_t *issuer;
-    serf_ssl_certificate_t *cert = NULL;
-    apr_status_t status;
-
-    apr_pool_t *test_pool = tc->testBaton;
-
-    status = serf_ssl_load_cert_file(&cert, get_ca_file(test_pool,
-                                                        "test/serftestca.pem"),
-                                     test_pool);
-
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-    CuAssertPtrNotNull(tc, cert);
-
-    issuer = serf_ssl_cert_issuer(cert, test_pool);
-    CuAssertPtrNotNull(tc, issuer);
-
-    /* TODO: create a new test certificate with different issuer and subject. */
-    CuAssertStrEquals(tc, "Serf",
-                      apr_hash_get(issuer, "CN", APR_HASH_KEY_STRING));
-    CuAssertStrEquals(tc, "Test Suite",
-                      apr_hash_get(issuer, "OU", APR_HASH_KEY_STRING));
-    CuAssertStrEquals(tc, "In Serf we trust, Inc.",
-                      apr_hash_get(issuer, "O", APR_HASH_KEY_STRING));
-    CuAssertStrEquals(tc, "Mechelen",
-                      apr_hash_get(issuer, "L", APR_HASH_KEY_STRING));
-    CuAssertStrEquals(tc, "Antwerp",
-                      apr_hash_get(issuer, "ST", APR_HASH_KEY_STRING));
-    CuAssertStrEquals(tc, "BE",
-                      apr_hash_get(issuer, "C", APR_HASH_KEY_STRING));
-    CuAssertStrEquals(tc, "serf at example.com",
-                      apr_hash_get(issuer, "E", APR_HASH_KEY_STRING));
-}
-
-/* Test that reading the notBefore,notAfter,sha1 fingerprint and subjectAltNames
-   from a custom CA certificate file works. */
-static void test_ssl_cert_certificate(CuTest *tc)
-{
-    apr_hash_t *kv;
-    serf_ssl_certificate_t *cert = NULL;
-    apr_array_header_t *san_arr;
-    apr_status_t status;
-
-    apr_pool_t *test_pool = tc->testBaton;
-
-    status = serf_ssl_load_cert_file(&cert, get_ca_file(test_pool,
-                                                        "test/serftestca.pem"),
-                                     test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-    CuAssertPtrNotNull(tc, cert);
-
-    kv = serf_ssl_cert_certificate(cert, test_pool);
-    CuAssertPtrNotNull(tc, kv);
-
-    CuAssertStrEquals(tc, "8A:4C:19:D5:F2:52:4E:35:49:5E:7A:14:80:B2:02:BD:B4:4D:22:18",
-                      apr_hash_get(kv, "sha1", APR_HASH_KEY_STRING));
-    CuAssertStrEquals(tc, "Mar 21 13:18:17 2008 GMT",
-                      apr_hash_get(kv, "notBefore", APR_HASH_KEY_STRING));
-    CuAssertStrEquals(tc, "Mar 21 13:18:17 2011 GMT",
-                      apr_hash_get(kv, "notAfter", APR_HASH_KEY_STRING));
-
-    /* TODO: create a new test certificate with a/some sAN's. */
-    san_arr = apr_hash_get(kv, "subjectAltName", APR_HASH_KEY_STRING);
-    CuAssertTrue(tc, san_arr == NULL);
-}
-
-static const char *extract_cert_from_pem(const char *pemdata,
-                                         apr_pool_t *pool)
-{
-    enum { INIT, CERT_BEGIN, CERT_FOUND } state;
-    serf_bucket_t *pembkt;
-    const char *begincert = "-----BEGIN CERTIFICATE-----";
-    const char *endcert = "-----END CERTIFICATE-----";
-    char *certdata = "";
-    apr_size_t certlen = 0;
-    apr_status_t status = APR_SUCCESS;
-
-    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(pool,
-                                                              NULL, NULL);
-
-    /* Extract the certificate from the .pem file, also remove newlines. */
-    pembkt = SERF_BUCKET_SIMPLE_STRING(pemdata, alloc);
-    state = INIT;
-    while (state != CERT_FOUND && status != APR_EOF) {
-        const char *data;
-        apr_size_t len;
-        int found;
-
-        status = serf_bucket_readline(pembkt, SERF_NEWLINE_ANY, &found,
-                                      &data, &len);
-        if (SERF_BUCKET_READ_ERROR(status))
-            return NULL;
-
-        if (state == INIT) {
-            if (strncmp(begincert, data, strlen(begincert)) == 0)
-                state = CERT_BEGIN;
-        } else if (state == CERT_BEGIN) {
-            if (strncmp(endcert, data, strlen(endcert)) == 0)
-                state = CERT_FOUND;
-            else {
-                certdata = apr_pstrcat(pool, certdata, data, NULL);
-                certlen += len;
-                switch (found) {
-                    case SERF_NEWLINE_CR:
-                    case SERF_NEWLINE_LF:
-                        certdata[certlen-1] = '\0';
-                        certlen --;
-                        break;
-                    case SERF_NEWLINE_CRLF:
-                        certdata[certlen-2] = '\0';
-                        certlen-=2;
-                        break;
-                }
-            }
-        }
-    }
-
-    if (state == CERT_FOUND)
-        return certdata;
-    else
-        return NULL;
-}
-
-static void test_ssl_cert_export(CuTest *tc)
-{
-    serf_ssl_certificate_t *cert = NULL;
-    apr_file_t *fp;
-    apr_finfo_t file_info;
-    const char *base64derbuf;
-    char *pembuf;
-    apr_size_t pemlen;
-    apr_status_t status;
-
-    apr_pool_t *test_pool = tc->testBaton;
-
-    status = serf_ssl_load_cert_file(&cert, get_ca_file(test_pool,
-                                                        "test/serftestca.pem"),
-                                     test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-    CuAssertPtrNotNull(tc, cert);
-
-    /* A .pem file contains a Base64 encoded DER certificate, which is exactly
-       what serf_ssl_cert_export is supposed to be returning. */
-    status = apr_file_open(&fp, "test/serftestca.pem",
-                           APR_FOPEN_READ | APR_FOPEN_BINARY,
-                           APR_FPROT_OS_DEFAULT, test_pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    apr_file_info_get(&file_info, APR_FINFO_SIZE, fp);
-    pembuf = apr_palloc(test_pool, file_info.size);
-
-    status = apr_file_read_full(fp, pembuf, file_info.size, &pemlen);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    base64derbuf = serf_ssl_cert_export(cert, test_pool);
-
-    CuAssertStrEquals(tc,
-                      extract_cert_from_pem(pembuf, test_pool),
-                      base64derbuf);
-}
-
-CuSuite *test_ssl(void)
-{
-    CuSuite *suite = CuSuiteNew();
-
-    CuSuiteSetSetupTeardownCallbacks(suite, test_setup, test_teardown);
-
-    SUITE_ADD_TEST(suite, test_ssl_init);
-    SUITE_ADD_TEST(suite, test_ssl_load_cert_file);
-    SUITE_ADD_TEST(suite, test_ssl_cert_subject);
-    SUITE_ADD_TEST(suite, test_ssl_cert_issuer);
-    SUITE_ADD_TEST(suite, test_ssl_cert_certificate);
-    SUITE_ADD_TEST(suite, test_ssl_cert_export);
-
-    return suite;
-}

Copied: vendor/serf/1.3.9/test/test_ssl.c (from rev 9259, vendor/serf/dist/test/test_ssl.c)
===================================================================
--- vendor/serf/1.3.9/test/test_ssl.c	                        (rev 0)
+++ vendor/serf/1.3.9/test/test_ssl.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,289 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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 <apr_env.h>
+
+#include "serf.h"
+#include "serf_bucket_types.h"
+
+#include "test_serf.h"
+
+#if defined(WIN32) && defined(_DEBUG)
+/* Include this file to allow running a Debug build of serf with a Release
+   build of OpenSSL. */
+#include <openssl/applink.c>
+#endif
+
+/* Test setting up the openssl library. */
+static void test_ssl_init(CuTest *tc)
+{
+    serf_bucket_t *bkt, *stream;
+    serf_ssl_context_t *ssl_context;
+    apr_status_t status;
+
+    apr_pool_t *test_pool = tc->testBaton;
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+                                                              NULL);
+
+    stream = SERF_BUCKET_SIMPLE_STRING("", alloc);
+
+    bkt = serf_bucket_ssl_decrypt_create(stream, NULL,
+                                         alloc);
+    ssl_context = serf_bucket_ssl_decrypt_context_get(bkt);
+
+    bkt = serf_bucket_ssl_encrypt_create(stream, ssl_context,
+                                         alloc);
+
+    status = serf_ssl_use_default_certificates(ssl_context);
+
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+}
+
+#define get_ca_file(pool, file)  get_srcdir_file(pool, file) 
+/* 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_pool_t *test_pool = tc->testBaton;
+    apr_status_t status = serf_ssl_load_cert_file(
+        &cert, get_ca_file(test_pool, "test/serftestca.pem"), test_pool);
+
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    CuAssertPtrNotNull(tc, cert);
+}
+
+/* Test that reading the subject from a custom CA certificate file works. */
+static void test_ssl_cert_subject(CuTest *tc)
+{
+    apr_hash_t *subject;
+    serf_ssl_certificate_t *cert = NULL;
+    apr_status_t status;
+
+    apr_pool_t *test_pool = tc->testBaton;
+
+    status = serf_ssl_load_cert_file(&cert, get_ca_file(test_pool,
+                                                        "test/serftestca.pem"),
+                                     test_pool);
+
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    CuAssertPtrNotNull(tc, cert);
+
+    subject = serf_ssl_cert_subject(cert, test_pool);
+    CuAssertPtrNotNull(tc, subject);
+
+    CuAssertStrEquals(tc, "Serf",
+                      apr_hash_get(subject, "CN", APR_HASH_KEY_STRING));
+    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 at example.com", 
+                      apr_hash_get(subject, "E", APR_HASH_KEY_STRING));
+}
+
+/* Test that reading the issuer from a custom CA certificate file works. */
+static void test_ssl_cert_issuer(CuTest *tc)
+{
+    apr_hash_t *issuer;
+    serf_ssl_certificate_t *cert = NULL;
+    apr_status_t status;
+
+    apr_pool_t *test_pool = tc->testBaton;
+
+    status = serf_ssl_load_cert_file(&cert, get_ca_file(test_pool,
+                                                        "test/serftestca.pem"),
+                                     test_pool);
+
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    CuAssertPtrNotNull(tc, cert);
+
+    issuer = serf_ssl_cert_issuer(cert, test_pool);
+    CuAssertPtrNotNull(tc, issuer);
+
+    /* TODO: create a new test certificate with different issuer and subject. */
+    CuAssertStrEquals(tc, "Serf",
+                      apr_hash_get(issuer, "CN", APR_HASH_KEY_STRING));
+    CuAssertStrEquals(tc, "Test Suite",
+                      apr_hash_get(issuer, "OU", APR_HASH_KEY_STRING));
+    CuAssertStrEquals(tc, "In Serf we trust, Inc.",
+                      apr_hash_get(issuer, "O", APR_HASH_KEY_STRING));
+    CuAssertStrEquals(tc, "Mechelen",
+                      apr_hash_get(issuer, "L", APR_HASH_KEY_STRING));
+    CuAssertStrEquals(tc, "Antwerp",
+                      apr_hash_get(issuer, "ST", APR_HASH_KEY_STRING));
+    CuAssertStrEquals(tc, "BE",
+                      apr_hash_get(issuer, "C", APR_HASH_KEY_STRING));
+    CuAssertStrEquals(tc, "serf at example.com",
+                      apr_hash_get(issuer, "E", APR_HASH_KEY_STRING));
+}
+
+/* Test that reading the notBefore,notAfter,sha1 fingerprint and subjectAltNames
+   from a custom CA certificate file works. */
+static void test_ssl_cert_certificate(CuTest *tc)
+{
+    apr_hash_t *kv;
+    serf_ssl_certificate_t *cert = NULL;
+    apr_array_header_t *san_arr;
+    apr_status_t status;
+
+    apr_pool_t *test_pool = tc->testBaton;
+
+    status = serf_ssl_load_cert_file(&cert, get_ca_file(test_pool,
+                                                        "test/serftestca.pem"),
+                                     test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    CuAssertPtrNotNull(tc, cert);
+
+    kv = serf_ssl_cert_certificate(cert, test_pool);
+    CuAssertPtrNotNull(tc, kv);
+
+    CuAssertStrEquals(tc, "8A:4C:19:D5:F2:52:4E:35:49:5E:7A:14:80:B2:02:BD:B4:4D:22:18",
+                      apr_hash_get(kv, "sha1", APR_HASH_KEY_STRING));
+    CuAssertStrEquals(tc, "Mar 21 13:18:17 2008 GMT",
+                      apr_hash_get(kv, "notBefore", APR_HASH_KEY_STRING));
+    CuAssertStrEquals(tc, "Mar 21 13:18:17 2011 GMT",
+                      apr_hash_get(kv, "notAfter", APR_HASH_KEY_STRING));
+
+    /* TODO: create a new test certificate with a/some sAN's. */
+    san_arr = apr_hash_get(kv, "subjectAltName", APR_HASH_KEY_STRING);
+    CuAssertTrue(tc, san_arr == NULL);
+}
+
+static const char *extract_cert_from_pem(const char *pemdata,
+                                         apr_pool_t *pool)
+{
+    enum { INIT, CERT_BEGIN, CERT_FOUND } state;
+    serf_bucket_t *pembkt;
+    const char *begincert = "-----BEGIN CERTIFICATE-----";
+    const char *endcert = "-----END CERTIFICATE-----";
+    char *certdata = "";
+    apr_size_t certlen = 0;
+    apr_status_t status = APR_SUCCESS;
+
+    serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(pool,
+                                                              NULL, NULL);
+
+    /* Extract the certificate from the .pem file, also remove newlines. */
+    pembkt = SERF_BUCKET_SIMPLE_STRING(pemdata, alloc);
+    state = INIT;
+    while (state != CERT_FOUND && status != APR_EOF) {
+        const char *data;
+        apr_size_t len;
+        int found;
+
+        status = serf_bucket_readline(pembkt, SERF_NEWLINE_ANY, &found,
+                                      &data, &len);
+        if (SERF_BUCKET_READ_ERROR(status))
+            return NULL;
+
+        if (state == INIT) {
+            if (strncmp(begincert, data, strlen(begincert)) == 0)
+                state = CERT_BEGIN;
+        } else if (state == CERT_BEGIN) {
+            if (strncmp(endcert, data, strlen(endcert)) == 0)
+                state = CERT_FOUND;
+            else {
+                certdata = apr_pstrcat(pool, certdata, data, NULL);
+                certlen += len;
+                switch (found) {
+                    case SERF_NEWLINE_CR:
+                    case SERF_NEWLINE_LF:
+                        certdata[certlen-1] = '\0';
+                        certlen --;
+                        break;
+                    case SERF_NEWLINE_CRLF:
+                        certdata[certlen-2] = '\0';
+                        certlen-=2;
+                        break;
+                }
+            }
+        }
+    }
+
+    if (state == CERT_FOUND)
+        return certdata;
+    else
+        return NULL;
+}
+
+static void test_ssl_cert_export(CuTest *tc)
+{
+    serf_ssl_certificate_t *cert = NULL;
+    apr_file_t *fp;
+    apr_finfo_t file_info;
+    const char *base64derbuf;
+    char *pembuf;
+    apr_size_t pemlen;
+    apr_status_t status;
+
+    apr_pool_t *test_pool = tc->testBaton;
+
+    status = serf_ssl_load_cert_file(&cert, get_ca_file(test_pool,
+                                                        "test/serftestca.pem"),
+                                     test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    CuAssertPtrNotNull(tc, cert);
+
+    /* A .pem file contains a Base64 encoded DER certificate, which is exactly
+       what serf_ssl_cert_export is supposed to be returning. */
+    status = apr_file_open(&fp,
+                           get_srcdir_file(test_pool, "test/serftestca.pem"),
+                           APR_FOPEN_READ | APR_FOPEN_BINARY,
+                           APR_FPROT_OS_DEFAULT, test_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    apr_file_info_get(&file_info, APR_FINFO_SIZE, fp);
+    pembuf = apr_palloc(test_pool, file_info.size);
+
+    status = apr_file_read_full(fp, pembuf, file_info.size, &pemlen);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    base64derbuf = serf_ssl_cert_export(cert, test_pool);
+
+    CuAssertStrEquals(tc,
+                      extract_cert_from_pem(pembuf, test_pool),
+                      base64derbuf);
+}
+
+CuSuite *test_ssl(void)
+{
+    CuSuite *suite = CuSuiteNew();
+
+    CuSuiteSetSetupTeardownCallbacks(suite, test_setup, test_teardown);
+
+    SUITE_ADD_TEST(suite, test_ssl_init);
+    SUITE_ADD_TEST(suite, test_ssl_load_cert_file);
+    SUITE_ADD_TEST(suite, test_ssl_cert_subject);
+    SUITE_ADD_TEST(suite, test_ssl_cert_issuer);
+    SUITE_ADD_TEST(suite, test_ssl_cert_certificate);
+    SUITE_ADD_TEST(suite, test_ssl_cert_export);
+
+    return suite;
+}

Deleted: vendor/serf/1.3.9/test/test_util.c
===================================================================
--- vendor/serf/dist/test/test_util.c	2017-02-20 02:08:13 UTC (rev 9258)
+++ vendor/serf/1.3.9/test/test_util.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -1,612 +0,0 @@
-/* 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 <stdlib.h>
-
-#include "serf.h"
-
-#include "test_serf.h"
-#include "server/test_server.h"
-
-
-/*****************************************************************************/
-/* Server setup function(s)
- */
-
-#define HTTP_SERV_URL  "http://localhost:" SERV_PORT_STR
-#define HTTPS_SERV_URL "https://localhost:" SERV_PORT_STR
-
-/* cleanup for conn */
-static apr_status_t cleanup_conn(void *baton)
-{
-    serf_connection_t *conn = baton;
-
-    serf_connection_close(conn);
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t default_server_address(apr_sockaddr_t **address,
-                                           apr_pool_t *pool)
-{
-    return apr_sockaddr_info_get(address,
-                                 "localhost", APR_UNSPEC, SERV_PORT, 0,
-                                 pool);
-}
-
-static apr_status_t default_proxy_address(apr_sockaddr_t **address,
-                                          apr_pool_t *pool)
-{
-    return apr_sockaddr_info_get(address,
-                                 "localhost", APR_UNSPEC, PROXY_PORT, 0,
-                                 pool);
-}
-
-/* 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 apr_status_t default_http_conn_setup(apr_socket_t *skt,
-                                            serf_bucket_t **input_bkt,
-                                            serf_bucket_t **output_bkt,
-                                            void *setup_baton,
-                                            apr_pool_t *pool)
-{
-    test_baton_t *tb = setup_baton;
-
-    *input_bkt = serf_bucket_socket_create(skt, tb->bkt_alloc);
-    return APR_SUCCESS;
-}
-
-/* This function makes serf use SSL on the connection. */
-apr_status_t default_https_conn_setup(apr_socket_t *skt,
-                                      serf_bucket_t **input_bkt,
-                                      serf_bucket_t **output_bkt,
-                                      void *setup_baton,
-                                      apr_pool_t *pool)
-{
-    test_baton_t *tb = setup_baton;
-
-    *input_bkt = serf_bucket_socket_create(skt, tb->bkt_alloc);
-    *input_bkt = serf_bucket_ssl_decrypt_create(*input_bkt, NULL,
-                                                tb->bkt_alloc);
-    tb->ssl_context = serf_bucket_ssl_encrypt_context_get(*input_bkt);
-
-    if (output_bkt) {
-        *output_bkt = serf_bucket_ssl_encrypt_create(*output_bkt,
-                                                     tb->ssl_context,
-                                                     tb->bkt_alloc);
-    }
-
-    if (tb->server_cert_cb)
-        serf_ssl_server_cert_callback_set(tb->ssl_context,
-                                          tb->server_cert_cb,
-                                          tb);
-
-    serf_ssl_set_hostname(tb->ssl_context, "localhost");
-
-    return APR_SUCCESS;
-}
-
-apr_status_t use_new_connection(test_baton_t *tb,
-                                apr_pool_t *pool)
-{
-    apr_uri_t url;
-    apr_status_t status;
-
-    if (tb->connection)
-        cleanup_conn(tb->connection);
-    tb->connection = NULL;
-
-    status = apr_uri_parse(pool, tb->serv_url, &url);
-    if (status != APR_SUCCESS)
-        return status;
-
-    status = serf_connection_create2(&tb->connection, tb->context,
-                                     url,
-                                     tb->conn_setup,
-                                     tb,
-                                     default_closed_connection,
-                                     tb,
-                                     pool);
-    apr_pool_cleanup_register(pool, tb->connection, cleanup_conn,
-                              apr_pool_cleanup_null);
-
-    return status;
-}
-
-/* Setup the client context, ready to connect and send requests to a
-   server.*/
-static apr_status_t setup(test_baton_t **tb_p,
-                          serf_connection_setup_t conn_setup,
-                          const char *serv_url,
-                          int use_proxy,
-                          apr_size_t message_count,
-                          apr_pool_t *pool)
-{
-    test_baton_t *tb;
-    apr_status_t status;
-
-    tb = apr_pcalloc(pool, sizeof(*tb));
-    *tb_p = tb;
-
-    tb->pool = pool;
-    tb->context = serf_context_create(pool);
-    tb->bkt_alloc = serf_bucket_allocator_create(pool, NULL, NULL);
-
-    tb->accepted_requests = apr_array_make(pool, message_count, sizeof(int));
-    tb->sent_requests = apr_array_make(pool, message_count, sizeof(int));
-    tb->handled_requests = apr_array_make(pool, message_count, sizeof(int));
-
-    tb->serv_url = serv_url;
-    tb->conn_setup = conn_setup;
-
-    status = default_server_address(&tb->serv_addr, pool);
-    if (status != APR_SUCCESS)
-        return status;
-
-    if (use_proxy) {
-        status = default_proxy_address(&tb->proxy_addr, pool);
-        if (status != APR_SUCCESS)
-            return status;
-
-        /* Configure serf to use the proxy server */
-        serf_config_proxy(tb->context, tb->proxy_addr);
-    }
-
-    status = use_new_connection(tb, pool);
-
-    return status;
-}
-
-/* Setup an https server and the client context to connect to that server */
-apr_status_t test_https_server_setup(test_baton_t **tb_p,
-                                     test_server_message_t *message_list,
-                                     apr_size_t message_count,
-                                     test_server_action_t *action_list,
-                                     apr_size_t action_count,
-                                     apr_int32_t options,
-                                     serf_connection_setup_t conn_setup,
-                                     const char *keyfile,
-                                     const char **certfiles,
-                                     const char *client_cn,
-                                     serf_ssl_need_server_cert_t server_cert_cb,
-                                     apr_pool_t *pool)
-{
-    apr_status_t status;
-    test_baton_t *tb;
-
-    status = setup(tb_p,
-                   conn_setup ? conn_setup : default_https_conn_setup,
-                   HTTPS_SERV_URL,
-                   FALSE,
-                   message_count,
-                   pool);
-    if (status != APR_SUCCESS)
-        return status;
-
-    tb = *tb_p;
-    tb->server_cert_cb = server_cert_cb;
-
-    /* Prepare a server. */
-    setup_https_test_server(&tb->serv_ctx, tb->serv_addr,
-                            message_list, message_count,
-                            action_list, action_count, options,
-                            keyfile, certfiles, client_cn,
-                            pool);
-    status = start_test_server(tb->serv_ctx);
-
-    return status;
-}
-
-/* Setup an http server and the client context to connect to that server */
-apr_status_t test_http_server_setup(test_baton_t **tb_p,
-                                    test_server_message_t *message_list,
-                                    apr_size_t message_count,
-                                    test_server_action_t *action_list,
-                                    apr_size_t action_count,
-                                    apr_int32_t options,
-                                    serf_connection_setup_t conn_setup,
-                                    apr_pool_t *pool)
-{
-    apr_status_t status;
-    test_baton_t *tb;
-
-    status = setup(tb_p,
-                   conn_setup ? conn_setup : default_http_conn_setup,
-                   HTTP_SERV_URL,
-                   FALSE,
-                   message_count,
-                   pool);
-    if (status != APR_SUCCESS)
-        return status;
-
-    tb = *tb_p;
-
-    /* Prepare a server. */
-    setup_test_server(&tb->serv_ctx, tb->serv_addr,
-                      message_list, message_count,
-                      action_list, action_count, options,
-                      pool);
-    status = start_test_server(tb->serv_ctx);
-
-    return status;
-}
-
-/* Setup a proxy server and an http server and the client context to connect to
-   that proxy server */
-apr_status_t
-test_server_proxy_setup(test_baton_t **tb_p,
-                        test_server_message_t *serv_message_list,
-                        apr_size_t serv_message_count,
-                        test_server_action_t *serv_action_list,
-                        apr_size_t serv_action_count,
-                        test_server_message_t *proxy_message_list,
-                        apr_size_t proxy_message_count,
-                        test_server_action_t *proxy_action_list,
-                        apr_size_t proxy_action_count,
-                        apr_int32_t options,
-                        serf_connection_setup_t conn_setup,
-                        apr_pool_t *pool)
-{
-    apr_status_t status;
-    test_baton_t *tb;
-
-    status = setup(tb_p,
-                   conn_setup ? conn_setup : default_http_conn_setup,
-                   HTTP_SERV_URL,
-                   TRUE,
-                   serv_message_count,
-                   pool);
-    if (status != APR_SUCCESS)
-        return status;
-
-    tb = *tb_p;
-
-    /* Prepare the server. */
-    setup_test_server(&tb->serv_ctx, tb->serv_addr,
-                      serv_message_list, serv_message_count,
-                      serv_action_list, serv_action_count,
-                      options,
-                      pool);
-    status = start_test_server(tb->serv_ctx);
-    if (status != APR_SUCCESS)
-        return status;
-
-    /* Prepare the proxy. */
-    setup_test_server(&tb->proxy_ctx, tb->proxy_addr,
-                      proxy_message_list, proxy_message_count,
-                      proxy_action_list, proxy_action_count,
-                      options,
-                      pool);
-    status = start_test_server(tb->proxy_ctx);
-
-    return status;
-}
-
-/* Setup a proxy server and a https server and the client context to connect to
-   that proxy server */
-apr_status_t
-test_https_server_proxy_setup(test_baton_t **tb_p,
-                              test_server_message_t *serv_message_list,
-                              apr_size_t serv_message_count,
-                              test_server_action_t *serv_action_list,
-                              apr_size_t serv_action_count,
-                              test_server_message_t *proxy_message_list,
-                              apr_size_t proxy_message_count,
-                              test_server_action_t *proxy_action_list,
-                              apr_size_t proxy_action_count,
-                              apr_int32_t options,
-                              serf_connection_setup_t conn_setup,
-                              const char *keyfile,
-                              const char **certfiles,
-                              const char *client_cn,
-                              serf_ssl_need_server_cert_t server_cert_cb,
-                              apr_pool_t *pool)
-{
-    apr_status_t status;
-    test_baton_t *tb;
-
-    status = setup(tb_p,
-                   conn_setup ? conn_setup : default_https_conn_setup,
-                   HTTPS_SERV_URL,
-                   TRUE, /* use proxy */
-                   serv_message_count,
-                   pool);
-    if (status != APR_SUCCESS)
-        return status;
-
-    tb = *tb_p;
-    tb->server_cert_cb = server_cert_cb;
-
-    /* Prepare a https server. */
-    setup_https_test_server(&tb->serv_ctx, tb->serv_addr,
-                            serv_message_list, serv_message_count,
-                            serv_action_list, serv_action_count,
-                            options,
-                            keyfile, certfiles, client_cn,
-                            pool);
-    status = start_test_server(tb->serv_ctx);
-
-    /* Prepare the proxy. */
-    setup_test_server(&tb->proxy_ctx, tb->proxy_addr,
-                      proxy_message_list, proxy_message_count,
-                      proxy_action_list, proxy_action_count,
-                      options,
-                      pool);
-    status = start_test_server(tb->proxy_ctx);
-
-    return status;
-}
-
-void *test_setup(void *dummy)
-{
-    apr_pool_t *test_pool;
-    apr_pool_create(&test_pool, NULL);
-    return test_pool;
-}
-
-void *test_teardown(void *baton)
-{
-    apr_pool_t *pool = baton;
-    apr_pool_destroy(pool);
-
-    return NULL;
-}
-
-/* Helper function, runs the client and server context loops and validates
- that no errors were encountered, and all messages were sent and received. */
-apr_status_t
-test_helper_run_requests_no_check(CuTest *tc, test_baton_t *tb,
-                                  int num_requests,
-                                  handler_baton_t handler_ctx[],
-                                  apr_pool_t *pool)
-{
-    apr_pool_t *iter_pool;
-    int i, done = 0;
-    apr_status_t status;
-
-    apr_pool_create(&iter_pool, pool);
-
-    while (!done)
-    {
-        apr_pool_clear(iter_pool);
-
-        /* run server event loop */
-        status = run_test_server(tb->serv_ctx, 0, iter_pool);
-        if (!APR_STATUS_IS_TIMEUP(status) &&
-            SERF_BUCKET_READ_ERROR(status))
-            return status;
-
-        /* run proxy event loop */
-        if (tb->proxy_ctx) {
-            status = run_test_server(tb->proxy_ctx, 0, iter_pool);
-            if (!APR_STATUS_IS_TIMEUP(status) &&
-                SERF_BUCKET_READ_ERROR(status))
-                return status;
-        }
-
-        /* run client event loop */
-        status = serf_context_run(tb->context, 0, iter_pool);
-        if (!APR_STATUS_IS_TIMEUP(status) &&
-            SERF_BUCKET_READ_ERROR(status))
-            return status;
-
-        done = 1;
-        for (i = 0; i < num_requests; i++)
-            done &= handler_ctx[i].done;
-    }
-    apr_pool_destroy(iter_pool);
-
-    return APR_SUCCESS;
-}
-
-void
-test_helper_run_requests_expect_ok(CuTest *tc, test_baton_t *tb,
-                                   int num_requests,
-                                   handler_baton_t handler_ctx[],
-                                   apr_pool_t *pool)
-{
-    apr_status_t status;
-
-    status = test_helper_run_requests_no_check(tc, tb, num_requests,
-                                               handler_ctx, pool);
-    CuAssertIntEquals(tc, APR_SUCCESS, status);
-
-    /* Check that all requests were received */
-    CuAssertIntEquals(tc, num_requests, tb->sent_requests->nelts);
-    CuAssertIntEquals(tc, num_requests, tb->accepted_requests->nelts);
-    CuAssertIntEquals(tc, num_requests, tb->handled_requests->nelts);
-}
-
-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;
-    serf_bucket_t *response;
-
-    /* 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;
-
-    response = serf_bucket_response_create(c, bkt_alloc);
-
-    if (strcasecmp(ctx->method, "HEAD") == 0)
-      serf_bucket_response_set_head(response);
-
-    return response;
-}
-
-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;
-
-    if (ctx->request)
-    {
-        /* Create a raw request bucket. */
-        *req_bkt = serf_bucket_simple_create(ctx->request, strlen(ctx->request),
-                                             NULL, NULL,
-                                             serf_request_get_alloc(request));
-    }
-    else
-    {
-        if (ctx->req_id >= 0) {
-            /* 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));
-        }
-        else
-            body_bkt = NULL;
-
-        *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;
-}
-
-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;
-        }
-
-        if (APR_STATUS_IS_EAGAIN(status)) {
-            return status;
-        }
-
-    }
-
-    return APR_SUCCESS;
-}
-
-void setup_handler(test_baton_t *tb, handler_baton_t *handler_ctx,
-                   const char *method, const char *path,
-                   int req_id,
-                   serf_response_handler_t handler)
-{
-    handler_ctx->method = method;
-    handler_ctx->path = path;
-    handler_ctx->done = FALSE;
-
-    handler_ctx->acceptor = accept_response;
-    handler_ctx->acceptor_baton = NULL;
-    handler_ctx->handler = handler ? handler : handle_response;
-    handler_ctx->req_id = req_id;
-    handler_ctx->accepted_requests = tb->accepted_requests;
-    handler_ctx->sent_requests = tb->sent_requests;
-    handler_ctx->handled_requests = tb->handled_requests;
-    handler_ctx->tb = tb;
-    handler_ctx->request = NULL;
-}
-
-void create_new_prio_request(test_baton_t *tb,
-                             handler_baton_t *handler_ctx,
-                             const char *method, const char *path,
-                             int req_id)
-{
-    setup_handler(tb, handler_ctx, method, path, req_id, NULL);
-    serf_connection_priority_request_create(tb->connection,
-                                            setup_request,
-                                            handler_ctx);
-}
-
-void create_new_request(test_baton_t *tb,
-                        handler_baton_t *handler_ctx,
-                        const char *method, const char *path,
-                        int req_id)
-{
-    setup_handler(tb, handler_ctx, method, path, req_id, NULL);
-    serf_connection_request_create(tb->connection,
-                                   setup_request,
-                                   handler_ctx);
-}
-
-void
-create_new_request_with_resp_hdlr(test_baton_t *tb,
-                                  handler_baton_t *handler_ctx,
-                                  const char *method, const char *path,
-                                  int req_id,
-                                  serf_response_handler_t handler)
-{
-    setup_handler(tb, handler_ctx, method, path, req_id, handler);
-    serf_connection_request_create(tb->connection,
-                                   setup_request,
-                                   handler_ctx);
-}

Copied: vendor/serf/1.3.9/test/test_util.c (from rev 9259, vendor/serf/dist/test/test_util.c)
===================================================================
--- vendor/serf/1.3.9/test/test_util.c	                        (rev 0)
+++ vendor/serf/1.3.9/test/test_util.c	2017-02-20 02:15:06 UTC (rev 9260)
@@ -0,0 +1,630 @@
+/* ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you 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_env.h>
+#include <apr_strings.h>
+
+#include <stdlib.h>
+
+#include "serf.h"
+
+#include "test_serf.h"
+#include "server/test_server.h"
+
+
+/*****************************************************************************/
+/* Server setup function(s)
+ */
+
+#define HTTP_SERV_URL  "http://localhost:" SERV_PORT_STR
+#define HTTPS_SERV_URL "https://localhost:" SERV_PORT_STR
+
+const char * get_srcdir_file(apr_pool_t *pool, const char * file)
+{
+    char *srcdir = "";
+
+    if (apr_env_get(&srcdir, "srcdir", pool) == APR_SUCCESS) {
+        return apr_pstrcat(pool, srcdir, "/", file, NULL);
+    }
+    else {
+        return file;
+    }
+}
+
+/* cleanup for conn */
+static apr_status_t cleanup_conn(void *baton)
+{
+    serf_connection_t *conn = baton;
+
+    serf_connection_close(conn);
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t default_server_address(apr_sockaddr_t **address,
+                                           apr_pool_t *pool)
+{
+    return apr_sockaddr_info_get(address,
+                                 "localhost", APR_UNSPEC, SERV_PORT, 0,
+                                 pool);
+}
+
+static apr_status_t default_proxy_address(apr_sockaddr_t **address,
+                                          apr_pool_t *pool)
+{
+    return apr_sockaddr_info_get(address,
+                                 "localhost", APR_UNSPEC, PROXY_PORT, 0,
+                                 pool);
+}
+
+/* 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 apr_status_t default_http_conn_setup(apr_socket_t *skt,
+                                            serf_bucket_t **input_bkt,
+                                            serf_bucket_t **output_bkt,
+                                            void *setup_baton,
+                                            apr_pool_t *pool)
+{
+    test_baton_t *tb = setup_baton;
+
+    *input_bkt = serf_bucket_socket_create(skt, tb->bkt_alloc);
+    return APR_SUCCESS;
+}
+
+/* This function makes serf use SSL on the connection. */
+apr_status_t default_https_conn_setup(apr_socket_t *skt,
+                                      serf_bucket_t **input_bkt,
+                                      serf_bucket_t **output_bkt,
+                                      void *setup_baton,
+                                      apr_pool_t *pool)
+{
+    test_baton_t *tb = setup_baton;
+
+    *input_bkt = serf_bucket_socket_create(skt, tb->bkt_alloc);
+    *input_bkt = serf_bucket_ssl_decrypt_create(*input_bkt, NULL,
+                                                tb->bkt_alloc);
+    tb->ssl_context = serf_bucket_ssl_encrypt_context_get(*input_bkt);
+
+    if (output_bkt) {
+        *output_bkt = serf_bucket_ssl_encrypt_create(*output_bkt,
+                                                     tb->ssl_context,
+                                                     tb->bkt_alloc);
+    }
+
+    if (tb->server_cert_cb)
+        serf_ssl_server_cert_callback_set(tb->ssl_context,
+                                          tb->server_cert_cb,
+                                          tb);
+
+    serf_ssl_set_hostname(tb->ssl_context, "localhost");
+
+    return APR_SUCCESS;
+}
+
+apr_status_t use_new_connection(test_baton_t *tb,
+                                apr_pool_t *pool)
+{
+    apr_uri_t url;
+    apr_status_t status;
+
+    if (tb->connection)
+        cleanup_conn(tb->connection);
+    tb->connection = NULL;
+
+    status = apr_uri_parse(pool, tb->serv_url, &url);
+    if (status != APR_SUCCESS)
+        return status;
+
+    status = serf_connection_create2(&tb->connection, tb->context,
+                                     url,
+                                     tb->conn_setup,
+                                     tb,
+                                     default_closed_connection,
+                                     tb,
+                                     pool);
+    apr_pool_cleanup_register(pool, tb->connection, cleanup_conn,
+                              apr_pool_cleanup_null);
+
+    return status;
+}
+
+/* Setup the client context, ready to connect and send requests to a
+   server.*/
+static apr_status_t setup(test_baton_t **tb_p,
+                          serf_connection_setup_t conn_setup,
+                          const char *serv_url,
+                          int use_proxy,
+                          apr_size_t message_count,
+                          apr_pool_t *pool)
+{
+    test_baton_t *tb;
+    apr_status_t status;
+
+    tb = apr_pcalloc(pool, sizeof(*tb));
+    *tb_p = tb;
+
+    tb->pool = pool;
+    tb->context = serf_context_create(pool);
+    tb->bkt_alloc = serf_bucket_allocator_create(pool, NULL, NULL);
+
+    tb->accepted_requests = apr_array_make(pool, message_count, sizeof(int));
+    tb->sent_requests = apr_array_make(pool, message_count, sizeof(int));
+    tb->handled_requests = apr_array_make(pool, message_count, sizeof(int));
+
+    tb->serv_url = serv_url;
+    tb->conn_setup = conn_setup;
+
+    status = default_server_address(&tb->serv_addr, pool);
+    if (status != APR_SUCCESS)
+        return status;
+
+    if (use_proxy) {
+        status = default_proxy_address(&tb->proxy_addr, pool);
+        if (status != APR_SUCCESS)
+            return status;
+
+        /* Configure serf to use the proxy server */
+        serf_config_proxy(tb->context, tb->proxy_addr);
+    }
+
+    status = use_new_connection(tb, pool);
+
+    return status;
+}
+
+/* Setup an https server and the client context to connect to that server */
+apr_status_t test_https_server_setup(test_baton_t **tb_p,
+                                     test_server_message_t *message_list,
+                                     apr_size_t message_count,
+                                     test_server_action_t *action_list,
+                                     apr_size_t action_count,
+                                     apr_int32_t options,
+                                     serf_connection_setup_t conn_setup,
+                                     const char *keyfile,
+                                     const char **certfiles,
+                                     const char *client_cn,
+                                     serf_ssl_need_server_cert_t server_cert_cb,
+                                     apr_pool_t *pool)
+{
+    apr_status_t status;
+    test_baton_t *tb;
+
+    status = setup(tb_p,
+                   conn_setup ? conn_setup : default_https_conn_setup,
+                   HTTPS_SERV_URL,
+                   FALSE,
+                   message_count,
+                   pool);
+    if (status != APR_SUCCESS)
+        return status;
+
+    tb = *tb_p;
+    tb->server_cert_cb = server_cert_cb;
+
+    /* Prepare a server. */
+    setup_https_test_server(&tb->serv_ctx, tb->serv_addr,
+                            message_list, message_count,
+                            action_list, action_count, options,
+                            keyfile, certfiles, client_cn,
+                            pool);
+    status = start_test_server(tb->serv_ctx);
+
+    return status;
+}
+
+/* Setup an http server and the client context to connect to that server */
+apr_status_t test_http_server_setup(test_baton_t **tb_p,
+                                    test_server_message_t *message_list,
+                                    apr_size_t message_count,
+                                    test_server_action_t *action_list,
+                                    apr_size_t action_count,
+                                    apr_int32_t options,
+                                    serf_connection_setup_t conn_setup,
+                                    apr_pool_t *pool)
+{
+    apr_status_t status;
+    test_baton_t *tb;
+
+    status = setup(tb_p,
+                   conn_setup ? conn_setup : default_http_conn_setup,
+                   HTTP_SERV_URL,
+                   FALSE,
+                   message_count,
+                   pool);
+    if (status != APR_SUCCESS)
+        return status;
+
+    tb = *tb_p;
+
+    /* Prepare a server. */
+    setup_test_server(&tb->serv_ctx, tb->serv_addr,
+                      message_list, message_count,
+                      action_list, action_count, options,
+                      pool);
+    status = start_test_server(tb->serv_ctx);
+
+    return status;
+}
+
+/* Setup a proxy server and an http server and the client context to connect to
+   that proxy server */
+apr_status_t
+test_server_proxy_setup(test_baton_t **tb_p,
+                        test_server_message_t *serv_message_list,
+                        apr_size_t serv_message_count,
+                        test_server_action_t *serv_action_list,
+                        apr_size_t serv_action_count,
+                        test_server_message_t *proxy_message_list,
+                        apr_size_t proxy_message_count,
+                        test_server_action_t *proxy_action_list,
+                        apr_size_t proxy_action_count,
+                        apr_int32_t options,
+                        serf_connection_setup_t conn_setup,
+                        apr_pool_t *pool)
+{
+    apr_status_t status;
+    test_baton_t *tb;
+
+    status = setup(tb_p,
+                   conn_setup ? conn_setup : default_http_conn_setup,
+                   HTTP_SERV_URL,
+                   TRUE,
+                   serv_message_count,
+                   pool);
+    if (status != APR_SUCCESS)
+        return status;
+
+    tb = *tb_p;
+
+    /* Prepare the server. */
+    setup_test_server(&tb->serv_ctx, tb->serv_addr,
+                      serv_message_list, serv_message_count,
+                      serv_action_list, serv_action_count,
+                      options,
+                      pool);
+    status = start_test_server(tb->serv_ctx);
+    if (status != APR_SUCCESS)
+        return status;
+
+    /* Prepare the proxy. */
+    setup_test_server(&tb->proxy_ctx, tb->proxy_addr,
+                      proxy_message_list, proxy_message_count,
+                      proxy_action_list, proxy_action_count,
+                      options,
+                      pool);
+    status = start_test_server(tb->proxy_ctx);
+
+    return status;
+}
+
+/* Setup a proxy server and a https server and the client context to connect to
+   that proxy server */
+apr_status_t
+test_https_server_proxy_setup(test_baton_t **tb_p,
+                              test_server_message_t *serv_message_list,
+                              apr_size_t serv_message_count,
+                              test_server_action_t *serv_action_list,
+                              apr_size_t serv_action_count,
+                              test_server_message_t *proxy_message_list,
+                              apr_size_t proxy_message_count,
+                              test_server_action_t *proxy_action_list,
+                              apr_size_t proxy_action_count,
+                              apr_int32_t options,
+                              serf_connection_setup_t conn_setup,
+                              const char *keyfile,
+                              const char **certfiles,
+                              const char *client_cn,
+                              serf_ssl_need_server_cert_t server_cert_cb,
+                              apr_pool_t *pool)
+{
+    apr_status_t status;
+    test_baton_t *tb;
+
+    status = setup(tb_p,
+                   conn_setup ? conn_setup : default_https_conn_setup,
+                   HTTPS_SERV_URL,
+                   TRUE, /* use proxy */
+                   serv_message_count,
+                   pool);
+    if (status != APR_SUCCESS)
+        return status;
+
+    tb = *tb_p;
+    tb->server_cert_cb = server_cert_cb;
+
+    /* Prepare a https server. */
+    setup_https_test_server(&tb->serv_ctx, tb->serv_addr,
+                            serv_message_list, serv_message_count,
+                            serv_action_list, serv_action_count,
+                            options,
+                            keyfile, certfiles, client_cn,
+                            pool);
+    status = start_test_server(tb->serv_ctx);
+
+    /* Prepare the proxy. */
+    setup_test_server(&tb->proxy_ctx, tb->proxy_addr,
+                      proxy_message_list, proxy_message_count,
+                      proxy_action_list, proxy_action_count,
+                      options,
+                      pool);
+    status = start_test_server(tb->proxy_ctx);
+
+    return status;
+}
+
+void *test_setup(void *dummy)
+{
+    apr_pool_t *test_pool;
+    apr_pool_create(&test_pool, NULL);
+    return test_pool;
+}
+
+void *test_teardown(void *baton)
+{
+    apr_pool_t *pool = baton;
+    apr_pool_destroy(pool);
+
+    return NULL;
+}
+
+/* Helper function, runs the client and server context loops and validates
+ that no errors were encountered, and all messages were sent and received. */
+apr_status_t
+test_helper_run_requests_no_check(CuTest *tc, test_baton_t *tb,
+                                  int num_requests,
+                                  handler_baton_t handler_ctx[],
+                                  apr_pool_t *pool)
+{
+    apr_pool_t *iter_pool;
+    int i, done = 0;
+    apr_status_t status;
+
+    apr_pool_create(&iter_pool, pool);
+
+    while (!done)
+    {
+        apr_pool_clear(iter_pool);
+
+        /* run server event loop */
+        status = run_test_server(tb->serv_ctx, 0, iter_pool);
+        if (!APR_STATUS_IS_TIMEUP(status) &&
+            SERF_BUCKET_READ_ERROR(status))
+            return status;
+
+        /* run proxy event loop */
+        if (tb->proxy_ctx) {
+            status = run_test_server(tb->proxy_ctx, 0, iter_pool);
+            if (!APR_STATUS_IS_TIMEUP(status) &&
+                SERF_BUCKET_READ_ERROR(status))
+                return status;
+        }
+
+        /* run client event loop */
+        status = serf_context_run(tb->context, 0, iter_pool);
+        if (!APR_STATUS_IS_TIMEUP(status) &&
+            SERF_BUCKET_READ_ERROR(status))
+            return status;
+
+        done = 1;
+        for (i = 0; i < num_requests; i++)
+            done &= handler_ctx[i].done;
+    }
+    apr_pool_destroy(iter_pool);
+
+    return APR_SUCCESS;
+}
+
+void
+test_helper_run_requests_expect_ok(CuTest *tc, test_baton_t *tb,
+                                   int num_requests,
+                                   handler_baton_t handler_ctx[],
+                                   apr_pool_t *pool)
+{
+    apr_status_t status;
+
+    status = test_helper_run_requests_no_check(tc, tb, num_requests,
+                                               handler_ctx, pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    /* Check that all requests were received */
+    CuAssertIntEquals(tc, num_requests, tb->sent_requests->nelts);
+    CuAssertIntEquals(tc, num_requests, tb->accepted_requests->nelts);
+    CuAssertIntEquals(tc, num_requests, tb->handled_requests->nelts);
+}
+
+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;
+    serf_bucket_t *response;
+
+    /* 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;
+
+    response = serf_bucket_response_create(c, bkt_alloc);
+
+    if (strcasecmp(ctx->method, "HEAD") == 0)
+      serf_bucket_response_set_head(response);
+
+    return response;
+}
+
+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;
+
+    if (ctx->request)
+    {
+        /* Create a raw request bucket. */
+        *req_bkt = serf_bucket_simple_create(ctx->request, strlen(ctx->request),
+                                             NULL, NULL,
+                                             serf_request_get_alloc(request));
+    }
+    else
+    {
+        if (ctx->req_id >= 0) {
+            /* 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));
+        }
+        else
+            body_bkt = NULL;
+
+        *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;
+}
+
+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;
+        }
+
+        if (APR_STATUS_IS_EAGAIN(status)) {
+            return status;
+        }
+
+    }
+
+    return APR_SUCCESS;
+}
+
+void setup_handler(test_baton_t *tb, handler_baton_t *handler_ctx,
+                   const char *method, const char *path,
+                   int req_id,
+                   serf_response_handler_t handler)
+{
+    handler_ctx->method = method;
+    handler_ctx->path = path;
+    handler_ctx->done = FALSE;
+
+    handler_ctx->acceptor = accept_response;
+    handler_ctx->acceptor_baton = NULL;
+    handler_ctx->handler = handler ? handler : handle_response;
+    handler_ctx->req_id = req_id;
+    handler_ctx->accepted_requests = tb->accepted_requests;
+    handler_ctx->sent_requests = tb->sent_requests;
+    handler_ctx->handled_requests = tb->handled_requests;
+    handler_ctx->tb = tb;
+    handler_ctx->request = NULL;
+}
+
+void create_new_prio_request(test_baton_t *tb,
+                             handler_baton_t *handler_ctx,
+                             const char *method, const char *path,
+                             int req_id)
+{
+    setup_handler(tb, handler_ctx, method, path, req_id, NULL);
+    serf_connection_priority_request_create(tb->connection,
+                                            setup_request,
+                                            handler_ctx);
+}
+
+void create_new_request(test_baton_t *tb,
+                        handler_baton_t *handler_ctx,
+                        const char *method, const char *path,
+                        int req_id)
+{
+    setup_handler(tb, handler_ctx, method, path, req_id, NULL);
+    serf_connection_request_create(tb->connection,
+                                   setup_request,
+                                   handler_ctx);
+}
+
+void
+create_new_request_with_resp_hdlr(test_baton_t *tb,
+                                  handler_baton_t *handler_ctx,
+                                  const char *method, const char *path,
+                                  int req_id,
+                                  serf_response_handler_t handler)
+{
+    setup_handler(tb, handler_ctx, method, path, req_id, handler);
+    serf_connection_request_create(tb->connection,
+                                   setup_request,
+                                   handler_ctx);
+}



More information about the Midnightbsd-cvs mailing list