Import serf-1.3.0

This commit is contained in:
Peter Wemm 2013-08-02 19:12:12 +00:00
parent 4e6fa1a552
commit 1f89a666e3
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/serf/dist/; revision=253893
svn path=/vendor/serf/serf-1.3.0/; revision=253894; tag=vendor/serf/serf-1.3.0
47 changed files with 1809 additions and 13353 deletions

20
CHANGES
View File

@ -1,4 +1,20 @@
Serf 1.2.1 [2013-06-03, from /tags/1.2.1]
Serf 1.3.0 [2013-07-23, from /tags/1.3.0]
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)
@ -19,7 +35,7 @@ Serf 1.2.0 [2013-02-22, from /tags/1.2.0, r1726]
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 where
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)

View File

@ -1,171 +0,0 @@
#
# Makefile for Serf
#
srcdir = @srcdir@
VPATH = @srcdir@
SERF_MAJOR_VERSION=@SERF_MAJOR_VERSION@
SERF_DOTTED_VERSION=@SERF_DOTTED_VERSION@
OBJECTS = buckets/aggregate_buckets.lo buckets/request_buckets.lo context.lo \
buckets/buckets.lo buckets/simple_buckets.lo buckets/file_buckets.lo \
buckets/mmap_buckets.lo buckets/socket_buckets.lo \
buckets/response_body_buckets.lo buckets/response_buckets.lo \
buckets/headers_buckets.lo \
buckets/allocator.lo buckets/dechunk_buckets.lo \
buckets/deflate_buckets.lo buckets/limit_buckets.lo \
buckets/ssl_buckets.lo buckets/barrier_buckets.lo \
buckets/chunk_buckets.lo buckets/bwtp_buckets.lo \
buckets/iovec_buckets.lo \
incoming.lo outgoing.lo ssltunnel.lo \
auth/auth.lo auth/auth_basic.lo auth/auth_digest.lo \
auth/auth_kerb.lo auth/auth_kerb_gss.lo
TARGET_LIB=libserf-$(SERF_MAJOR_VERSION).la
TEST_OBJECTS = test/serf_get.lo test/serf_response.lo test/serf_request.lo \
test/serf_spider.lo test/serf_server.lo test/serf_bwtp.lo
TEST_SUITE_OBJECTS = test/CuTest.lo test/test_all.lo test/test_util.lo \
test/test_buckets.lo test/test_context.lo \
test/test_ssl.lo test/server/test_server.lo \
test/server/test_sslserver.lo
PROGRAMS = $(TEST_OBJECTS:.lo=) test/test_all
TESTCASES = test/testcases/simple.response \
test/testcases/chunked-empty.response test/testcases/chunked.response \
test/testcases/chunked-trailers.response \
test/testcases/deflate.response
HEADERS = serf.h serf_bucket_types.h serf_bucket_util.h
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
pkgconfigdir=$(libdir)/pkgconfig
LIBTOOL = @APR_LIBTOOL@
LTFLAGS = @LTFLAGS@ --tag=CC
CC = @CC@
CFLAGS = @EXTRA_CFLAGS@ @CFLAGS@
CPPFLAGS = @EXTRA_CPPFLAGS@ @CPPFLAGS@
INCLUDES = -I$(srcdir) @APR_INCLUDES@ @APU_INCLUDES@ @EXTRA_INCLUDES@
MKDIR = @mkdir_p@
INSTALL = @INSTALL@
LDFLAGS = @EXTRA_LDFLAGS@ @LDFLAGS@
LIBS = @EXTRA_LIBS@ @SERF_LIBS@ -lz -lssl -lcrypto
all: $(TARGET_LIB) $(PROGRAMS)
context.lo: context.c $(HEADERS)
incoming.lo: incoming.c $(HEADERS)
outgoing.lo: outgoing.c $(HEADERS)
ssltunnel.lo: ssltunnel.c $(HEADERS)
buckets/aggregate_buckets.lo: buckets/aggregate_buckets.c $(HEADERS)
buckets/request_buckets.lo: buckets/request_buckets.c $(HEADERS)
buckets/buckets.lo: buckets/buckets.c $(HEADERS)
buckets/simple_buckets.lo: buckets/simple_buckets.c $(HEADERS)
buckets/file_buckets.lo: buckets/file_buckets.c $(HEADERS)
buckets/mmap_buckets.lo: buckets/mmap_buckets.c $(HEADERS)
buckets/socket_buckets.lo: buckets/socket_buckets.c $(HEADERS)
buckets/response_body_buckets.lo: buckets/response_body_buckets.c $(HEADERS)
buckets/response_buckets.lo: buckets/response_buckets.c $(HEADERS)
buckets/headers_buckets.lo: buckets/headers_buckets.c $(HEADERS)
buckets/allocator.lo: buckets/allocator.c $(HEADERS)
buckets/dechunk_buckets.lo: buckets/dechunk_buckets.c $(HEADERS)
buckets/deflate_buckets.lo: buckets/deflate_buckets.c $(HEADERS)
buckets/limit_buckets.lo: buckets/limit_buckets.c $(HEADERS)
buckets/ssl_buckets.lo: buckets/ssl_buckets.c $(HEADERS)
buckets/barrier_buckets.lo: buckets/barrier_buckets.c $(HEADERS)
buckets/chunk_buckets.lo: buckets/chunk_buckets.c $(HEADERS)
buckets/bwtp_buckets.lo: buckets/bwtp_buckets.c $(HEADERS)
buckets/iovec_buckets.lo: buckets/iovec_buckets.c $(HEADERS)
test/serf_get.lo: test/serf_get.c $(HEADERS)
test/serf_response.lo: test/serf_response.c $(HEADERS)
test/serf_request.lo: test/serf_request.c $(HEADERS)
test/serf_server.lo: test/serf_server.c $(HEADERS)
test/serf_spider.lo: test/serf_spider.c $(HEADERS)
test/serf_bwtp.lo: test/serf_bwtp.c $(HEADERS)
test/CuTest.lo: test/CuTest.c $(HEADERS)
test/test_all.lo: test/test_all.c $(HEADERS)
test/test_util.lo: test/test_util.c $(HEADERS)
test/test_buckets.lo: test/test_buckets.c $(HEADERS)
test/test_context.lo: test/test_context.c $(HEADERS)
test/test_ssl.lo: test/test_ssl.c $(HEADERS)
$(TARGET_LIB): $(OBJECTS)
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) $(LDFLAGS) -rpath $(libdir) -o $@ $(OBJECTS) $(LIBS)
test/serf_get: $(TARGET_LIB) test/serf_get.lo
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) $(LDFLAGS) -static -o $@ $(TARGET_LIB) test/serf_get.lo $(LIBS)
test/serf_response: $(TARGET_LIB) test/serf_response.lo
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) $(LDFLAGS) -static -o $@ $(TARGET_LIB) test/serf_response.lo $(LIBS)
test/serf_request: $(TARGET_LIB) test/serf_request.lo
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) $(LDFLAGS) -static -o $@ $(TARGET_LIB) test/serf_request.lo $(LIBS)
test/serf_server: $(TARGET_LIB) test/serf_server.lo
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) $(LDFLAGS) -static -o $@ $(TARGET_LIB) test/serf_server.lo $(LIBS)
test/serf_spider: $(TARGET_LIB) test/serf_spider.lo
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) $(LDFLAGS) -static -o $@ $(TARGET_LIB) test/serf_spider.lo $(LIBS)
test/serf_bwtp: $(TARGET_LIB) test/serf_bwtp.lo
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) $(LDFLAGS) -static -o $@ $(TARGET_LIB) test/serf_bwtp.lo $(LIBS)
test/test_all: $(TARGET_LIB) $(TEST_SUITE_OBJECTS)
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) $(LDFLAGS) -static -o $@ $(TARGET_LIB) $(TEST_SUITE_OBJECTS) $(LIBS)
check: test/serf_response test/test_all
@for i in $(TESTCASES); \
do echo "== Testing $$i =="; \
./test/serf_response $(srcdir)/$$i; \
done;
@echo "== Running test_all ==";
@./test/test_all
install: $(TARGET_LIB)
$(MKDIR) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir) $(DESTDIR)$(pkgconfigdir)
$(LIBTOOL) $(LTFLAGS) --mode=install $(INSTALL) -m 644 $(TARGET_LIB) $(DESTDIR)$(libdir)
for i in $(HEADERS); do \
$(INSTALL) -m 644 $(srcdir)/$$i $(DESTDIR)$(includedir); \
done
$(INSTALL) -m 644 serf.pc $(DESTDIR)$(pkgconfigdir)/serf-$(SERF_MAJOR_VERSION).pc
clean:
rm -f $(TARGET_LIB) $(OBJECTS) $(OBJECTS:.lo=.o) $(PROGRAMS) $(TEST_OBJECTS) $(TEST_OBJECTS:.lo=.o) $(TEST_SUITE_OBJECTS) $(TEST_SUITE_OBJECTS:.lo=.o)
for subdir in . buckets test; do \
(cd $$subdir && rm -rf .libs) ; \
done
distclean: clean
rm -f Makefile serf.pc config.log config.status
.SUFFIXES:
.SUFFIXES: .c .lo .o
mkdir-vpath:
@if [ ! -d auth ]; then \
$(MKDIR) auth; \
fi;
@if [ ! -d buckets ]; then \
$(MKDIR) buckets; \
fi;
@if [ ! -d test ]; then \
$(MKDIR) test; \
fi;
@if [ ! -d test/server ]; then \
$(MKDIR) test/server; \
fi;
@if [ ! -r test/serftestca.pem ]; then \
cp -f $(srcdir)/test/serftestca.pem test/; \
fi;
.c.lo:
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) $(INCLUDES) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< && touch $@

70
README
View File

@ -14,25 +14,67 @@ kept to a minimum to provide high performance operation.
----
Quick guide for the impatient
1. INSTALL
(Unix)
% ./configure
% make
% make install
1.1. SCons build system
----
serf uses SCons 2.x 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.
Building serf from a Subversion checkout (non-packaged releases)
Fetch the scons-local package:
http://prdownloads.sourceforge.net/scons/scons-local-2.0.1.tar.gz
We suggest that you try out 'serfmake'.
% ./serfmake --prefix=/usr/local/serf --with-apr=/usr/local/apr install
1.2 Building serf
If you want to use the autoconf build system and are using a Subversion
checkout, you need to run buildconf and have APR and APR-util sources handy.
To build serf:
% ./buildconf --with-apr=/path/to/apr --with-apr-util=/path/to/apr-util
(By default, buildconf will look in . and ../ for apr and apr-util.)
$ scons APR=/path/to/apr APU=/path/to/apu OPENSSL=/openssl/base PREFIX=/path/to/prefix
Then, you can use ./configure, make, etc.
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
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
1.4 Cleaning up the build
$ scons -c

438
SConstruct Normal file
View File

@ -0,0 +1,438 @@
# -*- 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
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 comma separated list and converts it to a space separated
list.
"""
return (key, '%s' % (help), default, None, lambda val: _converter(val))
# default directories
if sys.platform == 'win32':
default_libdir='..'
default_prefix='Debug'
else:
default_libdir='/usr'
default_prefix='/usr/local'
opts = Variables(files=[SAVED_CONFIG])
opts.AddVariables(
PathVariable('PREFIX',
'Directory to install under',
default_prefix,
PathVariable.PathIsDir),
PathVariable('APR',
"Path to apr-1-config, or to APR's install area",
default_libdir,
PathVariable.PathAccept),
PathVariable('APU',
"Path to apu-1-config, or to APR's install area",
default_libdir,
PathVariable.PathAccept),
PathVariable('OPENSSL',
"Path to OpenSSL's install area",
default_libdir,
PathVariable.PathIsDir),
PathVariable('ZLIB',
"Path to zlib's install area",
default_libdir,
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 (comma separated)",
None),
RawListVariable('LIBS', "Extra libraries passed to the linker, "
"e.g. -l<library> (comma separated)", None),
RawListVariable('LINKFLAGS', "Extra flags for the linker (comma separated)",
None),
RawListVariable('CPPFLAGS', "Extra flags for the C preprocessor "
"(comma 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))
# 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 = '$PREFIX/lib'
incdir = '$PREFIX/include/serf-$MAJOR'
LIBNAME = 'libserf-${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,@executable_path/%s.dylib' % (LIBNAME,))
env.Append(LINKFLAGS='-Wl,-install_name,%s/%s.dylib' % (thisdir, LIBNAME,))
# 'man ld' says positive non-zero for the first number, so we add one.
# Mac's interpretation of compatibility is the same as our MINOR version.
env.Append(LINKFLAGS='-Wl,-compatibility_version,%d' % (MINOR+1,))
env.Append(LINKFLAGS='-Wl,-current_version,%d.%d' % (MINOR+1, PATCH,))
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')
env.Append(CCFLAGS=[
'-Wdeclaration-after-statement',
'-Wmissing-prototypes',
])
### -Wall is not available on Solaris
if sys.platform != 'sunos5':
env.Append(CCFLAGS='-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')
# 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 --libs gssapi')
env.Append(CPPDEFINES='SERF_HAVE_GSSAPI')
if sys.platform == 'win32':
env.Append(CPPDEFINES=['SERF_HAVE_SSPI'])
# On Solaris, 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.
if sys.platform == 'sunos5':
for d in env['LIBPATH']:
env.Append(RPATH=d)
# Set up the construction of serf-*.pc
# TODO: add gssapi libs
pkgconfig = env.Textfile('serf-%d.pc' % (MAJOR,),
env.File('build/serf.pc.in'),
SUBST_DICT = {
'@MAJOR@': str(MAJOR),
'@PREFIX@': '$PREFIX',
'@INCLUDE_SUBDIR@': 'serf-%d' % (MAJOR,),
'@VERSION@': '%d.%d.%d' % (MAJOR, MINOR, PATCH),
'@LIBS@': '%s %s -lz' % (apu_libs, apr_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.Install(libdir, lib_shared)
if sys.platform == 'darwin':
install_shared_path = install_shared[0].abspath
env.AddPostAction(install_shared, ('install_name_tool -id %s %s'
% (install_shared_path,
install_shared_path)))
### construct shared lib symlinks. this also means install the lib
### as libserf-2.1.0.0.dylib, then add the symlinks.
### note: see InstallAs
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')

View File

@ -20,6 +20,7 @@
#include <apr.h>
#include <apr_base64.h>
#include <apr_strings.h>
#include <apr_lib.h>
static apr_status_t
default_auth_response_handler(peer_t peer,
@ -32,10 +33,52 @@ default_auth_response_handler(peer_t peer,
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,
},
{
401,
"Basic",
"basic",
SERF_AUTHN_BASIC,
serf__init_basic,
serf__init_basic_connection,
@ -43,58 +86,6 @@ static const serf__authn_scheme_t serf_authn_schemes[] = {
serf__setup_request_basic_auth,
default_auth_response_handler,
},
{
407,
"Basic",
SERF_AUTHN_BASIC,
serf__init_basic,
serf__init_basic_connection,
serf__handle_basic_auth,
serf__setup_request_basic_auth,
default_auth_response_handler,
},
{
401,
"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,
},
{
407,
"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,
},
#ifdef SERF_HAVE_KERB
{
401,
"Negotiate",
SERF_AUTHN_NEGOTIATE,
serf__init_kerb,
serf__init_kerb_connection,
serf__handle_kerb_auth,
serf__setup_request_kerb_auth,
serf__validate_response_kerb_auth,
},
{
407,
"Negotiate",
SERF_AUTHN_NEGOTIATE,
serf__init_kerb,
serf__init_kerb_connection,
serf__handle_kerb_auth,
serf__setup_request_kerb_auth,
serf__validate_response_kerb_auth,
},
#endif
/* ADD NEW AUTHENTICATION IMPLEMENTATIONS HERE (as they're written) */
/* sentinel */
@ -102,21 +93,6 @@ static const serf__authn_scheme_t serf_authn_schemes[] = {
};
/**
* Baton passed to the response header callback function
*/
typedef struct {
int code;
apr_status_t status;
const char *header;
serf_request_t *request;
serf_bucket_t *response;
void *baton;
apr_pool_t *pool;
const serf__authn_scheme_t *scheme;
const char *last_scheme_name;
} auth_baton_t;
/* Reads and discards all bytes in the response body. */
static apr_status_t discard_body(serf_bucket_t *response)
{
@ -142,99 +118,128 @@ static apr_status_t discard_body(serf_bucket_t *response)
*
* Returns a non-0 value of a matching handler was found.
*/
static int handle_auth_header(void *baton,
const char *key,
const char *header)
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;
/* 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 (code == 401) {
authn_info = serf__get_authn_info_for_server(conn);
} else {
authn_info = &ctx->proxy_authn_info;
}
/* 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);
}
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;
int scheme_found = FALSE;
const char *auth_name;
const char *auth_attr;
const serf__authn_scheme_t *scheme = NULL;
serf_connection_t *conn = ab->request->conn;
serf_context_t *ctx = conn->ctx;
char *auth_name, *c;
/* We're only interested in xxxx-Authenticate headers. */
if (strcmp(key, ab->header) != 0)
return 0;
/* Extract the authentication scheme name, and prepare for reading
the attributes. */
/* Extract the authentication scheme name. */
auth_attr = strchr(header, ' ');
if (auth_attr) {
auth_name = apr_pstrmemdup(ab->pool, header, auth_attr - header);
++auth_attr;
}
else
auth_name = header;
auth_name = apr_pstrmemdup(ab->pool, header, strlen(header));
ab->last_scheme_name = auth_name;
/* Convert scheme name to lower case to enable case insensitive matching. */
for (c = auth_name; *c != '\0'; c++)
*c = (char)apr_tolower(*c);
/* 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->code != 0; ++scheme) {
if (! (ab->code == scheme->code &&
ctx->authn_types & scheme->type))
continue;
apr_hash_set(ab->hdrs, auth_name, APR_HASH_KEY_STRING,
apr_pstrdup(ab->pool, header));
serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
"Client supports: %s\n", scheme->name);
if (strcmp(auth_name, scheme->name) == 0) {
serf__auth_handler_func_t handler = scheme->handle_func;
apr_status_t status = 0;
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 connection,
make sure to initialize the authentication handler first. */
if (ab->code == 401 && ctx->authn_info.scheme != scheme) {
status = scheme->init_ctx_func(ab->code, ctx, ctx->pool);
if (!status) {
status = scheme->init_conn_func(ab->code, conn, conn->pool);
if (!status)
ctx->authn_info.scheme = scheme;
else
ctx->authn_info.scheme = NULL;
}
}
else if (ab->code == 407 && ctx->proxy_authn_info.scheme != scheme) {
status = scheme->init_ctx_func(ab->code, ctx, ctx->pool);
if (!status) {
status = scheme->init_conn_func(ab->code, conn, conn->pool);
if (!status)
ctx->proxy_authn_info.scheme = scheme;
else
ctx->proxy_authn_info.scheme = NULL;
}
}
if (!status) {
scheme_found = TRUE;
ab->scheme = scheme;
status = handler(ab->code, ab->request, ab->response,
header, auth_attr, ab->baton, ctx->pool);
}
/* If the authentication fails, cache the error for now. Try the
next available scheme. If there's none raise the error. */
if (status) {
scheme_found = FALSE;
scheme = NULL;
}
/* Let the caller now if the authentication setup was succesful
or not. */
ab->status = status;
break;
}
}
/* If a matching scheme handler was found, we can stop iterating
over the response headers - so return a non-0 value. */
return scheme_found;
return 0;
}
/* Dispatch authentication handling. This function matches the possible
@ -252,11 +257,7 @@ static apr_status_t dispatch_auth(int code,
auth_baton_t ab = { 0 };
const char *auth_hdr;
ab.code = code;
ab.status = APR_SUCCESS;
ab.request = request;
ab.response = response;
ab.baton = baton;
ab.hdrs = apr_hash_make(pool);
ab.pool = pool;
/* Before iterating over all authn headers, check if there are any. */
@ -275,8 +276,8 @@ static apr_status_t dispatch_auth(int code,
"%s authz required. Response header(s): %s\n",
code == 401 ? "Server" : "Proxy", auth_hdr);
/* Iterate over all headers. Try to find a matching authentication scheme
handler.
/* 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
@ -285,15 +286,13 @@ static apr_status_t dispatch_auth(int code,
work with.
*/
serf_bucket_headers_do(hdrs,
handle_auth_header,
store_header_in_dict,
&ab);
if (ab.status != APR_SUCCESS)
return ab.status;
if (!ab.scheme || ab.scheme->name == NULL) {
/* No matching authentication found. */
return SERF_ERROR_AUTHN_NOT_SUPPORTED;
}
/* 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;
@ -356,28 +355,41 @@ apr_status_t serf__handle_auth_response(int *consumed_response,
/* Requeue the request with the necessary auth headers. */
/* ### Application doesn't know about this request! */
serf_connection_priority_request_create(request->conn,
request->setup,
request->setup_baton);
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 {
/* Validate the response authn headers if needed. */
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;
if (ctx->authn_info.scheme) {
validate_resp = ctx->authn_info.scheme->validate_response_func;
/* 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(HOST, sl.code, conn, request, response,
pool);
}
if (!resp_status && ctx->proxy_authn_info.scheme) {
validate_resp = ctx->proxy_authn_info.scheme->validate_response_func;
/* 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(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. */
@ -419,3 +431,42 @@ void serf__encode_auth_header(const char **header,
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;
}

View File

@ -16,7 +16,7 @@
#ifndef AUTH_H
#define AUTH_H
#include "auth_kerb.h"
#include "auth_spnego.h"
#ifdef __cplusplus
extern "C" {
@ -26,11 +26,19 @@ 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(int code,
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,
@ -52,7 +60,8 @@ apr_status_t serf__setup_request_basic_auth(peer_t peer,
apr_status_t serf__init_digest(int code,
serf_context_t *ctx,
apr_pool_t *pool);
apr_status_t serf__init_digest_connection(int code,
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,
@ -76,34 +85,35 @@ apr_status_t serf__validate_response_digest_auth(peer_t peer,
serf_bucket_t *response,
apr_pool_t *pool);
#ifdef SERF_HAVE_KERB
#ifdef SERF_HAVE_SPNEGO
/** Kerberos authentication **/
apr_status_t serf__init_kerb(int code,
serf_context_t *ctx,
apr_pool_t *pool);
apr_status_t serf__init_kerb_connection(int code,
serf_connection_t *conn,
apr_pool_t *pool);
apr_status_t serf__handle_kerb_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_kerb_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_kerb_auth(peer_t peer,
int code,
serf_connection_t *conn,
serf_request_t *request,
serf_bucket_t *response,
apr_pool_t *pool);
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(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

View File

@ -23,6 +23,8 @@
#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;
@ -41,12 +43,12 @@ serf__handle_basic_auth(int code,
apr_size_t tmp_len;
serf_connection_t *conn = request->conn;
serf_context_t *ctx = conn->ctx;
serf__authn_info_t *authn_info = (code == 401) ? &ctx->authn_info :
&ctx->proxy_authn_info;
basic_authn_info_t *basic_info = authn_info->baton;
serf__authn_info_t *authn_info;
basic_authn_info_t *basic_info;
apr_status_t status;
apr_pool_t *cred_pool;
char *username, *password;
char *username, *password, *realm_name;
const char *eq, *realm;
/* Can't do Basic authentication if there's no callback to get
username & password. */
@ -54,20 +56,25 @@ serf__handle_basic_auth(int code,
return SERF_ERROR_AUTHN_FAILED;
}
if (!authn_info->realm) {
char *realm_name = NULL;
const char *eq = strchr(auth_attr, '=');
if (code == 401) {
authn_info = serf__get_authn_info_for_server(conn);
} else {
authn_info = &ctx->proxy_authn_info;
}
basic_info = authn_info->baton;
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_name = NULL;
eq = strchr(auth_attr, '=');
realm_len = strlen(realm_name);
if (realm_name[realm_len - 1] == '\"') {
realm_name[realm_len - 1] = '\0';
realm_name++;
}
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++;
}
}
@ -75,18 +82,18 @@ serf__handle_basic_auth(int code,
return SERF_ERROR_AUTHN_MISSING_ATTRIBUTE;
}
authn_info->realm = apr_psprintf(conn->pool, "<%s://%s:%d> %s",
conn->host_info.scheme,
conn->host_info.hostname,
conn->host_info.port,
realm_name);
realm = serf__construct_realm(code == 401 ? HOST : PROXY,
conn, realm_name,
pool);
}
/* Ask the application for credentials */
apr_pool_create(&cred_pool, pool);
status = (*ctx->cred_cb)(&username, &password, request, baton,
code, authn_info->scheme->name,
authn_info->realm, cred_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;
@ -104,28 +111,39 @@ serf__handle_basic_auth(int code,
return APR_SUCCESS;
}
/* For Basic authentication we expect all authn info to be the same for all
connections in the context (same realm, username, password). Therefore we
can keep the header value in the context instead of per connection. */
apr_status_t
serf__init_basic(int code,
serf_context_t *ctx,
apr_pool_t *pool)
{
if (code == 401) {
ctx->authn_info.baton = apr_pcalloc(pool, sizeof(basic_authn_info_t));
} else {
ctx->proxy_authn_info.baton = apr_pcalloc(pool, sizeof(basic_authn_info_t));
}
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(int code,
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;
}
@ -139,17 +157,19 @@ serf__setup_request_basic_auth(peer_t peer,
serf_bucket_t *hdrs_bkt)
{
serf_context_t *ctx = conn->ctx;
basic_authn_info_t *authn_info;
serf__authn_info_t *authn_info;
basic_authn_info_t *basic_info;
if (peer == HOST) {
authn_info = ctx->authn_info.baton;
authn_info = serf__get_authn_info_for_server(conn);
} else {
authn_info = ctx->proxy_authn_info.baton;
authn_info = &ctx->proxy_authn_info;
}
basic_info = authn_info->baton;
if (authn_info && authn_info->header && authn_info->value) {
serf_bucket_headers_setn(hdrs_bkt, authn_info->header,
authn_info->value);
if (basic_info && basic_info->header && basic_info->value) {
serf_bucket_headers_setn(hdrs_bkt, basic_info->header,
basic_info->value);
return APR_SUCCESS;
}

View File

@ -27,8 +27,12 @@
/** 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.
The context is per connection. */
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;
@ -217,7 +221,7 @@ serf__handle_digest_auth(int code,
{
char *attrs;
char *nextkv;
const char *realm_name = NULL;
const char *realm, *realm_name = NULL;
const char *nonce = NULL;
const char *algorithm = NULL;
const char *qop = NULL;
@ -225,10 +229,8 @@ serf__handle_digest_auth(int code,
const char *key;
serf_connection_t *conn = request->conn;
serf_context_t *ctx = conn->ctx;
serf__authn_info_t *authn_info = (code == 401) ? &ctx->authn_info :
&ctx->proxy_authn_info;
digest_authn_info_t *digest_info = (code == 401) ? conn->authn_baton :
conn->proxy_authn_baton;
serf__authn_info_t *authn_info;
digest_authn_info_t *digest_info;
apr_status_t status;
apr_pool_t *cred_pool;
char *username, *password;
@ -239,6 +241,13 @@ serf__handle_digest_auth(int code,
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);
@ -286,17 +295,17 @@ serf__handle_digest_auth(int code,
return SERF_ERROR_AUTHN_MISSING_ATTRIBUTE;
}
authn_info->realm = apr_psprintf(conn->pool, "<%s://%s:%d> %s",
conn->host_info.scheme,
conn->host_info.hostname,
conn->host_info.port,
realm_name);
realm = serf__construct_realm(code == 401 ? HOST : PROXY,
conn, realm_name,
pool);
/* Ask the application for credentials */
apr_pool_create(&cred_pool, pool);
status = (*ctx->cred_cb)(&username, &password, request, baton,
code, authn_info->scheme->name,
authn_info->realm, cred_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;
@ -305,9 +314,12 @@ serf__handle_digest_auth(int code,
digest_info->header = (code == 401) ? "Authorization" :
"Proxy-Authorization";
/* Store the digest authentication parameters in the context relative
to this connection, so we can use it to create the Authorization header
when setting up requests. */
/* 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);
@ -339,16 +351,22 @@ serf__init_digest(int code,
}
apr_status_t
serf__init_digest_connection(int code,
serf__init_digest_connection(const serf__authn_scheme_t *scheme,
int code,
serf_connection_t *conn,
apr_pool_t *pool)
{
/* Digest authentication is done per connection, so keep all progress
information per connection. */
serf_context_t *ctx = conn->ctx;
serf__authn_info_t *authn_info;
if (code == 401) {
conn->authn_baton = apr_pcalloc(pool, sizeof(digest_authn_info_t));
authn_info = serf__get_authn_info_for_server(conn);
} else {
conn->proxy_authn_baton = apr_pcalloc(pool, sizeof(digest_authn_info_t));
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 */
@ -366,23 +384,44 @@ serf__setup_request_digest_auth(peer_t peer,
const char *uri,
serf_bucket_t *hdrs_bkt)
{
digest_authn_info_t *digest_info = (peer == HOST) ? conn->authn_baton :
conn->proxy_authn_baton;
serf_context_t *ctx = conn->ctx;
serf__authn_info_t *authn_info;
digest_authn_info_t *digest_info;
apr_status_t status = APR_SUCCESS;
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;
apr_uri_t parsed_uri;
const char *path;
/* TODO: per request pool? */
/* Extract path from uri. */
status = apr_uri_parse(conn->pool, uri, &parsed_uri);
/* 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";
value = build_auth_header(digest_info, parsed_uri.path, method,
value = build_auth_header(digest_info, path, method,
conn->pool);
serf_bucket_headers_setn(hdrs_bkt, digest_info->header,
@ -392,7 +431,7 @@ serf__setup_request_digest_auth(peer_t peer,
/* 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 = parsed_uri.path;
request->auth_baton = path;
}
return status;
@ -413,8 +452,7 @@ serf__validate_response_digest_auth(peer_t peer,
const char *qop = NULL;
const char *nc_str = NULL;
serf_bucket_t *hdrs;
digest_authn_info_t *digest_info = (peer == HOST) ? conn->authn_baton :
conn->proxy_authn_baton;
serf_context_t *ctx = conn->ctx;
hdrs = serf_bucket_response_get_headers(response);
@ -468,6 +506,15 @@ serf__validate_response_digest_auth(peer_t peer,
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;
ha2 = build_digest_ha2(req_uri, "", qop, pool);
tmp = apr_psprintf(pool, "%s:%s:%s:%s:%s:%s",

View File

@ -13,9 +13,9 @@
* limitations under the License.
*/
#include "auth_kerb.h"
#include "auth_spnego.h"
#ifdef SERF_HAVE_KERB
#ifdef SERF_HAVE_SPNEGO
/** These functions implement SPNEGO-based Kerberos and NTLM authentication,
* using either GSS-API (RFC 2743) or SSPI on Windows.
@ -31,8 +31,6 @@
#include <apr_strings.h>
/** TODO:
** - This implements the SPNEGO mechanism, not Kerberos directly. Adapt
** filename, functions & comments.
** - 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
@ -166,7 +164,7 @@ typedef struct
apr_pool_t *pool;
/* GSSAPI context */
serf__kerb_context_t *gss_ctx;
serf__spnego_context_t *gss_ctx;
/* Current state of the authentication cycle. */
gss_api_auth_state state;
@ -188,8 +186,8 @@ gss_api_get_credentials(char *token, apr_size_t token_len,
const char **buf, apr_size_t *buf_len,
gss_authn_info_t *gss_info)
{
serf__kerb_buffer_t input_buf;
serf__kerb_buffer_t output_buf;
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
@ -203,8 +201,8 @@ gss_api_get_credentials(char *token, apr_size_t token_len,
}
/* Establish a security context to the server. */
status = serf__kerb_init_sec_context
(gss_info->gss_ctx,
status = serf__spnego_init_sec_context(
gss_info->gss_ctx,
KRB_HTTP_SERVICE, hostname,
&input_buf,
&output_buf,
@ -248,13 +246,18 @@ do_auth(peer_t peer,
apr_pool_t *pool)
{
serf_context_t *ctx = conn->ctx;
serf__authn_info_t *authn_info = (peer == HOST) ? &ctx->authn_info :
&ctx->proxy_authn_info;
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;
@ -306,7 +309,7 @@ do_auth(peer_t peer,
/* If the server didn't provide us with a token, start with a new initial
step in the SPNEGO authentication. */
if (!token) {
serf__kerb_reset_sec_context(gss_info->gss_ctx);
serf__spnego_reset_sec_context(gss_info->gss_ctx);
gss_info->state = gss_api_auth_not_started;
}
@ -339,9 +342,9 @@ do_auth(peer_t peer,
}
apr_status_t
serf__init_kerb(int code,
serf_context_t *ctx,
apr_pool_t *pool)
serf__init_spnego(int code,
serf_context_t *ctx,
apr_pool_t *pool)
{
return APR_SUCCESS;
}
@ -349,19 +352,20 @@ serf__init_kerb(int code,
/* A new connection is created to a server that's known to use
Kerberos. */
apr_status_t
serf__init_kerb_connection(int code,
serf_connection_t *conn,
apr_pool_t *pool)
serf__init_spnego_connection(const serf__authn_scheme_t *scheme,
int code,
serf_connection_t *conn,
apr_pool_t *pool)
{
gss_authn_info_t *gss_info;
apr_status_t status;
gss_info = apr_pcalloc(pool, sizeof(*gss_info));
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__kerb_create_sec_context(&gss_info->gss_ctx, pool,
gss_info->pool);
status = serf__spnego_create_sec_context(&gss_info->gss_ctx, scheme,
gss_info->pool, pool);
if (status) {
return status;
@ -384,13 +388,13 @@ serf__init_kerb_connection(int code,
/* A 40x response was received, handle the authentication. */
apr_status_t
serf__handle_kerb_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__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;
gss_authn_info_t *gss_info = (code == 401) ? conn->authn_baton :
@ -406,13 +410,13 @@ serf__handle_kerb_auth(int code,
/* Setup the authn headers on this request message. */
apr_status_t
serf__setup_request_kerb_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__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)
{
gss_authn_info_t *gss_info = (peer == HOST) ? conn->authn_baton :
conn->proxy_authn_baton;
@ -488,12 +492,12 @@ serf__setup_request_kerb_auth(peer_t peer,
* data which should be validated by the client (mutual authentication).
*/
apr_status_t
serf__validate_response_kerb_auth(peer_t peer,
int code,
serf_connection_t *conn,
serf_request_t *request,
serf_bucket_t *response,
apr_pool_t *pool)
serf__validate_response_spnego_auth(peer_t peer,
int code,
serf_connection_t *conn,
serf_request_t *request,
serf_bucket_t *response,
apr_pool_t *pool)
{
gss_authn_info_t *gss_info;
const char *auth_hdr_name;
@ -549,4 +553,4 @@ serf__validate_response_kerb_auth(peer_t peer,
return APR_SUCCESS;
}
#endif /* SERF_HAVE_GSSAPI */
#endif /* SERF_HAVE_SPNEGO */

View File

@ -13,32 +13,34 @@
* limitations under the License.
*/
#ifndef AUTH_KERB_H
#define AUTH_KERB_H
#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_KERB
#define SERF_HAVE_SPNEGO
#define SERF_USE_SSPI
#elif defined(SERF_HAVE_GSSAPI)
#define SERF_HAVE_KERB
#define SERF_HAVE_SPNEGO
#define SERF_USE_GSSAPI
#endif
#ifdef SERF_HAVE_KERB
#ifdef SERF_HAVE_SPNEGO
#ifdef __cplusplus
extern "C" {
#endif
typedef struct serf__kerb_context_t serf__kerb_context_t;
typedef struct serf__spnego_context_t serf__spnego_context_t;
typedef struct serf__kerb_buffer_t {
typedef struct serf__spnego_buffer_t {
apr_size_t length;
void *value;
} serf__kerb_buffer_t;
} serf__spnego_buffer_t;
/* Create outbound security context.
*
@ -48,9 +50,10 @@ typedef struct serf__kerb_buffer_t {
*
*/
apr_status_t
serf__kerb_create_sec_context(serf__kerb_context_t **ctx_p,
apr_pool_t *scratch_pool,
apr_pool_t *result_pool);
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.
*
@ -58,7 +61,7 @@ serf__kerb_create_sec_context(serf__kerb_context_t **ctx_p,
* application and a remote peer.
*
* CTX is pointer to existing context created using
* serf__kerb_create_sec_context() function.
* 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
@ -78,21 +81,21 @@ serf__kerb_create_sec_context(serf__kerb_context_t **ctx_p,
* for a return token.
*
* - APR_SUCCESS The security context was successfully initialized. There is no
* need for another serf__kerb_init_sec_context call. If the function returns
* 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__kerb_init_sec_context(serf__kerb_context_t *ctx,
const char *service,
const char *hostname,
serf__kerb_buffer_t *input_buf,
serf__kerb_buffer_t *output_buf,
apr_pool_t *scratch_pool,
apr_pool_t *result_pool
);
serf__spnego_init_sec_context(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.
@ -101,12 +104,12 @@ serf__kerb_init_sec_context(serf__kerb_context_t *ctx,
* where each request requires a new security context.
*/
apr_status_t
serf__kerb_reset_sec_context(serf__kerb_context_t *ctx);
serf__spnego_reset_sec_context(serf__spnego_context_t *ctx);
#ifdef __cplusplus
}
#endif
#endif /* SERF_HAVE_KERB */
#endif /* SERF_HAVE_SPNEGO */
#endif /* !AUTH_KERB_H */
#endif /* !AUTH_SPNEGO_H */

View File

@ -15,7 +15,7 @@
#include "serf.h"
#include "serf_private.h"
#include "auth_kerb.h"
#include "auth_spnego.h"
#ifdef SERF_USE_GSSAPI
#include <apr_strings.h>
@ -33,7 +33,7 @@ static gss_OID_desc spnego_mech_oid = { 6, "\x2b\x06\x01\x05\x05\x02" };
#define GSS_SPNEGO_MECHANISM &spnego_mech_oid
#endif
struct serf__kerb_context_t
struct serf__spnego_context_t
{
/* GSSAPI context */
gss_ctx_id_t gss_ctx;
@ -44,7 +44,7 @@ struct serf__kerb_context_t
static void
log_error(int verbose_flag, const char *filename,
serf__kerb_context_t *ctx,
serf__spnego_context_t *ctx,
OM_uint32 err_maj_stat,
OM_uint32 err_min_stat,
const char *msg)
@ -81,13 +81,19 @@ log_error(int verbose_flag, const char *filename,
static apr_status_t
cleanup_ctx(void *data)
{
OM_uint32 min_stat;
serf__kerb_context_t *ctx = data;
serf__spnego_context_t *ctx = data;
if (ctx->gss_ctx != GSS_C_NO_CONTEXT) {
if (gss_delete_sec_context(&min_stat, &ctx->gss_ctx,
GSS_C_NO_BUFFER) == GSS_S_FAILURE)
return APR_EGENERAL;
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, __FILE__, ctx,
gss_maj_stat, gss_min_stat,
"Error cleaning up GSS security context");
return SERF_ERROR_AUTHN_FAILED;
}
}
return APR_SUCCESS;
@ -105,11 +111,12 @@ cleanup_sec_buffer(void *data)
}
apr_status_t
serf__kerb_create_sec_context(serf__kerb_context_t **ctx_p,
apr_pool_t *scratch_pool,
apr_pool_t *result_pool)
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__kerb_context_t *ctx;
serf__spnego_context_t *ctx;
ctx = apr_pcalloc(result_pool, sizeof(*ctx));
@ -126,7 +133,7 @@ serf__kerb_create_sec_context(serf__kerb_context_t **ctx_p,
}
apr_status_t
serf__kerb_reset_sec_context(serf__kerb_context_t *ctx)
serf__spnego_reset_sec_context(serf__spnego_context_t *ctx)
{
OM_uint32 dummy_stat;
@ -139,14 +146,14 @@ serf__kerb_reset_sec_context(serf__kerb_context_t *ctx)
}
apr_status_t
serf__kerb_init_sec_context(serf__kerb_context_t *ctx,
const char *service,
const char *hostname,
serf__kerb_buffer_t *input_buf,
serf__kerb_buffer_t *output_buf,
apr_pool_t *scratch_pool,
apr_pool_t *result_pool
)
serf__spnego_init_sec_context(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;
@ -164,7 +171,10 @@ serf__kerb_init_sec_context(serf__kerb_context_t *ctx,
GSS_C_NT_HOSTBASED_SERVICE,
&host_gss_name);
if(GSS_ERROR(gss_maj_stat)) {
return APR_EGENERAL;
log_error(AUTH_VERBOSE, __FILE__, 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
@ -207,7 +217,7 @@ serf__kerb_init_sec_context(serf__kerb_context_t *ctx,
log_error(AUTH_VERBOSE, __FILE__, ctx,
gss_maj_stat, gss_min_stat,
"Error during Kerberos handshake");
return APR_EGENERAL;
return SERF_ERROR_AUTHN_FAILED;
}
}

View File

@ -13,8 +13,9 @@
* limitations under the License.
*/
#include "auth_kerb.h"
#include "auth_spnego.h"
#include "serf.h"
#include "serf_private.h"
#ifdef SERF_USE_SSPI
#include <apr.h>
@ -28,11 +29,18 @@
#define SEC_E_MUTUAL_AUTH_FAILED _HRESULT_TYPEDEF_(0x80090363L)
#endif
struct serf__kerb_context_t
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
@ -79,7 +87,7 @@ map_sspi_status(SECURITY_STATUS sspi_status)
static apr_status_t
cleanup_ctx(void *data)
{
serf__kerb_context_t *ctx = data;
serf__spnego_context_t *ctx = data;
if (SecIsValidHandle(&ctx->sspi_context)) {
DeleteSecurityContext(&ctx->sspi_context);
@ -103,25 +111,35 @@ cleanup_sec_buffer(void *data)
}
apr_status_t
serf__kerb_create_sec_context(serf__kerb_context_t **ctx_p,
apr_pool_t *scratch_pool,
apr_pool_t *result_pool)
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__kerb_context_t *ctx;
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, "Negotiate", SECPKG_CRED_OUTBOUND,
NULL, sspi_package, SECPKG_CRED_OUTBOUND,
NULL, NULL, NULL, NULL,
&ctx->sspi_credentials, NULL);
@ -161,7 +179,7 @@ get_canonical_hostname(const char **canonname,
}
apr_status_t
serf__kerb_reset_sec_context(serf__kerb_context_t *ctx)
serf__spnego_reset_sec_context(serf__spnego_context_t *ctx)
{
if (SecIsValidHandle(&ctx->sspi_context)) {
DeleteSecurityContext(&ctx->sspi_context);
@ -174,14 +192,14 @@ serf__kerb_reset_sec_context(serf__kerb_context_t *ctx)
}
apr_status_t
serf__kerb_init_sec_context(serf__kerb_context_t *ctx,
const char *service,
const char *hostname,
serf__kerb_buffer_t *input_buf,
serf__kerb_buffer_t *output_buf,
apr_pool_t *scratch_pool,
apr_pool_t *result_pool
)
serf__spnego_init_sec_context(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;
@ -189,15 +207,26 @@ serf__kerb_init_sec_context(serf__kerb_context_t *ctx,
SecBufferDesc sspi_in_buffer_desc;
SecBuffer sspi_out_buffer;
SecBufferDesc sspi_out_buffer_desc;
char *target_name;
apr_status_t apr_status;
const char *canonname;
apr_status = get_canonical_hostname(&canonname, hostname, scratch_pool);
if (apr_status) {
return apr_status;
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(AUTH_VERBOSE, __FILE__,
"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;
}
target_name = apr_pstrcat(scratch_pool, service, "/", canonname, NULL);
/* Prepare input buffer description. */
sspi_in_buffer.BufferType = SECBUFFER_TOKEN;
@ -220,7 +249,7 @@ serf__kerb_init_sec_context(serf__kerb_context_t *ctx,
status = InitializeSecurityContext(
&ctx->sspi_credentials,
ctx->initalized ? &ctx->sspi_context : NULL,
target_name,
ctx->target_name,
ISC_REQ_ALLOCATE_MEMORY
| ISC_REQ_MUTUAL_AUTH
| ISC_REQ_CONFIDENTIALITY,

View File

@ -353,16 +353,104 @@ static apr_status_t serf_aggregate_readline(serf_bucket_t *bucket,
int acceptable, int *found,
const char **data, apr_size_t *len)
{
/* Follow pattern from serf_aggregate_read. */
return APR_ENOTIMPL;
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)
{
/* Follow pattern from serf_aggregate_read. */
return APR_ENOTIMPL;
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(

View File

@ -17,7 +17,7 @@
#include "serf.h"
#include "serf_bucket_util.h"
#include "serf_private.h"
serf_bucket_t *serf_bucket_create(
const serf_bucket_type_t *type,
@ -155,6 +155,32 @@ char *serf_bstrdup(serf_bucket_alloc_t *allocator,
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;
}
/* ==================================================================== */

View File

@ -162,6 +162,9 @@ static apr_status_t serf_dechunk_read(serf_bucket_t *bucket,
ctx->state = STATE_SIZE;
}
/* Don't return the CR of CRLF to the caller! */
*len = 0;
if (status)
return status;
@ -169,6 +172,7 @@ static apr_status_t serf_dechunk_read(serf_bucket_t *bucket,
case STATE_DONE:
/* Just keep returning EOF */
*len = 0;
return APR_EOF;
default:

View File

@ -325,8 +325,10 @@ static apr_status_t serf_headers_read(serf_bucket_t *bucket,
apr_size_t avail;
select_value(ctx, data, &avail);
if (ctx->state == READ_DONE)
if (ctx->state == READ_DONE) {
*len = avail;
return APR_EOF;
}
if (requested >= avail) {
/* return everything from this chunk */

View File

@ -17,14 +17,7 @@
#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
#include "serf_private.h"
typedef struct {
serf_bucket_t *stream;

View File

@ -105,14 +105,9 @@ static void serialize_data(serf_bucket_t *bucket)
iov[3].iov_base = " HTTP/1.1\r\n";
iov[3].iov_len = sizeof(" HTTP/1.1\r\n") - 1;
/* ### pool allocation! */
new_data = apr_pstrcatv(serf_bucket_allocator_get_pool(bucket->allocator),
iov, 4, &nbytes);
/* Create a new bucket for this string. A free function isn't needed
* since the string is residing in a pool.
*/
new_bucket = SERF_BUCKET_SIMPLE_STRING_LEN(new_data, nbytes,
/* 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.

View File

@ -19,7 +19,7 @@
#include "serf.h"
#include "serf_bucket_util.h"
#include "serf_private.h"
typedef struct {
serf_bucket_t *stream;

View File

@ -71,6 +71,23 @@ serf_bucket_t *serf_bucket_simple_copy_create(
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)

View File

@ -211,14 +211,14 @@ 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));
@ -255,7 +255,8 @@ static int bio_bucket_read(BIO *bio, char *in, int 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",
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... */
@ -296,7 +297,8 @@ static int bio_bucket_write(BIO *bio, const char *in, int 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",
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... */
@ -570,6 +572,15 @@ validate_server_certificate(int cert_valid, X509_STORE_CTX *store_ctx)
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;
}
@ -621,9 +632,12 @@ static apr_status_t ssl_decrypt(void *baton, apr_size_t bufsize,
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;
@ -784,16 +798,19 @@ static apr_status_t ssl_encrypt(void *baton, apr_size_t bufsize,
serf__log(SSL_VERBOSE, __FILE__,
"ssl_encrypt: SSL write: %d\n", ssl_len);
/* We're done. */
serf_bucket_mem_free(ctx->allocator, vecs_data);
/* If we failed to write... */
if (ssl_len < 0) {
int ssl_err;
/* Ah, bugger. We need to put that data back. */
serf_bucket_aggregate_prepend_iovec(ctx->encrypt.stream,
vecs, vecs_read);
/* 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);
@ -801,6 +818,8 @@ static apr_status_t ssl_encrypt(void *baton, apr_size_t bufsize,
"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;
@ -812,13 +831,17 @@ static apr_status_t ssl_encrypt(void *baton, apr_size_t bufsize,
status = SERF_ERROR_WAIT_CONN;
}
else {
ctx->fatal_err = status = SERF_ERROR_SSL_COMM_FAILED;
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);
}
}
}
@ -1024,7 +1047,7 @@ static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey)
}
if (status || !cert_path) {
break;
break;
}
/* Load the x.509 cert file stored in PKCS12 */
@ -1313,7 +1336,7 @@ apr_status_t serf_ssl_load_cert_file(
apr_pool_t *pool)
{
FILE *fp = fopen(file_path, "r");
if (fp) {
X509 *ssl_cert = PEM_read_X509(fp, NULL, NULL, NULL);
fclose(fp);

View File

@ -1,985 +0,0 @@
dnl -------------------------------------------------------- -*- autoconf -*-
dnl Licensed to the Apache Software Foundation (ASF) under one or more
dnl contributor license agreements. See the NOTICE file distributed with
dnl this work for additional information regarding copyright ownership.
dnl The ASF licenses this file to You under the Apache License, Version 2.0
dnl (the "License"); you may not use this file except in compliance with
dnl the License. You may obtain a copy of the License at
dnl
dnl http://www.apache.org/licenses/LICENSE-2.0
dnl
dnl Unless required by applicable law or agreed to in writing, software
dnl distributed under the License is distributed on an "AS IS" BASIS,
dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
dnl See the License for the specific language governing permissions and
dnl limitations under the License.
dnl
dnl apr_common.m4: APR's general-purpose autoconf macros
dnl
dnl
dnl APR_CONFIG_NICE(filename)
dnl
dnl Saves a snapshot of the configure command-line for later reuse
dnl
AC_DEFUN([APR_CONFIG_NICE], [
rm -f $1
cat >$1<<EOF
#! /bin/sh
#
# Created by configure
EOF
if test -n "$CC"; then
echo "CC=\"$CC\"; export CC" >> $1
fi
if test -n "$CFLAGS"; then
echo "CFLAGS=\"$CFLAGS\"; export CFLAGS" >> $1
fi
if test -n "$CPPFLAGS"; then
echo "CPPFLAGS=\"$CPPFLAGS\"; export CPPFLAGS" >> $1
fi
if test -n "$LDFLAGS"; then
echo "LDFLAGS=\"$LDFLAGS\"; export LDFLAGS" >> $1
fi
if test -n "$LTFLAGS"; then
echo "LTFLAGS=\"$LTFLAGS\"; export LTFLAGS" >> $1
fi
if test -n "$LIBS"; then
echo "LIBS=\"$LIBS\"; export LIBS" >> $1
fi
if test -n "$INCLUDES"; then
echo "INCLUDES=\"$INCLUDES\"; export INCLUDES" >> $1
fi
if test -n "$NOTEST_CFLAGS"; then
echo "NOTEST_CFLAGS=\"$NOTEST_CFLAGS\"; export NOTEST_CFLAGS" >> $1
fi
if test -n "$NOTEST_CPPFLAGS"; then
echo "NOTEST_CPPFLAGS=\"$NOTEST_CPPFLAGS\"; export NOTEST_CPPFLAGS" >> $1
fi
if test -n "$NOTEST_LDFLAGS"; then
echo "NOTEST_LDFLAGS=\"$NOTEST_LDFLAGS\"; export NOTEST_LDFLAGS" >> $1
fi
if test -n "$NOTEST_LIBS"; then
echo "NOTEST_LIBS=\"$NOTEST_LIBS\"; export NOTEST_LIBS" >> $1
fi
# Retrieve command-line arguments.
eval "set x $[0] $ac_configure_args"
shift
for arg
do
APR_EXPAND_VAR(arg, $arg)
echo "\"[$]arg\" \\" >> $1
done
echo '"[$]@"' >> $1
chmod +x $1
])dnl
dnl APR_MKDIR_P_CHECK(fallback-mkdir-p)
dnl checks whether mkdir -p works
AC_DEFUN([APR_MKDIR_P_CHECK], [
AC_CACHE_CHECK(for working mkdir -p, ac_cv_mkdir_p,[
test -d conftestdir && rm -rf conftestdir
mkdir -p conftestdir/somedir >/dev/null 2>&1
if test -d conftestdir/somedir; then
ac_cv_mkdir_p=yes
else
ac_cv_mkdir_p=no
fi
rm -rf conftestdir
])
if test "$ac_cv_mkdir_p" = "yes"; then
mkdir_p="mkdir -p"
else
mkdir_p="$1"
fi
])
dnl
dnl APR_SUBDIR_CONFIG(dir [, sub-package-cmdline-args, args-to-drop])
dnl
dnl dir: directory to find configure in
dnl sub-package-cmdline-args: arguments to add to the invocation (optional)
dnl args-to-drop: arguments to drop from the invocation (optional)
dnl
dnl Note: This macro relies on ac_configure_args being set properly.
dnl
dnl The args-to-drop argument is shoved into a case statement, so
dnl multiple arguments can be separated with a |.
dnl
dnl Note: Older versions of autoconf do not single-quote args, while 2.54+
dnl places quotes around every argument. So, if you want to drop the
dnl argument called --enable-layout, you must pass the third argument as:
dnl [--enable-layout=*|\'--enable-layout=*]
dnl
dnl Trying to optimize this is left as an exercise to the reader who wants
dnl to put up with more autoconf craziness. I give up.
dnl
AC_DEFUN([APR_SUBDIR_CONFIG], [
# save our work to this point; this allows the sub-package to use it
AC_CACHE_SAVE
echo "configuring package in $1 now"
ac_popdir=`pwd`
apr_config_subdirs="$1"
test -d $1 || $mkdir_p $1
ac_abs_srcdir=`(cd $srcdir/$1 && pwd)`
cd $1
changequote(, )dnl
# A "../" for each directory in /$config_subdirs.
ac_dots=`echo $apr_config_subdirs|sed -e 's%^\./%%' -e 's%[^/]$%&/%' -e 's%[^/]*/%../%g'`
changequote([, ])dnl
# Make the cache file pathname absolute for the subdirs
# required to correctly handle subdirs that might actually
# be symlinks
case "$cache_file" in
/*) # already absolute
ac_sub_cache_file=$cache_file ;;
*) # Was relative path.
ac_sub_cache_file="$ac_popdir/$cache_file" ;;
esac
ifelse($3, [], [apr_configure_args=$ac_configure_args],[
apr_configure_args=
apr_sep=
for apr_configure_arg in $ac_configure_args
do
case "$apr_configure_arg" in
$3)
continue ;;
esac
apr_configure_args="$apr_configure_args$apr_sep'$apr_configure_arg'"
apr_sep=" "
done
])
dnl autoconf doesn't add --silent to ac_configure_args; explicitly pass it
test "x$silent" = "xyes" && apr_configure_args="$apr_configure_args --silent"
dnl AC_CONFIG_SUBDIRS silences option warnings, emulate this for 2.62
apr_configure_args="--disable-option-checking $apr_configure_args"
dnl The eval makes quoting arguments work - specifically the second argument
dnl where the quoting mechanisms used is "" rather than [].
dnl
dnl We need to execute another shell because some autoconf/shell combinations
dnl will choke after doing repeated APR_SUBDIR_CONFIG()s. (Namely Solaris
dnl and autoconf-2.54+)
if eval $SHELL $ac_abs_srcdir/configure $apr_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_abs_srcdir $2
then :
echo "$1 configured properly"
else
echo "configure failed for $1"
exit 1
fi
cd $ac_popdir
# grab any updates from the sub-package
AC_CACHE_LOAD
])dnl
dnl
dnl APR_SAVE_THE_ENVIRONMENT(variable_name)
dnl
dnl Stores the variable (usually a Makefile macro) for later restoration
dnl
AC_DEFUN([APR_SAVE_THE_ENVIRONMENT], [
apr_ste_save_$1="$$1"
])dnl
dnl
dnl APR_RESTORE_THE_ENVIRONMENT(variable_name, prefix_)
dnl
dnl Uses the previously saved variable content to figure out what configure
dnl has added to the variable, moving the new bits to prefix_variable_name
dnl and restoring the original variable contents. This makes it possible
dnl for a user to override configure when it does something stupid.
dnl
AC_DEFUN([APR_RESTORE_THE_ENVIRONMENT], [
dnl Check whether $apr_ste_save_$1 is empty or
dnl only whitespace. The verbatim "X" is token number 1,
dnl the following whitespace will be ignored.
set X $apr_ste_save_$1
if test ${#} -eq 1; then
$2$1="$$1"
$1=
else
if test "x$apr_ste_save_$1" = "x$$1"; then
$2$1=
else
$2$1=`echo "$$1" | sed -e "s%${apr_ste_save_$1}%%"`
$1="$apr_ste_save_$1"
fi
fi
if test "x$silent" != "xyes"; then
echo " restoring $1 to \"$$1\""
echo " setting $2$1 to \"$$2$1\""
fi
AC_SUBST($2$1)
])dnl
dnl
dnl APR_SETIFNULL(variable, value)
dnl
dnl Set variable iff it's currently null
dnl
AC_DEFUN([APR_SETIFNULL], [
if test -z "$$1"; then
test "x$silent" != "xyes" && echo " setting $1 to \"$2\""
$1="$2"
fi
])dnl
dnl
dnl APR_SETVAR(variable, value)
dnl
dnl Set variable no matter what
dnl
AC_DEFUN([APR_SETVAR], [
test "x$silent" != "xyes" && echo " forcing $1 to \"$2\""
$1="$2"
])dnl
dnl
dnl APR_ADDTO(variable, value)
dnl
dnl Add value to variable
dnl
AC_DEFUN([APR_ADDTO], [
if test "x$$1" = "x"; then
test "x$silent" != "xyes" && echo " setting $1 to \"$2\""
$1="$2"
else
apr_addto_bugger="$2"
for i in $apr_addto_bugger; do
apr_addto_duplicate="0"
for j in $$1; do
if test "x$i" = "x$j"; then
apr_addto_duplicate="1"
break
fi
done
if test $apr_addto_duplicate = "0"; then
test "x$silent" != "xyes" && echo " adding \"$i\" to $1"
$1="$$1 $i"
fi
done
fi
])dnl
dnl
dnl APR_REMOVEFROM(variable, value)
dnl
dnl Remove a value from a variable
dnl
AC_DEFUN([APR_REMOVEFROM], [
if test "x$$1" = "x$2"; then
test "x$silent" != "xyes" && echo " nulling $1"
$1=""
else
apr_new_bugger=""
apr_removed=0
for i in $$1; do
if test "x$i" != "x$2"; then
apr_new_bugger="$apr_new_bugger $i"
else
apr_removed=1
fi
done
if test $apr_removed = "1"; then
test "x$silent" != "xyes" && echo " removed \"$2\" from $1"
$1=$apr_new_bugger
fi
fi
]) dnl
dnl
dnl APR_CHECK_DEFINE_FILES( symbol, header_file [header_file ...] )
dnl
AC_DEFUN([APR_CHECK_DEFINE_FILES], [
AC_CACHE_CHECK([for $1 in $2],ac_cv_define_$1,[
ac_cv_define_$1=no
for curhdr in $2
do
AC_EGREP_CPP(YES_IS_DEFINED, [
#include <$curhdr>
#ifdef $1
YES_IS_DEFINED
#endif
], ac_cv_define_$1=yes)
done
])
if test "$ac_cv_define_$1" = "yes"; then
AC_DEFINE(HAVE_$1, 1, [Define if $1 is defined])
fi
])
dnl
dnl APR_CHECK_DEFINE(symbol, header_file)
dnl
AC_DEFUN([APR_CHECK_DEFINE], [
AC_CACHE_CHECK([for $1 in $2],ac_cv_define_$1,[
AC_EGREP_CPP(YES_IS_DEFINED, [
#include <$2>
#ifdef $1
YES_IS_DEFINED
#endif
], ac_cv_define_$1=yes, ac_cv_define_$1=no)
])
if test "$ac_cv_define_$1" = "yes"; then
AC_DEFINE(HAVE_$1, 1, [Define if $1 is defined in $2])
fi
])
dnl
dnl APR_CHECK_APR_DEFINE( symbol )
dnl
AC_DEFUN([APR_CHECK_APR_DEFINE], [
apr_old_cppflags=$CPPFLAGS
CPPFLAGS="$CPPFLAGS $INCLUDES"
AC_EGREP_CPP(YES_IS_DEFINED, [
#include <apr.h>
#if $1
YES_IS_DEFINED
#endif
], ac_cv_define_$1=yes, ac_cv_define_$1=no)
CPPFLAGS=$apr_old_cppflags
])
dnl APR_CHECK_FILE(filename); set ac_cv_file_filename to
dnl "yes" if 'filename' is readable, else "no".
dnl @deprecated! - use AC_CHECK_FILE instead
AC_DEFUN([APR_CHECK_FILE], [
dnl Pick a safe variable name
define([apr_cvname], ac_cv_file_[]translit([$1], [./+-], [__p_]))
AC_CACHE_CHECK([for $1], [apr_cvname],
[if test -r $1; then
apr_cvname=yes
else
apr_cvname=no
fi])
])
define(APR_IFALLYES,[dnl
ac_rc=yes
for ac_spec in $1; do
ac_type=`echo "$ac_spec" | sed -e 's/:.*$//'`
ac_item=`echo "$ac_spec" | sed -e 's/^.*://'`
case $ac_type in
header )
ac_item=`echo "$ac_item" | sed 'y%./+-%__p_%'`
ac_var="ac_cv_header_$ac_item"
;;
file )
ac_item=`echo "$ac_item" | sed 'y%./+-%__p_%'`
ac_var="ac_cv_file_$ac_item"
;;
func ) ac_var="ac_cv_func_$ac_item" ;;
struct ) ac_var="ac_cv_struct_$ac_item" ;;
define ) ac_var="ac_cv_define_$ac_item" ;;
custom ) ac_var="$ac_item" ;;
esac
eval "ac_val=\$$ac_var"
if test ".$ac_val" != .yes; then
ac_rc=no
break
fi
done
if test ".$ac_rc" = .yes; then
:
$2
else
:
$3
fi
])
define(APR_BEGIN_DECISION,[dnl
ac_decision_item='$1'
ac_decision_msg='FAILED'
ac_decision=''
])
AC_DEFUN([APR_DECIDE],[dnl
dnl Define the flag (or not) in apr_private.h via autoheader
AH_TEMPLATE($1, [Define if $2 will be used])
ac_decision='$1'
ac_decision_msg='$2'
ac_decision_$1=yes
ac_decision_$1_msg='$2'
])
define(APR_DECISION_OVERRIDE,[dnl
ac_decision=''
for ac_item in $1; do
eval "ac_decision_this=\$ac_decision_${ac_item}"
if test ".$ac_decision_this" = .yes; then
ac_decision=$ac_item
eval "ac_decision_msg=\$ac_decision_${ac_item}_msg"
fi
done
])
define(APR_DECISION_FORCE,[dnl
ac_decision="$1"
eval "ac_decision_msg=\"\$ac_decision_${ac_decision}_msg\""
])
define(APR_END_DECISION,[dnl
if test ".$ac_decision" = .; then
echo "[$]0:Error: decision on $ac_decision_item failed" 1>&2
exit 1
else
if test ".$ac_decision_msg" = .; then
ac_decision_msg="$ac_decision"
fi
AC_DEFINE_UNQUOTED(${ac_decision_item})
AC_MSG_RESULT([decision on $ac_decision_item... $ac_decision_msg])
fi
])
dnl
dnl APR_CHECK_SIZEOF_EXTENDED(INCLUDES, TYPE [, CROSS_SIZE])
dnl
dnl A variant of AC_CHECK_SIZEOF which allows the checking of
dnl sizes of non-builtin types
dnl
AC_DEFUN([APR_CHECK_SIZEOF_EXTENDED],
[changequote(<<, >>)dnl
dnl The name to #define.
define(<<AC_TYPE_NAME>>, translit(sizeof_$2, [a-z *], [A-Z_P]))dnl
dnl The cache variable name.
define(<<AC_CV_NAME>>, translit(ac_cv_sizeof_$2, [ *], [_p]))dnl
changequote([, ])dnl
AC_MSG_CHECKING(size of $2)
AC_CACHE_VAL(AC_CV_NAME,
[AC_TRY_RUN([#include <stdio.h>
$1
main()
{
FILE *f=fopen("conftestval", "w");
if (!f) exit(1);
fprintf(f, "%d\n", sizeof($2));
exit(0);
}], AC_CV_NAME=`cat conftestval`, AC_CV_NAME=0, ifelse([$3],,,
AC_CV_NAME=$3))])dnl
AC_MSG_RESULT($AC_CV_NAME)
AC_DEFINE_UNQUOTED(AC_TYPE_NAME, $AC_CV_NAME, [The size of ]$2)
undefine([AC_TYPE_NAME])dnl
undefine([AC_CV_NAME])dnl
])
dnl
dnl APR_TRY_COMPILE_NO_WARNING(INCLUDES, FUNCTION-BODY,
dnl [ACTIONS-IF-NO-WARNINGS], [ACTIONS-IF-WARNINGS])
dnl
dnl Tries a compile test with warnings activated so that the result
dnl is false if the code doesn't compile cleanly. For compilers
dnl where it is not known how to activate a "fail-on-error" mode,
dnl it is undefined which of the sets of actions will be run.
dnl
AC_DEFUN([APR_TRY_COMPILE_NO_WARNING],
[apr_save_CFLAGS=$CFLAGS
CFLAGS="$CFLAGS $CFLAGS_WARN"
if test "$ac_cv_prog_gcc" = "yes"; then
CFLAGS="$CFLAGS -Werror"
fi
AC_COMPILE_IFELSE(
[AC_LANG_SOURCE(
[#include "confdefs.h"
]
[[$1]]
[int main(int argc, const char *const *argv) {]
[[$2]]
[ return 0; }]
)],
[$3], [$4])
CFLAGS=$apr_save_CFLAGS
])
dnl
dnl APR_CHECK_STRERROR_R_RC
dnl
dnl Decide which style of retcode is used by this system's
dnl strerror_r(). It either returns int (0 for success, -1
dnl for failure), or it returns a pointer to the error
dnl string.
dnl
dnl
AC_DEFUN([APR_CHECK_STRERROR_R_RC], [
AC_MSG_CHECKING(for type of return code from strerror_r)
AC_TRY_RUN([
#include <errno.h>
#include <string.h>
#include <stdio.h>
main()
{
char buf[1024];
if (strerror_r(ERANGE, buf, sizeof buf) < 1) {
exit(0);
}
else {
exit(1);
}
}], [
ac_cv_strerror_r_rc_int=yes ], [
ac_cv_strerror_r_rc_int=no ], [
ac_cv_strerror_r_rc_int=no ] )
if test "x$ac_cv_strerror_r_rc_int" = xyes; then
AC_DEFINE(STRERROR_R_RC_INT, 1, [Define if strerror returns int])
msg="int"
else
msg="pointer"
fi
AC_MSG_RESULT([$msg])
] )
dnl
dnl APR_CHECK_DIRENT_INODE
dnl
dnl Decide if d_fileno or d_ino are available in the dirent
dnl structure on this platform. Single UNIX Spec says d_ino,
dnl BSD uses d_fileno. Undef to find the real beast.
dnl
AC_DEFUN([APR_CHECK_DIRENT_INODE], [
AC_CACHE_CHECK([for inode member of struct dirent], apr_cv_dirent_inode, [
apr_cv_dirent_inode=no
AC_TRY_COMPILE([
#include <sys/types.h>
#include <dirent.h>
],[
#ifdef d_ino
#undef d_ino
#endif
struct dirent de; de.d_fileno;
], apr_cv_dirent_inode=d_fileno)
if test "$apr_cv_dirent_inode" = "no"; then
AC_TRY_COMPILE([
#include <sys/types.h>
#include <dirent.h>
],[
#ifdef d_fileno
#undef d_fileno
#endif
struct dirent de; de.d_ino;
], apr_cv_dirent_inode=d_ino)
fi
])
if test "$apr_cv_dirent_inode" != "no"; then
AC_DEFINE_UNQUOTED(DIRENT_INODE, $apr_cv_dirent_inode,
[Define if struct dirent has an inode member])
fi
])
dnl
dnl APR_CHECK_DIRENT_TYPE
dnl
dnl Decide if d_type is available in the dirent structure
dnl on this platform. Not part of the Single UNIX Spec.
dnl Note that this is worthless without DT_xxx macros, so
dnl look for one while we are at it.
dnl
AC_DEFUN([APR_CHECK_DIRENT_TYPE], [
AC_CACHE_CHECK([for file type member of struct dirent], apr_cv_dirent_type,[
apr_cv_dirent_type=no
AC_TRY_COMPILE([
#include <sys/types.h>
#include <dirent.h>
],[
struct dirent de; de.d_type = DT_REG;
], apr_cv_dirent_type=d_type)
])
if test "$apr_cv_dirent_type" != "no"; then
AC_DEFINE_UNQUOTED(DIRENT_TYPE, $apr_cv_dirent_type,
[Define if struct dirent has a d_type member])
fi
])
dnl the following is a newline, a space, a tab, and a backslash (the
dnl backslash is used by the shell to skip newlines, but m4 sees it;
dnl treat it like whitespace).
dnl WARNING: don't reindent these lines, or the space/tab will be lost!
define([apr_whitespace],[
\])
dnl
dnl APR_COMMA_ARGS(ARG1 ...)
dnl convert the whitespace-separated arguments into comman-separated
dnl arguments.
dnl
dnl APR_FOREACH(CODE-BLOCK, ARG1, ARG2, ...)
dnl subsitute CODE-BLOCK for each ARG[i]. "eachval" will be set to ARG[i]
dnl within each iteration.
dnl
changequote({,})
define({APR_COMMA_ARGS},{patsubst([$}{1],[[}apr_whitespace{]+],[,])})
define({APR_FOREACH},
{ifelse($}{2,,,
[define([eachval],
$}{2)$}{1[]APR_FOREACH([$}{1],
builtin([shift],
builtin([shift], $}{@)))])})
changequote([,])
dnl APR_FLAG_HEADERS(HEADER-FILE ... [, FLAG-TO-SET ] [, "yes" ])
dnl we set FLAG-TO-SET to 1 if we find HEADER-FILE, otherwise we set to 0
dnl if FLAG-TO-SET is null, we automagically determine it's name
dnl by changing all "/" to "_" in the HEADER-FILE and dropping
dnl all "." and "-" chars. If the 3rd parameter is "yes" then instead of
dnl setting to 1 or 0, we set FLAG-TO-SET to yes or no.
dnl
AC_DEFUN([APR_FLAG_HEADERS], [
AC_CHECK_HEADERS($1)
for aprt_i in $1
do
ac_safe=`echo "$aprt_i" | sed 'y%./+-%__p_%'`
aprt_2=`echo "$aprt_i" | sed -e 's%/%_%g' -e 's/\.//g' -e 's/-//g'`
if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
eval "ifelse($2,,$aprt_2,$2)=ifelse($3,yes,yes,1)"
else
eval "ifelse($2,,$aprt_2,$2)=ifelse($3,yes,no,0)"
fi
done
])
dnl APR_FLAG_FUNCS(FUNC ... [, FLAG-TO-SET] [, "yes" ])
dnl if FLAG-TO-SET is null, we automagically determine it's name
dnl prepending "have_" to the function name in FUNC, otherwise
dnl we use what's provided as FLAG-TO-SET. If the 3rd parameter
dnl is "yes" then instead of setting to 1 or 0, we set FLAG-TO-SET
dnl to yes or no.
dnl
AC_DEFUN([APR_FLAG_FUNCS], [
AC_CHECK_FUNCS($1)
for aprt_j in $1
do
aprt_3="have_$aprt_j"
if eval "test \"`echo '$ac_cv_func_'$aprt_j`\" = yes"; then
eval "ifelse($2,,$aprt_3,$2)=ifelse($3,yes,yes,1)"
else
eval "ifelse($2,,$aprt_3,$2)=ifelse($3,yes,no,0)"
fi
done
])
dnl Iteratively interpolate the contents of the second argument
dnl until interpolation offers no new result. Then assign the
dnl final result to $1.
dnl
dnl Example:
dnl
dnl foo=1
dnl bar='${foo}/2'
dnl baz='${bar}/3'
dnl APR_EXPAND_VAR(fraz, $baz)
dnl $fraz is now "1/2/3"
dnl
AC_DEFUN([APR_EXPAND_VAR], [
ap_last=
ap_cur="$2"
while test "x${ap_cur}" != "x${ap_last}";
do
ap_last="${ap_cur}"
ap_cur=`eval "echo ${ap_cur}"`
done
$1="${ap_cur}"
])
dnl
dnl Removes the value of $3 from the string in $2, strips of any leading
dnl slashes, and returns the value in $1.
dnl
dnl Example:
dnl orig_path="${prefix}/bar"
dnl APR_PATH_RELATIVE(final_path, $orig_path, $prefix)
dnl $final_path now contains "bar"
AC_DEFUN([APR_PATH_RELATIVE], [
ap_stripped=`echo $2 | sed -e "s#^$3##"`
# check if the stripping was successful
if test "x$2" != "x${ap_stripped}"; then
# it was, so strip of any leading slashes
$1="`echo ${ap_stripped} | sed -e 's#^/*##'`"
else
# it wasn't so return the original
$1="$2"
fi
])
dnl APR_HELP_STRING(LHS, RHS)
dnl Autoconf 2.50 can not handle substr correctly. It does have
dnl AC_HELP_STRING, so let's try to call it if we can.
dnl Note: this define must be on one line so that it can be properly returned
dnl as the help string. When using this macro with a multi-line RHS, ensure
dnl that you surround the macro invocation with []s
AC_DEFUN([APR_HELP_STRING], [ifelse(regexp(AC_ACVERSION, 2\.1), -1, AC_HELP_STRING([$1],[$2]),[ ][$1] substr([ ],len($1))[$2])])
dnl
dnl APR_LAYOUT(configlayout, layoutname [, extravars])
dnl
AC_DEFUN([APR_LAYOUT], [
if test ! -f $srcdir/config.layout; then
echo "** Error: Layout file $srcdir/config.layout not found"
echo "** Error: Cannot use undefined layout '$LAYOUT'"
exit 1
fi
# Catch layout names including a slash which will otherwise
# confuse the heck out of the sed script.
case $2 in
*/*)
echo "** Error: $2 is not a valid layout name"
exit 1 ;;
esac
pldconf=./config.pld
changequote({,})
sed -e "1s/[ ]*<[lL]ayout[ ]*$2[ ]*>[ ]*//;1t" \
-e "1,/[ ]*<[lL]ayout[ ]*$2[ ]*>[ ]*/d" \
-e '/[ ]*<\/Layout>[ ]*/,$d' \
-e "s/^[ ]*//g" \
-e "s/:[ ]*/=\'/g" \
-e "s/[ ]*$/'/g" \
$1 > $pldconf
layout_name=$2
if test ! -s $pldconf; then
echo "** Error: unable to find layout $layout_name"
exit 1
fi
. $pldconf
rm $pldconf
for var in prefix exec_prefix bindir sbindir libexecdir mandir \
sysconfdir datadir includedir localstatedir runtimedir \
logfiledir libdir installbuilddir libsuffix $3; do
eval "val=\"\$$var\""
case $val in
*+)
val=`echo $val | sed -e 's;\+$;;'`
eval "$var=\"\$val\""
autosuffix=yes
;;
*)
autosuffix=no
;;
esac
val=`echo $val | sed -e 's:\(.\)/*$:\1:'`
val=`echo $val | sed -e 's:[\$]\([a-z_]*\):${\1}:g'`
if test "$autosuffix" = "yes"; then
if echo $val | grep apache >/dev/null; then
addtarget=no
else
addtarget=yes
fi
if test "$addtarget" = "yes"; then
val="$val/apache2"
fi
fi
eval "$var='$val'"
done
changequote([,])
])dnl
dnl
dnl APR_ENABLE_LAYOUT(default layout name [, extra vars])
dnl
AC_DEFUN([APR_ENABLE_LAYOUT], [
AC_ARG_ENABLE(layout,
[ --enable-layout=LAYOUT],[
LAYOUT=$enableval
])
if test -z "$LAYOUT"; then
LAYOUT="$1"
fi
APR_LAYOUT($srcdir/config.layout, $LAYOUT, $2)
AC_MSG_CHECKING(for chosen layout)
AC_MSG_RESULT($layout_name)
])
dnl
dnl APR_PARSE_ARGUMENTS
dnl a reimplementation of autoconf's argument parser,
dnl used here to allow us to co-exist layouts and argument based
dnl set ups.
AC_DEFUN([APR_PARSE_ARGUMENTS], [
ac_prev=
# Retrieve the command-line arguments. The eval is needed because
# the arguments are quoted to preserve accuracy.
eval "set x $ac_configure_args"
shift
for ac_option
do
# If the previous option needs an argument, assign it.
if test -n "$ac_prev"; then
eval "$ac_prev=\$ac_option"
ac_prev=
continue
fi
ac_optarg=`expr "x$ac_option" : 'x[[^=]]*=\(.*\)'`
case $ac_option in
-bindir | --bindir | --bindi | --bind | --bin | --bi)
ac_prev=bindir ;;
-bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
bindir="$ac_optarg" ;;
-datadir | --datadir | --datadi | --datad | --data | --dat | --da)
ac_prev=datadir ;;
-datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
| --da=*)
datadir="$ac_optarg" ;;
-exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
| --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
| --exec | --exe | --ex)
ac_prev=exec_prefix ;;
-exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
| --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
| --exec=* | --exe=* | --ex=*)
exec_prefix="$ac_optarg" ;;
-includedir | --includedir | --includedi | --included | --include \
| --includ | --inclu | --incl | --inc)
ac_prev=includedir ;;
-includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
| --includ=* | --inclu=* | --incl=* | --inc=*)
includedir="$ac_optarg" ;;
-infodir | --infodir | --infodi | --infod | --info | --inf)
ac_prev=infodir ;;
-infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
infodir="$ac_optarg" ;;
-libdir | --libdir | --libdi | --libd)
ac_prev=libdir ;;
-libdir=* | --libdir=* | --libdi=* | --libd=*)
libdir="$ac_optarg" ;;
-libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
| --libexe | --libex | --libe)
ac_prev=libexecdir ;;
-libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
| --libexe=* | --libex=* | --libe=*)
libexecdir="$ac_optarg" ;;
-localstatedir | --localstatedir | --localstatedi | --localstated \
| --localstate | --localstat | --localsta | --localst \
| --locals | --local | --loca | --loc | --lo)
ac_prev=localstatedir ;;
-localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
| --localstate=* | --localstat=* | --localsta=* | --localst=* \
| --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
localstatedir="$ac_optarg" ;;
-mandir | --mandir | --mandi | --mand | --man | --ma | --m)
ac_prev=mandir ;;
-mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
mandir="$ac_optarg" ;;
-prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
ac_prev=prefix ;;
-prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
prefix="$ac_optarg" ;;
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
| --sbi=* | --sb=*)
sbindir="$ac_optarg" ;;
-sharedstatedir | --sharedstatedir | --sharedstatedi \
| --sharedstated | --sharedstate | --sharedstat | --sharedsta \
| --sharedst | --shareds | --shared | --share | --shar \
| --sha | --sh)
ac_prev=sharedstatedir ;;
-sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
| --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
| --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
| --sha=* | --sh=*)
sharedstatedir="$ac_optarg" ;;
-sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
| --syscon | --sysco | --sysc | --sys | --sy)
ac_prev=sysconfdir ;;
-sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
| --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
sysconfdir="$ac_optarg" ;;
esac
done
# Be sure to have absolute paths.
for ac_var in exec_prefix prefix
do
eval ac_val=$`echo $ac_var`
case $ac_val in
[[\\/$]]* | ?:[[\\/]]* | NONE | '' ) ;;
*) AC_MSG_ERROR([expected an absolute path for --$ac_var: $ac_val]);;
esac
done
])dnl
dnl
dnl APR_CHECK_DEPEND
dnl
dnl Determine what program we can use to generate .deps-style dependencies
dnl
AC_DEFUN([APR_CHECK_DEPEND], [
dnl Try to determine what depend program we can use
dnl All GCC-variants should have -MM.
dnl If not, then we can check on those, too.
if test "$GCC" = "yes"; then
MKDEP='$(CC) -MM'
else
rm -f conftest.c
dnl <sys/types.h> should be available everywhere!
cat > conftest.c <<EOF
#include <sys/types.h>
int main() { return 0; }
EOF
MKDEP="true"
for i in "$CC -MM" "$CC -M" "$CPP -MM" "$CPP -M" "cpp -M"; do
AC_MSG_CHECKING([if $i can create proper make dependencies])
if $i conftest.c 2>/dev/null | grep 'conftest.o: conftest.c' >/dev/null; then
MKDEP=$i
AC_MSG_RESULT(yes)
break;
fi
AC_MSG_RESULT(no)
done
rm -f conftest.c
fi
AC_SUBST(MKDEP)
])
dnl
dnl APR_CHECK_TYPES_COMPATIBLE(TYPE-1, TYPE-2, [ACTION-IF-TRUE])
dnl
dnl Try to determine whether two types are the same. Only works
dnl for gcc and icc.
dnl
AC_DEFUN([APR_CHECK_TYPES_COMPATIBLE], [
define([apr_cvname], apr_cv_typematch_[]translit([$1], [ ], [_])_[]translit([$2], [ ], [_]))
AC_CACHE_CHECK([whether $1 and $2 are the same], apr_cvname, [
AC_TRY_COMPILE(AC_INCLUDES_DEFAULT, [
int foo[0 - !__builtin_types_compatible_p($1, $2)];
], [apr_cvname=yes
$3], [apr_cvname=no])])
])

56
build/check.py Executable file
View File

@ -0,0 +1,56 @@
#!/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)
print "== Running the unit tests =="
try:
subprocess.check_call(TEST_ALL_EXE)
except subprocess.CalledProcessError:
print "ERROR: test(s) failed in test_all"

1544
build/config.guess vendored

File diff suppressed because it is too large Load Diff

1788
build/config.sub vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,202 +0,0 @@
dnl -------------------------------------------------------- -*- autoconf -*-
dnl Licensed to the Apache Software Foundation (ASF) under one or more
dnl contributor license agreements. See the NOTICE file distributed with
dnl this work for additional information regarding copyright ownership.
dnl The ASF licenses this file to You under the Apache License, Version 2.0
dnl (the "License"); you may not use this file except in compliance with
dnl the License. You may obtain a copy of the License at
dnl
dnl http://www.apache.org/licenses/LICENSE-2.0
dnl
dnl Unless required by applicable law or agreed to in writing, software
dnl distributed under the License is distributed on an "AS IS" BASIS,
dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
dnl See the License for the specific language governing permissions and
dnl limitations under the License.
dnl
dnl find_apr.m4 : locate the APR include files and libraries
dnl
dnl This macro file can be used by applications to find and use the APR
dnl library. It provides a standardized mechanism for using APR. It supports
dnl embedding APR into the application source, or locating an installed
dnl copy of APR.
dnl
dnl APR_FIND_APR(srcdir, builddir, implicit-install-check, acceptable-majors,
dnl detailed-check)
dnl
dnl where srcdir is the location of the bundled APR source directory, or
dnl empty if source is not bundled.
dnl
dnl where builddir is the location where the bundled APR will will be built,
dnl or empty if the build will occur in the srcdir.
dnl
dnl where implicit-install-check set to 1 indicates if there is no
dnl --with-apr option specified, we will look for installed copies.
dnl
dnl where acceptable-majors is a space separated list of acceptable major
dnl version numbers. Often only a single major version will be acceptable.
dnl If multiple versions are specified, and --with-apr=PREFIX or the
dnl implicit installed search are used, then the first (leftmost) version
dnl in the list that is found will be used. Currently defaults to [0 1].
dnl
dnl where detailed-check is an M4 macro which sets the apr_acceptable to
dnl either "yes" or "no". The macro will be invoked for each installed
dnl copy of APR found, with the apr_config variable set appropriately.
dnl Only installed copies of APR which are considered acceptable by
dnl this macro will be considered found. If no installed copies are
dnl considered acceptable by this macro, apr_found will be set to either
dnl either "no" or "reconfig".
dnl
dnl Sets the following variables on exit:
dnl
dnl apr_found : "yes", "no", "reconfig"
dnl
dnl apr_config : If the apr-config tool exists, this refers to it. If
dnl apr_found is "reconfig", then the bundled directory
dnl should be reconfigured *before* using apr_config.
dnl
dnl Note: this macro file assumes that apr-config has been installed; it
dnl is normally considered a required part of an APR installation.
dnl
dnl If a bundled source directory is available and needs to be (re)configured,
dnl then apr_found is set to "reconfig". The caller should reconfigure the
dnl (passed-in) source directory, placing the result in the build directory,
dnl as appropriate.
dnl
dnl If apr_found is "yes" or "reconfig", then the caller should use the
dnl value of apr_config to fetch any necessary build/link information.
dnl
AC_DEFUN([APR_FIND_APR], [
apr_found="no"
if test "$target_os" = "os2-emx"; then
# Scripts don't pass test -x on OS/2
TEST_X="test -f"
else
TEST_X="test -x"
fi
ifelse([$4], [], [
ifdef(AC_WARNING,AC_WARNING([$0: missing argument 4 (acceptable-majors): Defaulting to APR 0.x then APR 1.x]))
acceptable_majors="0 1"],
[acceptable_majors="$4"])
apr_temp_acceptable_apr_config=""
for apr_temp_major in $acceptable_majors
do
case $apr_temp_major in
0)
apr_temp_acceptable_apr_config="$apr_temp_acceptable_apr_config apr-config"
;;
*)
apr_temp_acceptable_apr_config="$apr_temp_acceptable_apr_config apr-$apr_temp_major-config"
;;
esac
done
AC_MSG_CHECKING(for APR)
AC_ARG_WITH(apr,
[ --with-apr=PATH prefix for installed APR or the full path to
apr-config],
[
if test "$withval" = "no" || test "$withval" = "yes"; then
AC_MSG_ERROR([--with-apr requires a directory or file to be provided])
fi
for apr_temp_apr_config_file in $apr_temp_acceptable_apr_config
do
for lookdir in "$withval/bin" "$withval"
do
if $TEST_X "$lookdir/$apr_temp_apr_config_file"; then
apr_config="$lookdir/$apr_temp_apr_config_file"
ifelse([$5], [], [], [
apr_acceptable="yes"
$5
if test "$apr_acceptable" != "yes"; then
AC_MSG_WARN([Found APR in $apr_config, but we think it is considered unacceptable])
continue
fi])
apr_found="yes"
break 2
fi
done
done
if test "$apr_found" != "yes" && $TEST_X "$withval" && $withval --help > /dev/null 2>&1 ; then
apr_config="$withval"
ifelse([$5], [], [apr_found="yes"], [
apr_acceptable="yes"
$5
if test "$apr_acceptable" = "yes"; then
apr_found="yes"
fi])
fi
dnl if --with-apr is used, it is a fatal error for its argument
dnl to be invalid
if test "$apr_found" != "yes"; then
AC_MSG_ERROR([the --with-apr parameter is incorrect. It must specify an install prefix, a build directory, or an apr-config file.])
fi
],[
dnl If we allow installed copies, check those before using bundled copy.
if test -n "$3" && test "$3" = "1"; then
for apr_temp_apr_config_file in $apr_temp_acceptable_apr_config
do
if $apr_temp_apr_config_file --help > /dev/null 2>&1 ; then
apr_config="$apr_temp_apr_config_file"
ifelse([$5], [], [], [
apr_acceptable="yes"
$5
if test "$apr_acceptable" != "yes"; then
AC_MSG_WARN([skipped APR at $apr_config, version not acceptable])
continue
fi])
apr_found="yes"
break
else
dnl look in some standard places
for lookdir in /usr /usr/local /usr/local/apr /opt/apr; do
if $TEST_X "$lookdir/bin/$apr_temp_apr_config_file"; then
apr_config="$lookdir/bin/$apr_temp_apr_config_file"
ifelse([$5], [], [], [
apr_acceptable="yes"
$5
if test "$apr_acceptable" != "yes"; then
AC_MSG_WARN([skipped APR at $apr_config, version not acceptable])
continue
fi])
apr_found="yes"
break 2
fi
done
fi
done
fi
dnl if we have not found anything yet and have bundled source, use that
if test "$apr_found" = "no" && test -d "$1"; then
apr_temp_abs_srcdir="`cd \"$1\" && pwd`"
apr_found="reconfig"
apr_bundled_major="`sed -n '/#define.*APR_MAJOR_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p' \"$1/include/apr_version.h\"`"
case $apr_bundled_major in
"")
AC_MSG_ERROR([failed to find major version of bundled APR])
;;
0)
apr_temp_apr_config_file="apr-config"
;;
*)
apr_temp_apr_config_file="apr-$apr_bundled_major-config"
;;
esac
if test -n "$2"; then
apr_config="$2/$apr_temp_apr_config_file"
else
apr_config="$1/$apr_temp_apr_config_file"
fi
fi
])
AC_MSG_RESULT($apr_found)
])

View File

@ -1,211 +0,0 @@
dnl -------------------------------------------------------- -*- autoconf -*-
dnl Licensed to the Apache Software Foundation (ASF) under one or more
dnl contributor license agreements. See the NOTICE file distributed with
dnl this work for additional information regarding copyright ownership.
dnl The ASF licenses this file to You under the Apache License, Version 2.0
dnl (the "License"); you may not use this file except in compliance with
dnl the License. You may obtain a copy of the License at
dnl
dnl http://www.apache.org/licenses/LICENSE-2.0
dnl
dnl Unless required by applicable law or agreed to in writing, software
dnl distributed under the License is distributed on an "AS IS" BASIS,
dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
dnl See the License for the specific language governing permissions and
dnl limitations under the License.
dnl
dnl find_apu.m4 : locate the APR-util (APU) include files and libraries
dnl
dnl This macro file can be used by applications to find and use the APU
dnl library. It provides a standardized mechanism for using APU. It supports
dnl embedding APU into the application source, or locating an installed
dnl copy of APU.
dnl
dnl APR_FIND_APU(srcdir, builddir, implicit-install-check, acceptable-majors,
dnl detailed-check)
dnl
dnl where srcdir is the location of the bundled APU source directory, or
dnl empty if source is not bundled.
dnl
dnl where builddir is the location where the bundled APU will be built,
dnl or empty if the build will occur in the srcdir.
dnl
dnl where implicit-install-check set to 1 indicates if there is no
dnl --with-apr-util option specified, we will look for installed copies.
dnl
dnl where acceptable-majors is a space separated list of acceptable major
dnl version numbers. Often only a single major version will be acceptable.
dnl If multiple versions are specified, and --with-apr-util=PREFIX or the
dnl implicit installed search are used, then the first (leftmost) version
dnl in the list that is found will be used. Currently defaults to [0 1].
dnl
dnl where detailed-check is an M4 macro which sets the apu_acceptable to
dnl either "yes" or "no". The macro will be invoked for each installed
dnl copy of APU found, with the apu_config variable set appropriately.
dnl Only installed copies of APU which are considered acceptable by
dnl this macro will be considered found. If no installed copies are
dnl considered acceptable by this macro, apu_found will be set to either
dnl either "no" or "reconfig".
dnl
dnl Sets the following variables on exit:
dnl
dnl apu_found : "yes", "no", "reconfig"
dnl
dnl apu_config : If the apu-config tool exists, this refers to it. If
dnl apu_found is "reconfig", then the bundled directory
dnl should be reconfigured *before* using apu_config.
dnl
dnl Note: this macro file assumes that apr-config has been installed; it
dnl is normally considered a required part of an APR installation.
dnl
dnl Note: At this time, we cannot find *both* a source dir and a build dir.
dnl If both are available, the build directory should be passed to
dnl the --with-apr-util switch.
dnl
dnl Note: the installation layout is presumed to follow the standard
dnl PREFIX/lib and PREFIX/include pattern. If the APU config file
dnl is available (and can be found), then non-standard layouts are
dnl possible, since it will be described in the config file.
dnl
dnl If a bundled source directory is available and needs to be (re)configured,
dnl then apu_found is set to "reconfig". The caller should reconfigure the
dnl (passed-in) source directory, placing the result in the build directory,
dnl as appropriate.
dnl
dnl If apu_found is "yes" or "reconfig", then the caller should use the
dnl value of apu_config to fetch any necessary build/link information.
dnl
AC_DEFUN([APR_FIND_APU], [
apu_found="no"
if test "$target_os" = "os2-emx"; then
# Scripts don't pass test -x on OS/2
TEST_X="test -f"
else
TEST_X="test -x"
fi
ifelse([$4], [],
[
ifdef(AC_WARNING,([$0: missing argument 4 (acceptable-majors): Defaulting to APU 0.x then APU 1.x]))
acceptable_majors="0 1"
], [acceptable_majors="$4"])
apu_temp_acceptable_apu_config=""
for apu_temp_major in $acceptable_majors
do
case $apu_temp_major in
0)
apu_temp_acceptable_apu_config="$apu_temp_acceptable_apu_config apu-config"
;;
*)
apu_temp_acceptable_apu_config="$apu_temp_acceptable_apu_config apu-$apu_temp_major-config"
;;
esac
done
AC_MSG_CHECKING(for APR-util)
AC_ARG_WITH(apr-util,
[ --with-apr-util=PATH prefix for installed APU or the full path to
apu-config],
[
if test "$withval" = "no" || test "$withval" = "yes"; then
AC_MSG_ERROR([--with-apr-util requires a directory or file to be provided])
fi
for apu_temp_apu_config_file in $apu_temp_acceptable_apu_config
do
for lookdir in "$withval/bin" "$withval"
do
if $TEST_X "$lookdir/$apu_temp_apu_config_file"; then
apu_config="$lookdir/$apu_temp_apu_config_file"
ifelse([$5], [], [], [
apu_acceptable="yes"
$5
if test "$apu_acceptable" != "yes"; then
AC_MSG_WARN([Found APU in $apu_config, but it is considered unacceptable])
continue
fi])
apu_found="yes"
break 2
fi
done
done
if test "$apu_found" != "yes" && $TEST_X "$withval" && $withval --help > /dev/null 2>&1 ; then
apu_config="$withval"
ifelse([$5], [], [apu_found="yes"], [
apu_acceptable="yes"
$5
if test "$apu_acceptable" = "yes"; then
apu_found="yes"
fi])
fi
dnl if --with-apr-util is used, it is a fatal error for its argument
dnl to be invalid
if test "$apu_found" != "yes"; then
AC_MSG_ERROR([the --with-apr-util parameter is incorrect. It must specify an install prefix, a build directory, or an apu-config file.])
fi
],[
if test -n "$3" && test "$3" = "1"; then
for apu_temp_apu_config_file in $apu_temp_acceptable_apu_config
do
if $apu_temp_apu_config_file --help > /dev/null 2>&1 ; then
apu_config="$apu_temp_apu_config_file"
ifelse([$5], [], [], [
apu_acceptable="yes"
$5
if test "$apu_acceptable" != "yes"; then
AC_MSG_WARN([skipped APR-util at $apu_config, version not acceptable])
continue
fi])
apu_found="yes"
break
else
dnl look in some standard places (apparently not in builtin/default)
for lookdir in /usr /usr/local /usr/local/apr /opt/apr; do
if $TEST_X "$lookdir/bin/$apu_temp_apu_config_file"; then
apu_config="$lookdir/bin/$apu_temp_apu_config_file"
ifelse([$5], [], [], [
apu_acceptable="yes"
$5
if test "$apu_acceptable" != "yes"; then
AC_MSG_WARN([skipped APR-util at $apu_config, version not acceptable])
continue
fi])
apu_found="yes"
break 2
fi
done
fi
done
fi
dnl if we have not found anything yet and have bundled source, use that
if test "$apu_found" = "no" && test -d "$1"; then
apu_temp_abs_srcdir="`cd \"$1\" && pwd`"
apu_found="reconfig"
apu_bundled_major="`sed -n '/#define.*APU_MAJOR_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p' \"$1/include/apu_version.h\"`"
case $apu_bundled_major in
"")
AC_MSG_ERROR([failed to find major version of bundled APU])
;;
0)
apu_temp_apu_config_file="apu-config"
;;
*)
apu_temp_apu_config_file="apu-$apu_bundled_major-config"
;;
esac
if test -n "$2"; then
apu_config="$2/$apu_temp_apu_config_file"
else
apu_config="$1/$apu_temp_apu_config_file"
fi
fi
])
AC_MSG_RESULT($apu_found)
])

View File

@ -58,11 +58,19 @@ def extract_exports(fname):
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:]:
for func in extract_exports(fname):
funclist = extract_exports(fname)
funclist = set(funclist) - set(blacklist)
for func in funclist:
print(func)

View File

@ -1,37 +0,0 @@
#!/bin/sh
#
# extract version numbers from a header file
#
# USAGE: get-version.sh CMD VERSION_HEADER PREFIX
# where CMD is one of: all, major, libtool
# where PREFIX is the prefix to {MAJOR|MINOR|PATCH}_VERSION defines
#
# get-version.sh all returns a dotted version number
# get-version.sh major returns just the major version number
# get-version.sh libtool returns a version "libtool -version-info" format
#
if test $# != 3; then
echo "USAGE: $0 CMD VERSION_HEADER PREFIX"
echo " where CMD is one of: all, major, libtool"
exit 1
fi
major_sed="/#define.*$3_MAJOR_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p"
minor_sed="/#define.*$3_MINOR_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p"
patch_sed="/#define.*$3_PATCH_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p"
major="`sed -n $major_sed $2`"
minor="`sed -n $minor_sed $2`"
patch="`sed -n $patch_sed $2`"
if test "$1" = "all"; then
echo ${major}.${minor}.${patch}
elif test "$1" = "major"; then
echo ${major}
elif test "$1" = "libtool"; then
# Yes, ${minor}:${patch}:${minor} is correct due to libtool idiocy.
echo ${minor}:${patch}:${minor}
else
echo "ERROR: unknown version CMD ($1)"
exit 1
fi

View File

@ -1,112 +0,0 @@
#!/bin/sh
##
## install.sh -- install a program, script or datafile
##
## Based on `install-sh' from the X Consortium's X11R5 distribution
## as of 89/12/18 which is freely available.
## Cleaned up for Apache's Autoconf-style Interface (APACI)
## by Ralf S. Engelschall <rse@apache.org>
##
#
# This script falls under the Apache License.
# See http://www.apache.org/docs/LICENSE
#
# put in absolute paths if you don't have them in your path;
# or use env. vars.
#
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
#
# parse argument line
#
instcmd="$mvprog"
chmodcmd=""
chowncmd=""
chgrpcmd=""
stripcmd=""
rmcmd="$rmprog -f"
mvcmd="$mvprog"
ext=""
src=""
dst=""
while [ "x$1" != "x" ]; do
case $1 in
-c) instcmd="$cpprog"
shift; continue
;;
-m) chmodcmd="$chmodprog $2"
shift; shift; continue
;;
-o) chowncmd="$chownprog $2"
shift; shift; continue
;;
-g) chgrpcmd="$chgrpprog $2"
shift; shift; continue
;;
-s) stripcmd="$stripprog"
shift; continue
;;
-S) stripcmd="$stripprog $2"
shift; shift; continue
;;
-e) ext="$2"
shift; shift; continue
;;
*) if [ "x$src" = "x" ]; then
src=$1
else
dst=$1
fi
shift; continue
;;
esac
done
if [ "x$src" = "x" ]; then
echo "install.sh: no input file specified"
exit 1
fi
if [ "x$dst" = "x" ]; then
echo "install.sh: no destination specified"
exit 1
fi
#
# If destination is a directory, append the input filename; if
# your system does not like double slashes in filenames, you may
# need to add some logic
#
if [ -d $dst ]; then
dst="$dst/`basename $src`"
fi
# Add a possible extension (such as ".exe") to src and dst
src="$src$ext"
dst="$dst$ext"
# Make a temp file name in the proper directory.
dstdir=`dirname $dst`
dsttmp=$dstdir/#inst.$$#
# Move or copy the file name to the temp name
$instcmd $src $dsttmp
# And set any options; do chmod last to preserve setuid bits
if [ "x$chowncmd" != "x" ]; then $chowncmd $dsttmp; fi
if [ "x$chgrpcmd" != "x" ]; then $chgrpcmd $dsttmp; fi
if [ "x$stripcmd" != "x" ]; then $stripcmd $dsttmp; fi
if [ "x$chmodcmd" != "x" ]; then $chmodcmd $dsttmp; fi
# Now rename the file to the real destination.
$rmcmd $dst
$mvcmd $dsttmp $dst
exit 0

View File

@ -1,141 +0,0 @@
EXPORTS
serf_error_string
serf_context_create
serf_context_create_ex
serf_event_trigger
serf_context_run
serf_context_prerun
serf_context_set_progress_cb
serf_connection_create
serf_connection_create2
serf_listener_create
serf_incoming_create
serf_connection_reset
serf_connection_close
serf_connection_set_max_outstanding_requests
serf_connection_set_async_responses
serf_connection_request_create
serf_connection_priority_request_create
serf_connection_get_latency
serf_request_is_written
serf_request_cancel
serf_request_get_pool
serf_request_get_alloc
serf_request_get_conn
serf_request_set_handler
serf_config_proxy
serf_config_authn_types
serf_config_credentials_callback
serf_context_bucket_socket_create
serf_request_bucket_request_create
serf_bucket_allocator_create
serf_bucket_allocator_get_pool
serf_linebuf_init
serf_linebuf_fetch
serf_debug__record_read
serf_debug__entered_loop
serf_debug__closed_conn
serf_debug__bucket_destroy
serf_debug__bucket_alloc_check
serf_lib_version
serf_bucket_request_create
serf_bucket_request_get_headers
serf_bucket_request_become
serf_bucket_request_set_root
serf_bucket_response_create
serf_bucket_response_status
serf_bucket_response_wait_for_headers
serf_bucket_response_get_headers
serf_bucket_response_set_head
serf_bucket_response_body_create
serf_bucket_bwtp_frame_get_channel
serf_bucket_bwtp_frame_get_type
serf_bucket_bwtp_frame_get_phrase
serf_bucket_bwtp_frame_get_headers
serf_bucket_bwtp_channel_open
serf_bucket_bwtp_channel_close
serf_bucket_bwtp_header_create
serf_bucket_bwtp_message_create
serf_bucket_bwtp_incoming_frame_create
serf_bucket_bwtp_incoming_frame_wait_for_headers
serf_bucket_aggregate_cleanup
serf_bucket_aggregate_create
serf_bucket_aggregate_become
serf_bucket_aggregate_prepend
serf_bucket_aggregate_append
serf_bucket_aggregate_hold_open
serf_bucket_aggregate_prepend_iovec
serf_bucket_aggregate_append_iovec
serf_bucket_file_create
serf_bucket_socket_create
serf_bucket_socket_set_read_progress_cb
serf_bucket_simple_create
serf_bucket_simple_copy_create
serf_bucket_mmap_create
serf_bucket_headers_create
serf_bucket_headers_set
serf_bucket_headers_setc
serf_bucket_headers_setn
serf_bucket_headers_setx
serf_bucket_headers_get
serf_bucket_headers_do
serf_bucket_chunk_create
serf_bucket_dechunk_create
serf_bucket_deflate_create
serf_bucket_limit_create
serf_ssl_client_cert_provider_set
serf_ssl_client_cert_password_set
serf_ssl_server_cert_callback_set
serf_ssl_server_cert_chain_callback_set
serf_ssl_use_default_certificates
serf_ssl_set_hostname
serf_ssl_cert_depth
serf_ssl_cert_issuer
serf_ssl_cert_subject
serf_ssl_cert_certificate
serf_ssl_cert_export
serf_ssl_load_cert_file
serf_ssl_trust_cert
serf_ssl_use_compression
serf_bucket_ssl_encrypt_create
serf_bucket_ssl_encrypt_context_get
serf_bucket_ssl_decrypt_create
serf_bucket_ssl_decrypt_context_get
serf_bucket_barrier_create
serf_bucket_iovec_create
serf_bucket_type_request
serf_bucket_type_response
serf_bucket_type_response_body
serf_bucket_type_bwtp_frame
serf_bucket_type_bwtp_incoming_frame
serf_bucket_type_aggregate
serf_bucket_type_file
serf_bucket_type_socket
serf_bucket_type_simple
serf_bucket_type_mmap
serf_bucket_type_headers
serf_bucket_type_chunk
serf_bucket_type_dechunk
serf_bucket_type_deflate
serf_bucket_type_limit
serf_bucket_type_ssl_encrypt
serf_bucket_type_ssl_decrypt
serf_bucket_type_barrier
serf_bucket_type_iovec
serf_bucket_create
serf_default_read_iovec
serf_default_read_for_sendfile
serf_default_read_bucket
serf_default_destroy
serf_default_destroy_and_data
serf_bucket_mem_alloc
serf_bucket_mem_calloc
serf_bucket_mem_free
serf_bstrmemdup
serf_bmemdup
serf_bstrdup
serf_util_readline
serf_databuf_init
serf_databuf_read
serf_databuf_readline
serf_databuf_peek

13
build/serf.pc.in Normal file
View File

@ -0,0 +1,13 @@
SERF_MAJOR_VERSION=@MAJOR@
prefix=@PREFIX@
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include/@INCLUDE_SUBDIR@
Name: serf
Description: HTTP client library
Version: @VERSION@
Requires.private: libssl libcrypto
Libs: -L${libdir} -lserf-${SERF_MAJOR_VERSION}
Libs.private: @LIBS@
Cflags: -I${includedir}

119
buildconf
View File

@ -1,119 +0,0 @@
#!/bin/sh
#
# Copyright 2005 Justin Erenkrantz and Greg Stein
# Copyright 2005 The Apache Software Foundation or its licensors, as
# applicable.
#
# 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.
#
#
# buildconf: Build the support scripts needed to compile from a
# checked-out version of the source code.
# set a couple of defaults for where we should be looking for our support libs.
# can be overridden with --with-apr=[dir] and --with-apr-util=[dir]
apr_src_dir="apr ../apr"
apu_src_dir="apr-util ../apr-util"
while test $# -gt 0
do
# Normalize
case "$1" in
-*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
*) optarg= ;;
esac
case "$1" in
--with-apr=*)
apr_src_dir=$optarg
;;
esac
case "$1" in
--with-apr-util=*)
apu_src_dir=$optarg
;;
esac
shift
done
#
# Check to be sure that we have the srclib dependencies checked-out
#
should_exit=0
apr_found=0
apu_found=0
for dir in $apr_src_dir
do
if [ -d "${dir}" -a -f "${dir}/build/apr_common.m4" ]; then
echo "found apr source: ${dir}"
apr_src_dir=$dir
apr_found=1
break
fi
done
if [ $apr_found -lt 1 ]; then
echo ""
echo "You don't have a copy of the apr source in srclib/apr. "
echo "Please get the source using the following instructions,"
echo "or specify the location of the source with "
echo "--with-apr=[path to apr] :"
echo ""
echo " svn co http://svn.apache.org/repos/asf/apr/apr/trunk srclib/apr"
echo ""
should_exit=1
fi
for dir in $apu_src_dir
do
if [ -d "${dir}" -a -f "${dir}/Makefile.in" ]; then
echo "found apr-util source: ${dir}"
apu_src_dir=$dir
apu_found=1
break
fi
done
if [ $apu_found -lt 1 ]; then
echo ""
echo "APR-util not found. Assuming you are using APR 2.x."
echo ""
apu_src_dir=
fi
if [ $should_exit -gt 0 ]; then
exit 1
fi
echo copying build files
cp $apr_src_dir/build/config.guess $apr_src_dir/build/config.sub \
$apr_src_dir/build/install.sh $apr_src_dir/build/apr_common.m4 \
$apr_src_dir/build/find_apr.m4 $apr_src_dir/build/get-version.sh build
if [ -n "$apu_src_dir" -a -d "$apu_src_dir" ] ; then
cp $apu_src_dir/build/find_apu.m4 build
fi
echo generating configure
${AUTOCONF:-autoconf}
# Remove autoconf 2.5x's cache directory
rm -rf autom4te*.cache
echo generating serf.def
./build/gen_def.py serf.h serf_bucket_*.h > build/serf.def

View File

@ -1,26 +0,0 @@
##
## config.layout -- Pre-defined Installation Path Layouts
##
## Hints:
## - layouts can be loaded with configure's --enable-layout=ID option
## - when no --enable-layout option is given, the default layout is `serf'
## - a trailing plus character (`+') on paths is replaced with a
## `/<target>' suffix where <target> is currently hardcoded to 'serf'.
## (This may become a configurable parameter at some point.)
##
<Layout Serf>
prefix: /usr/local/serf
exec_prefix: ${prefix}
bindir: ${exec_prefix}/bin
sbindir: ${exec_prefix}/bin
libdir: ${exec_prefix}/lib
libexecdir: ${exec_prefix}/modules
mandir: ${prefix}/man
sysconfdir: ${prefix}/conf
datadir: ${prefix}
installbuilddir: ${datadir}/build-${SERF_MAJOR_VERSION}
includedir: ${prefix}/include/serf-${SERF_MAJOR_VERSION}
localstatedir: ${prefix}
libsuffix: -${SERF_MAJOR_VERSION}
</Layout>

6326
configure vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,277 +0,0 @@
dnl Autoconf file for Serf
AC_PREREQ(2.50)
AC_INIT(context.c)
AC_CONFIG_AUX_DIR(build)
sinclude(build/apr_common.m4)
sinclude(build/find_apr.m4)
AC_PREFIX_DEFAULT(/usr/local/serf)
dnl Get the layout here, so we can pass the required variables to apr
APR_ENABLE_LAYOUT(Serf, [])
dnl reparse the configure arguments.
APR_PARSE_ARGUMENTS
APR_SAVE_THE_ENVIRONMENT(CPPFLAGS)
APR_SAVE_THE_ENVIRONMENT(CFLAGS)
APR_SAVE_THE_ENVIRONMENT(CXXFLAGS)
APR_SAVE_THE_ENVIRONMENT(LDFLAGS)
APR_SAVE_THE_ENVIRONMENT(LIBS)
APR_SAVE_THE_ENVIRONMENT(INCLUDES)
APR_CONFIG_NICE(config.nice)
nl='
'
dnl Check that mkdir -p works
APR_MKDIR_P_CHECK($top_srcdir/build/mkdir.sh)
AC_SUBST(mkdir_p)
dnl ## Run configure for packages Apache uses
dnl shared library support for these packages doesn't currently
dnl work on some platforms
AC_CANONICAL_SYSTEM
orig_prefix="$prefix"
echo $ac_n "${nl}Configuring Apache Portable Runtime library...${nl}"
APR_FIND_APR("$srcdir/apr", "./apr", 1, 0 1 2)
if test "$apr_found" = "no"; then
AC_MSG_ERROR([APR not found. Please read the documentation.])
fi
if test "$apr_found" = "reconfig"; then
APR_SUBDIR_CONFIG(apr,
[--prefix=$prefix --exec-prefix=$exec_prefix --libdir=$libdir --includedir=$includedir --bindir=$bindir --datadir=$datadir --with-installbuilddir=$installbuilddir],
[--enable-layout=*|\'--enable-layout=*])
dnl We must be the first to build and the last to be cleaned
SERF_BUILD_SRCLIB_DIRS="apr $SERF_BUILD_SRCLIB_DIRS"
SERF_CLEAN_SRCLIB_DIRS="$SERF_CLEAN_SRCLIB_DIRS apr"
fi
APR_SETIFNULL(CC, `$apr_config --cc`)
APR_SETIFNULL(CPP, `$apr_config --cpp`)
APR_SETIFNULL(APR_LIBTOOL, `$apr_config --apr-libtool`)
APR_ADDTO(CFLAGS, `$apr_config --cflags`)
APR_ADDTO(CPPFLAGS, `$apr_config --cppflags`)
APR_ADDTO(LDFLAGS, `$apr_config --ldflags`)
SHLIBPATH_VAR=`$apr_config --shlib-path-var`
APR_BINDIR=`$apr_config --bindir`
APR_INCLUDES=`$apr_config --includes`
APR_VERSION=`$apr_config --version`
APR_CONFIG="$apr_config"
APR_SETIFNULL(LTFLAGS, "--silent")
AC_SUBST(LTFLAGS)
AC_SUBST(APR_LIBTOOL)
AC_SUBST(APR_BINDIR)
AC_SUBST(APR_INCLUDES)
AC_SUBST(APR_VERSION)
AC_SUBST(APR_CONFIG)
APR_VERSION_MAJOR="`echo \"$APR_VERSION\" | sed 's,\..*,,'`"
APR_VERSION_NUM="`echo \"$APR_VERSION\" | \
sed -e 's/[[^0-9\.]].*$//' \
-e 's/\.\([[0-9]]\)$/.0\1/' \
-e 's/\.\([[0-9]][[0-9]]\)$/.0\1/' \
-e 's/\.\([[0-9]]\)\./0\1/; s/\.//g;'`"
if test "$APR_VERSION_NUM" -ge "200000"; then
APU_BINDIR=""
APU_INCLUDES=""
APU_VERSION=""
APU_CONFIG=""
else
sinclude(build/find_apu.m4)
echo $ac_n "${nl}Configuring Apache Portable Runtime Utility library...${nl}"
ifdef([APR_FIND_APU], [
APR_FIND_APU("$srcdir/apr-util", "./apr-util", 1, $APR_VERSION_MAJOR)
], [AC_MSG_ERROR([APR-util required, but find_apu.m4 not present!])])
if test "$apu_found" = "no"; then
AC_MSG_ERROR([APR-util not found. Please read the documentation.])
fi
# Catch some misconfigurations:
case ${apr_found}.${apu_found} in
reconfig.yes)
AC_MSG_ERROR([Cannot use an external APR-util with the bundled APR])
;;
yes.reconfig)
AC_MSG_ERROR([Cannot use an external APR with the bundled APR-util])
;;
esac
if test "$apu_found" = "reconfig"; then
APR_SUBDIR_CONFIG(apr-util,
[--with-apr=../apr --prefix=$prefix --exec-prefix=$exec_prefix --libdir=$libdir --includedir=$includedir --bindir=$bindir],
[--enable-layout=*|\'--enable-layout=*])
dnl We must be the last to build and the first to be cleaned
SERF_BUILD_SRCLIB_DIRS="$SERF_BUILD_SRCLIB_DIRS apr-util"
SERF_CLEAN_SRCLIB_DIRS="apr-util $SERF_CLEAN_SRCLIB_DIRS"
fi
APR_ADDTO(LDFLAGS, `$apu_config --ldflags`)
APU_BINDIR=`$apu_config --bindir`
APU_INCLUDES=`$apu_config --includes`
APU_VERSION=`$apu_config --version`
APU_CONFIG="$APU_BINDIR/apu-`echo ${APU_VERSION} | sed 's,\..*,,'`-config"
fi
AC_SUBST(APU_BINDIR)
AC_SUBST(APU_INCLUDES)
AC_SUBST(APU_VERSION)
AC_SUBST(APU_CONFIG)
dnl In case we picked up CC and CPP from APR, get that info into the
dnl config cache so that PCRE uses it. Otherwise, CC and CPP used for
dnl PCRE and for our config tests will be whatever PCRE determines.
AC_PROG_CC
AC_PROG_CPP
AC_PROG_INSTALL
if test "x${cache_file}" = "x/dev/null"; then
# Likewise, ensure that CC and CPP are passed through to the pcre
# configure script iff caching is disabled (the autoconf 2.5x default).
export CC; export CPP
fi
echo $ac_n "Configuring Serf...${nl}"
dnl Absolute source/build directory
abs_srcdir=`(cd $srcdir && pwd)`
abs_builddir=`pwd`
dnl get our version information
get_version="$abs_srcdir/build/get-version.sh"
version_hdr="$abs_srcdir/serf.h"
SERF_MAJOR_VERSION="`$get_version major $version_hdr SERF`"
SERF_DOTTED_VERSION="`$get_version all $version_hdr SERF`"
AC_SUBST(SERF_MAJOR_VERSION)
AC_SUBST(SERF_DOTTED_VERSION)
AC_SUBST(SERF_BUILD_SRCLIB_DIRS)
AC_SUBST(SERF_CLEAN_SRCLIB_DIRS)
AC_ARG_WITH(openssl,
APR_HELP_STRING([--with-openssl=PATH],[Path to OpenSSL (eg. /usr/local/ssl)]),
[
if test "$withval" = "yes"; then
AC_MSG_ERROR([--with-openssl requires a path])
else
openssl_prefix=$withval
if test "x$openssl_prefix" != "x" -a ! -d "$openssl_prefix"; then
AC_MSG_ERROR('--with-openssl requires a path to a directory')
fi
APR_ADDTO(CPPFLAGS, "-I${openssl_prefix}/include")
if test -e "${openssl_prefix}/Makefile"; then
APR_ADDTO(LDFLAGS, "-L${openssl_prefix}")
APR_ADDTO(LDFLAGS, "-R${openssl_prefix}")
else
APR_ADDTO(LDFLAGS, "-L${openssl_prefix}/lib")
APR_ADDTO(LDFLAGS, "-R${openssl_prefix}/lib")
fi
fi
])
dnl Look for OpenSSL
AC_CHECK_HEADER([openssl/opensslv.h], [],
[AC_MSG_ERROR([We require OpenSSL; try --with-openssl])])
dnl Look for Kerberos 5 for GSSAPI
AC_ARG_WITH(gssapi,
APR_HELP_STRING([--with-gssapi=PATH],[build with GSSAPI support; needs krb5-config in PATH/bin (eg. /usr/lib/mit)]),
[
if test "$withval" = "yes"; then
AC_MSG_ERROR([--with-gssapi requires a path])
else
gssapi_prefix=$withval/
if test "x$gssapi_prefix" != "x" -a ! -d "$gssapi_prefix"; then
AC_MSG_ERROR('--with-gssapi requires a path to a directory')
fi
AC_MSG_CHECKING([for krb5-config])
if test -x "$gssapi_prefix/bin/krb5-config"; then
krb5conf=$gssapi_prefix/bin/krb5-config
AC_MSG_RESULT([$krb5conf])
AC_MSG_CHECKING([for gssapi support in krb5-config])
if "$krb5conf" | grep gssapi > /dev/null; then
AC_MSG_RESULT([yes])
GSSAPI_confopts=gssapi
else
AC_MSG_RESULT([no])
GSSAPI_confopts=
fi
GSSAPI_cflags=`"$krb5conf" --cflags $GSSAPI_confopts`
GSSAPI_libs=`"$krb5conf" --libs $GSSAPI_confopts`
if test -z "$GSSAPI_confopts"; then
case "${host_os}" in
solaris*)
GSSAPI_cflags="$GSSAPI_cflags -I/usr/include/gssapi"
GSSAPI_libs="$GSSAPI_libs -lgss"
;;
esac
fi
APR_ADDTO(CFLAGS, "$GSSAPI_cflags")
APR_ADDTO(CFLAGS, [-DSERF_HAVE_GSSAPI])
APR_ADDTO(LDFLAGS, "$GSSAPI_libs")
AC_MSG_CHECKING([if gssapi works])
AC_LINK_IFELSE([AC_LANG_SOURCE([[
#include <gssapi.h>
int main()
{gss_init_sec_context(NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL);}]])],
lib_gssapi="yes", lib_gssapi="no")
if test "$lib_gssapi" = "yes"; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
AC_MSG_ERROR([cannot find GSSAPI (Kerberos)])
fi
else
AC_MSG_RESULT([no])
AC_MSG_WARN([--with-gssapi specified but krb5-config not found])
fi
fi
])
dnl CuTest requires libm on Solaris
AC_SEARCH_LIBS(fabs, m)
libs=""
if test -n "$apu_config"; then
APR_ADDTO(libs, [`$apu_config --link-libtool --libs`])
fi
APR_ADDTO(libs, [`$apr_config --link-libtool --libs` $LIBS])
APR_ADDTO(SERF_LIBS, [$libs])
AC_SUBST(SERF_LIBS)
APR_RESTORE_THE_ENVIRONMENT(CPPFLAGS, EXTRA_)
APR_RESTORE_THE_ENVIRONMENT(CFLAGS, EXTRA_)
APR_RESTORE_THE_ENVIRONMENT(CXXFLAGS, EXTRA_)
APR_RESTORE_THE_ENVIRONMENT(LDFLAGS, EXTRA_)
APR_RESTORE_THE_ENVIRONMENT(LIBS, EXTRA_)
APR_RESTORE_THE_ENVIRONMENT(INCLUDES, EXTRA_)
AC_CONFIG_FILES([Makefile serf.pc])
AC_CONFIG_COMMANDS([mkdir-vpath],[make mkdir-vpath])
AC_OUTPUT

View File

@ -22,20 +22,6 @@
#include "serf_private.h"
/* 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
/**
* 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
@ -182,6 +168,7 @@ serf_context_t *serf_context_create_ex(
ctx->progress_written = 0;
ctx->authn_types = SERF_AUTHN_ALL;
ctx->server_authn_info = apr_hash_make(pool);
return ctx;
}
@ -382,7 +369,7 @@ const char *serf_error_string(apr_status_t errcode)
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 "\
return "The proxy server returned an error while setting up the "
"SSL tunnel.";
default:
return NULL;

View File

@ -152,7 +152,7 @@ apr_status_t serf_listener_create(
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;

View File

@ -16,6 +16,7 @@
#include <apr_pools.h>
#include <apr_poll.h>
#include <apr_version.h>
#include <apr_portable.h>
#include "serf.h"
#include "serf_bucket_util.h"
@ -113,30 +114,34 @@ apr_status_t serf__conn_update_pollset(serf_connection_t *conn)
/* ### not true. we only want to read IF we have sent some data */
desc.reqevents |= APR_POLLIN;
/* 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 {
serf_request_t *request = conn->requests;
/* Don't write if OpenSSL told us that it needs to read data first. */
if (conn->stop_writing != 1) {
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. */
}
/* 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 {
while (request != NULL && request->req_bkt == NULL &&
request->written)
request = request->next;
if (request != NULL)
desc.reqevents |= APR_POLLOUT;
serf_request_t *request = conn->requests;
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 {
while (request != NULL && request->req_bkt == NULL &&
request->written)
request = request->next;
if (request != NULL)
desc.reqevents |= APR_POLLOUT;
}
}
}
}
@ -177,6 +182,108 @@ static void check_buckets_drained(serf_connection_t *conn)
#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.
*/
@ -186,6 +293,7 @@ apr_status_t serf__open_connections(serf_context_t *ctx)
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;
@ -240,7 +348,7 @@ apr_status_t serf__open_connections(serf_context_t *ctx)
serf__log_skt(SOCK_VERBOSE, __FILE__, skt,
"connected socket for conn 0x%x, status %d\n",
conn, status);
if (status != APR_SUCCESS) {
if (status != APR_SUCCESS) {
if (!APR_STATUS_IS_EINPROGRESS(status))
return status;
}
@ -253,21 +361,33 @@ apr_status_t serf__open_connections(serf_context_t *ctx)
prepare this connection (it might be possible to skip some
part of the handshaking). */
if (ctx->proxy_address) {
if (conn->ctx->proxy_authn_info.scheme)
conn->ctx->proxy_authn_info.scheme->init_conn_func(407, conn,
conn->pool);
authn_info = &ctx->proxy_authn_info;
if (authn_info->scheme) {
authn_info->scheme->init_conn_func(authn_info->scheme, 407,
conn, conn->pool);
}
}
if (conn->ctx->authn_info.scheme)
conn->ctx->authn_info.scheme->init_conn_func(401, 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
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;
@ -396,15 +516,6 @@ static apr_status_t remove_connection(serf_context_t *ctx,
&desc, conn);
}
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;
}
}
/* A socket was closed, inform the application. */
static void handle_conn_closed(serf_connection_t *conn, apr_status_t status)
{
@ -492,7 +603,7 @@ static apr_status_t socket_writev(serf_connection_t *conn)
status = apr_socket_sendv(conn->skt, conn->vec,
conn->vec_len, &written);
if (status && !APR_STATUS_IS_EAGAIN(status))
if (status && !APR_STATUS_IS_EAGAIN(status))
serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt,
"socket_sendv error %d\n", status);
@ -535,99 +646,29 @@ static apr_status_t socket_writev(serf_connection_t *conn)
return status;
}
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)
static apr_status_t setup_request(serf_request_t *request)
{
serf_connection_t *conn = request->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);
/* 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;
}
/* 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;
}
/* write data out to the connection */
static apr_status_t write_to_connection(serf_connection_t *conn)
{
@ -717,32 +758,23 @@ static apr_status_t write_to_connection(serf_connection_t *conn)
}
if (request->req_bkt == NULL) {
/* 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. */
read_status = request->setup(request, request->setup_baton,
&request->req_bkt,
&request->acceptor,
&request->acceptor_baton,
&request->handler,
&request->handler_baton,
request->respool);
read_status = setup_request(request);
if (read_status) {
/* Something bad happened. Propagate any errors. */
return read_status;
}
}
if (!request->written) {
request->written = 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,
@ -750,17 +782,24 @@ static apr_status_t write_to_connection(serf_connection_t *conn)
&conn->vec_len);
if (!conn->hit_eof) {
if (APR_STATUS_IS_EAGAIN(read_status) ||
read_status == SERF_ERROR_WAIT_CONN) {
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)
*/
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. */
@ -790,6 +829,9 @@ static apr_status_t write_to_connection(serf_connection_t *conn)
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 (read_status && conn->hit_eof && conn->vec_len == 0) {
/* If we hit the end of the request bucket and all of its data has
@ -895,6 +937,57 @@ static apr_status_t handle_async_response(serf_connection_t *conn,
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)
{
@ -907,6 +1000,14 @@ static apr_status_t read_from_connection(serf_connection_t *conn)
*/
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)
@ -1137,6 +1238,20 @@ apr_status_t serf__process_connection(serf_connection_t *conn,
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))
return APR_FROM_OS_ERROR(error);
}
}
#endif
return APR_EGENERAL;
}
if ((events & APR_POLLOUT) != 0) {
@ -1180,7 +1295,8 @@ serf_connection_t *serf_connection_create(
apr_pool_create(&conn->skt_pool, conn->pool);
/* register a cleanup */
apr_pool_cleanup_register(conn->pool, conn, clean_conn, apr_pool_cleanup_null);
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;
@ -1227,7 +1343,12 @@ apr_status_t serf_connection_create2(
c->host_url = apr_uri_unparse(c->pool,
&host_info,
APR_URI_UNP_OMITPATHINFO);
c->host_info = host_info;
/* 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;
@ -1330,11 +1451,12 @@ void serf_connection_set_async_responses(
conn->async_handler_baton = handler_baton;
}
serf_request_t *serf_connection_request_create(
serf_connection_t *conn,
serf_request_setup_t setup,
void *setup_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;
@ -1346,10 +1468,25 @@ serf_request_t *serf_connection_request_create(
request->respool = NULL;
request->req_bkt = NULL;
request->resp_bkt = NULL;
request->priority = 0;
request->priority = priority;
request->written = 0;
request->ssltunnel = ssltunnel;
request->next = 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);
@ -1360,26 +1497,18 @@ serf_request_t *serf_connection_request_create(
return request;
}
serf_request_t *serf_connection_priority_request_create(
serf_connection_t *conn,
serf_request_setup_t setup,
void *setup_baton)
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 = 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 = 1;
request->written = 0;
request->next = NULL;
request = create_request(conn, setup, setup_baton,
1, /* priority */
ssltunnelreq);
/* Link the new request after the last written request. */
iter = conn->requests;
@ -1391,10 +1520,17 @@ serf_request_t *serf_connection_priority_request_create(
iter = iter->next;
}
/* Advance to next non priority request */
while (iter != NULL && iter->priority) {
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) {
@ -1412,6 +1548,24 @@ serf_request_t *serf_connection_priority_request_create(
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)
{
@ -1466,29 +1620,53 @@ serf_bucket_t *serf_request_bucket_request_create(
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);
/* Proxy? */
if (ctx->proxy_address && conn->host_url)
/* 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 */
if (ctx->authn_info.scheme)
ctx->authn_info.scheme->setup_request_func(HOST, 0, conn, request,
/* 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 */
if (ctx->proxy_authn_info.scheme)
ctx->proxy_authn_info.scheme->setup_request_func(PROXY, 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;
}

44
serf.h
View File

@ -59,57 +59,55 @@ typedef struct serf_request_t serf_request_t;
* 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 (APR_OS_START_USERERR + SERF_ERROR_RANGE + 1)
#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 (APR_OS_START_USERERR + SERF_ERROR_RANGE + 2)
#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 (APR_OS_START_USERERR + SERF_ERROR_RANGE + 3)
#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 (APR_OS_START_USERERR + \
SERF_ERROR_RANGE + 4)
#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 (APR_OS_START_USERERR + \
SERF_ERROR_RANGE + 5)
#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 (APR_OS_START_USERERR + \
SERF_ERROR_RANGE + 6)
#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 (APR_OS_START_USERERR + \
SERF_ERROR_RANGE + 7)
#define SERF_ERROR_SSLTUNNEL_SETUP_FAILED (SERF_ERROR_START + 7)
/* The server unexpectedly closed the connection prematurely. */
#define SERF_ERROR_ABORTED_CONNECTION (APR_OS_START_USERERR + \
SERF_ERROR_RANGE + 8)
#define SERF_ERROR_ABORTED_CONNECTION (SERF_ERROR_START + 8)
/* SSL certificates related errors */
#define SERF_ERROR_SSL_CERT_FAILED (APR_OS_START_USERERR + SERF_ERROR_RANGE + 70)
#define SERF_ERROR_SSL_CERT_FAILED (SERF_ERROR_START + 70)
/* SSL communications related errors */
#define SERF_ERROR_SSL_COMM_FAILED (APR_OS_START_USERERR + SERF_ERROR_RANGE + 71)
#define SERF_ERROR_SSL_COMM_FAILED (SERF_ERROR_START + 71)
/* General authentication related errors */
#define SERF_ERROR_AUTHN_FAILED (APR_OS_START_USERERR + SERF_ERROR_RANGE + 90)
#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 (APR_OS_START_USERERR + SERF_ERROR_RANGE + 91)
#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 (APR_OS_START_USERERR + SERF_ERROR_RANGE + 92)
#define SERF_ERROR_AUTHN_MISSING_ATTRIBUTE (SERF_ERROR_START + 92)
/* Authentication handler initialization related errors */
#define SERF_ERROR_AUTHN_INITALIZATION_FAILED (APR_OS_START_USERERR +\
SERF_ERROR_RANGE + 93)
#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) \
@ -497,6 +495,8 @@ apr_status_t serf_connection_close(
* 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,
@ -1061,8 +1061,8 @@ void serf_debug__bucket_alloc_check(
/* Version info */
#define SERF_MAJOR_VERSION 1
#define SERF_MINOR_VERSION 2
#define SERF_PATCH_VERSION 1
#define SERF_MINOR_VERSION 3
#define SERF_PATCH_VERSION 0
/* Version number string */
#define SERF_VERSION_STRING APR_STRINGIFY(SERF_MAJOR_VERSION) "." \

215
serf.mak
View File

@ -1,215 +0,0 @@
#**** serf Win32 -*- Makefile -*- ********************************************
#
# Define DEBUG_BUILD to create a debug version of the library.
!IF "$(OS)" == "Windows_NT"
NULL=
!ELSE
NULL=nul
!ENDIF
CFLAGS = /Zi /W3 /EHsc /I "./"
!IF "$(DEBUG_BUILD)" == ""
INTDIR = Release
CFLAGS = /MD /O2 /D "NDEBUG" $(CFLAGS)
STATIC_LIB = $(INTDIR)\serf-1.lib
!ELSE
INTDIR = Debug
CFLAGS = /MDd /Od /W3 /Gm /D "_DEBUG" $(CFLAGS)
STATIC_LIB = $(INTDIR)\serf-1.lib
!ENDIF
########
# Support for OpenSSL integration
!IF "$(OPENSSL_SRC)" == ""
!ERROR OpenSSL is required. Please define OPENSSL_SRC.
!ELSE
OPENSSL_FLAGS = /I "$(OPENSSL_SRC)\inc32"
!ENDIF
!IF "$(HTTPD_SRC)" != ""
!IF "$(APR_SRC)" == ""
APR_SRC=$(HTTPD_SRC)\srclib\apr
!ENDIF
!IF "$(APRUTIL_SRC)" == ""
APRUTIL_SRC=$(HTTPD_SRC)\srclib\apr-util
!ENDIF
!ENDIF
########
# APR
!IF "$(APR_SRC)" == ""
!ERROR APR is required. Please define APR_SRC or HTTPD_SRC.
!ENDIF
APR_FLAGS = /I "$(APR_SRC)\include"
!IF [IF EXIST "$(APR_SRC)\$(INTDIR)\libapr-1.lib" exit 1] == 1
APR_LIBS = "$(APR_SRC)\$(INTDIR)\libapr-1.lib"
!ELSE
APR_LIBS = "$(APR_SRC)\$(INTDIR)\libapr.lib"
!ENDIF
########
# APR Util
!IF "$(APRUTIL_SRC)" == ""
!ERROR APR-Util is required. Please define APRUTIL_SRC or HTTPD_SRC.
!ENDIF
APRUTIL_FLAGS = /I "$(APRUTIL_SRC)\include"
!IF [IF EXIST "$(APRUTIL_SRC)\$(INTDIR)\libaprutil-1.lib" exit 1] == 1
APRUTIL_LIBS = "$(APRUTIL_SRC)\$(INTDIR)\libaprutil-1.lib"
!ELSE
APRUTIL_LIBS = "$(APRUTIL_SRC)\$(INTDIR)\libaprutil.lib"
!ENDIF
########
# Support for zlib integration
!IF "$(ZLIB_SRC)" == ""
!ERROR ZLib is required. Please define ZLIB_SRC.
!ELSE
ZLIB_FLAGS = /I "$(ZLIB_SRC)"
!IF "$(ZLIB_DLL)" == ""
!IF "$(ZLIB_LIBDIR)" == ""
!IF "$(DEBUG_BUILD)" == ""
ZLIB_LIBS = "$(ZLIB_SRC)\zlibstat.lib"
!ELSE
ZLIB_LIBS = "$(ZLIB_SRC)\zlibstatD.lib"
!ENDIF
!ELSE
ZLIB_LIBS = "$(ZLIB_LIBDIR)\x86\ZlibStat$(INTDIR)\zlibstat.lib"
ZLIB_FLAGS = $(ZLIB_FLAGS) /D ZLIB_WINAPI
!ENDIF
!ELSE
ZLIB_FLAGS = $(ZLIB_FLAGS) /D ZLIB_DLL
ZLIB_LIBS = "$(ZLIB_SRC)\zlibdll.lib"
!ENDIF
!ENDIF
# Exclude stuff we don't need from the Win32 headers
WIN32_DEFS = /D WIN32 /D WIN32_LEAN_AND_MEAN /D NOUSER /D NOGDI /D NONLS /D NOCRYPT /D SERF_HAVE_SSPI
CPP=cl.exe
CPP_PROJ = /c /nologo $(CFLAGS) $(WIN32_DEFS) $(APR_FLAGS) $(APRUTIL_FLAGS) $(OPENSSL_FLAGS) $(ZLIB_FLAGS) /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\"
LIB32=link.exe
LIB32_FLAGS=/nologo
LIB32_OBJS= \
"$(INTDIR)\aggregate_buckets.obj" \
"$(INTDIR)\auth.obj" \
"$(INTDIR)\auth_basic.obj" \
"$(INTDIR)\auth_digest.obj" \
"$(INTDIR)\auth_kerb.obj" \
"$(INTDIR)\auth_kerb_gss.obj" \
"$(INTDIR)\auth_kerb_sspi.obj" \
"$(INTDIR)\context.obj" \
"$(INTDIR)\ssltunnel.obj" \
"$(INTDIR)\allocator.obj" \
"$(INTDIR)\barrier_buckets.obj" \
"$(INTDIR)\buckets.obj" \
"$(INTDIR)\chunk_buckets.obj" \
"$(INTDIR)\dechunk_buckets.obj" \
"$(INTDIR)\deflate_buckets.obj" \
"$(INTDIR)\file_buckets.obj" \
"$(INTDIR)\headers_buckets.obj" \
"$(INTDIR)\incoming.obj" \
"$(INTDIR)\iovec_buckets.obj" \
"$(INTDIR)\limit_buckets.obj" \
"$(INTDIR)\mmap_buckets.obj" \
"$(INTDIR)\outgoing.obj" \
"$(INTDIR)\request_buckets.obj" \
"$(INTDIR)\response_buckets.obj" \
"$(INTDIR)\response_body_buckets.obj" \
"$(INTDIR)\simple_buckets.obj" \
"$(INTDIR)\socket_buckets.obj" \
"$(INTDIR)\ssl_buckets.obj" \
!IFDEF OPENSSL_STATIC
LIB32_OBJS = $(LIB32_OBJS) "$(OPENSSL_SRC)\out32\libeay32.lib" \
"$(OPENSSL_SRC)\out32\ssleay32.lib"
!ELSE
LIB32_OBJS = $(LIB32_OBJS) "$(OPENSSL_SRC)\out32dll\libeay32.lib" \
"$(OPENSSL_SRC)\out32dll\ssleay32.lib"
!ENDIF
LIB32_OBJS = $(LIB32_OBJS) $(APR_LIBS) $(APRUTIL_LIBS) $(ZLIB_LIBS)
SYS_LIBS = secur32.lib
TEST_OBJS = \
"$(INTDIR)\CuTest.obj" \
"$(INTDIR)\test_all.obj" \
"$(INTDIR)\test_util.obj" \
"$(INTDIR)\test_context.obj" \
"$(INTDIR)\test_buckets.obj" \
"$(INTDIR)\test_ssl.obj" \
"$(INTDIR)\test_server.obj" \
"$(INTDIR)\test_sslserver.obj" \
TEST_LIBS = user32.lib advapi32.lib gdi32.lib ws2_32.lib
ALL: $(INTDIR) $(STATIC_LIB) TESTS
CLEAN:
-@erase /q "$(INTDIR)" >nul
$(INTDIR):
-@if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)"
TESTS: $(STATIC_LIB) $(INTDIR)\serf_response.exe $(INTDIR)\serf_get.exe \
$(INTDIR)\serf_request.exe $(INTDIR)\test_all.exe
CHECK: $(INTDIR) TESTS
$(INTDIR)\serf_response.exe test\testcases\simple.response
$(INTDIR)\serf_response.exe test\testcases\chunked-empty.response
$(INTDIR)\serf_response.exe test\testcases\chunked.response
$(INTDIR)\serf_response.exe test\testcases\chunked-trailers.response
$(INTDIR)\serf_response.exe test\testcases\deflate.response
$(INTDIR)\test_all.exe
"$(STATIC_LIB)": $(INTDIR) $(LIB32_OBJS)
$(LIB32) -lib @<<
$(LIB32_FLAGS) $(LIB32_OBJS) $(SYS_LIBS) /OUT:$@
<<
.c{$(INTDIR)}.obj:
$(CPP) @<<
$(CPP_PROJ) $<
<<
{auth}.c{$(INTDIR)}.obj:
$(CPP) @<<
$(CPP_PROJ) $<
<<
{buckets}.c{$(INTDIR)}.obj:
$(CPP) @<<
$(CPP_PROJ) $<
<<
{test}.c{$(INTDIR)}.obj:
$(CPP) @<<
$(CPP_PROJ) $<
<<
{test\server}.c{$(INTDIR)}.obj:
$(CPP) @<<
$(CPP_PROJ) $<
<<
$(INTDIR)\serf_response.exe: $(INTDIR)\serf_response.obj $(STATIC_LIB)
$(LIB32) /DEBUG /OUT:$@ $** $(LIB32_FLAGS) $(TEST_LIBS)
$(INTDIR)\serf_get.exe: $(INTDIR)\serf_get.obj $(STATIC_LIB)
$(LIB32) /DEBUG /OUT:$@ $** $(LIB32_FLAGS) $(TEST_LIBS)
$(INTDIR)\serf_request.exe: $(INTDIR)\serf_request.obj $(STATIC_LIB)
$(LIB32) /DEBUG /OUT:$@ $** $(LIB32_FLAGS) $(TEST_LIBS)
$(INTDIR)\test_all.exe: $(TEST_OBJS) $(STATIC_LIB)
$(LIB32) /DEBUG /OUT:$@ $** $(LIB32_FLAGS) $(TEST_LIBS)

View File

@ -1,13 +0,0 @@
SERF_MAJOR_VERSION=@SERF_MAJOR_VERSION@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: serf
Description: HTTP client library
Version: @SERF_DOTTED_VERSION@
Requires.private: libssl libcrypto
Libs: -L${libdir} -lserf-${SERF_MAJOR_VERSION}
Libs.private: @EXTRA_LIBS@ @SERF_LIBS@ -lz
Cflags: -I${includedir}

View File

@ -307,6 +307,16 @@ serf_bucket_t *serf_bucket_simple_copy_create(
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);
@ -579,7 +589,7 @@ apr_hash_t *serf_ssl_cert_subject(
/**
* Extract the fields of the certificate in a table with keys (sha1, notBefore,
* notAfter). The returned table will be allocated in @a pool.
* notAfter, subjectAltName). The returned table will be allocated in @a pool.
*/
apr_hash_t *serf_ssl_cert_certificate(
const serf_ssl_certificate_t *cert,

View File

@ -148,6 +148,14 @@ 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.

View File

@ -26,6 +26,13 @@
#define IOV_MAX 16
#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)
@ -39,6 +46,18 @@
#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;
@ -76,6 +95,8 @@ struct serf_request_t {
int written;
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.
@ -93,8 +114,6 @@ typedef struct serf_pollset_t {
} serf_pollset_t;
typedef struct serf__authn_info_t {
const char *realm;
const serf__authn_scheme_t *scheme;
void *baton;
@ -124,8 +143,15 @@ struct serf_context_t {
apr_off_t progress_read;
apr_off_t progress_written;
/* authentication info for this context, shared by all connections. */
serf__authn_info_t authn_info;
/* 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.*/
@ -158,7 +184,7 @@ 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,
SERF_CONN_CLOSING /* conn is closing, no more requests,
start a new socket */
} serf__connection_state_t;
@ -232,8 +258,12 @@ struct serf_connection_t {
unsigned int max_outstanding_requests;
int hit_eof;
/* Host info. */
/* 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;
/* connection and authentication scheme specific information */
@ -245,6 +275,9 @@ struct serf_connection_t {
/* 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 ***/
@ -293,7 +326,8 @@ typedef apr_status_t
* connection is opened.
*/
typedef apr_status_t
(*serf__init_conn_func_t)(int code,
(*serf__init_conn_func_t)(const serf__authn_scheme_t *scheme,
int code,
serf_connection_t *conn,
apr_pool_t *pool);
@ -329,15 +363,14 @@ typedef apr_status_t
* serf__authn_scheme_t: vtable for an authn scheme provider.
*/
struct serf__authn_scheme_t {
/* The http status code that's handled by this authentication scheme.
Normal values are 401 for server authentication and 407 for proxy
authentication */
int code;
/* The name of this authentication scheme. This should be a case
sensitive match of the string sent in the HTTP authentication header. */
/* 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;
@ -367,6 +400,14 @@ apr_status_t serf__handle_auth_response(int *consumed_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);
@ -380,6 +421,17 @@ 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);

506
serfmake
View File

@ -1,506 +0,0 @@
#!/usr/bin/env python
import os
import re
import shutil
import sys
import stat
import copy
### use get_version() ?
MAJOR = 1
# Basic defines for our outputs.
LIBNAME = 'libserf-%d' % (MAJOR,)
INCLUDES = 'serf-%d' % (MAJOR,)
PCFILE = 'serf-%d' % (MAJOR,)
FILES_HDR = [
('.', 'serf'),
('.', 'serf_bucket_types'),
('.', 'serf_bucket_util'),
]
LIB_FILES = [
('.', 'context'),
('.', 'incoming'),
('.', 'outgoing'),
('.', 'ssltunnel'),
('buckets', 'aggregate_buckets'),
('buckets', 'request_buckets'),
('buckets', 'buckets'),
('buckets', 'simple_buckets'),
('buckets', 'file_buckets'),
('buckets', 'mmap_buckets'),
('buckets', 'socket_buckets'),
('buckets', 'response_buckets'),
('buckets', 'response_body_buckets'),
('buckets', 'headers_buckets'),
('buckets', 'allocator'),
('buckets', 'dechunk_buckets'),
('buckets', 'deflate_buckets'),
('buckets', 'limit_buckets'),
('buckets', 'ssl_buckets'),
('buckets', 'barrier_buckets'),
('buckets', 'chunk_buckets'),
('buckets', 'iovec_buckets'),
('auth', 'auth'),
('auth', 'auth_basic'),
('auth', 'auth_digest'),
('auth', 'auth_kerb'),
('auth', 'auth_kerb_gss'),
]
TEST_DEPS = [
('test', 'CuTest'),
('test', 'test_util'),
('test', 'test_context'),
('test', 'test_buckets'),
('test', 'test_ssl'),
('test/server', 'test_server'),
('test/server', 'test_sslserver'),
]
TEST_HDR_FILES = [
('test', 'CuTest'),
('test', 'test_serf'),
]
TEST_FILES = [
('test', 'serf_get'),
('test', 'serf_response'),
('test', 'serf_request'),
('test', 'serf_spider'),
('test', 'test_all'),
]
TESTCASES = [
('test/testcases', 'simple.response'),
('test/testcases', 'chunked-empty.response'),
('test/testcases', 'chunked.response'),
('test/testcases', 'chunked-trailers.response'),
('test/testcases', 'deflate.response'),
]
def main(argv):
params = {}
commands = []
for arg in argv[1:]:
idx = arg.find('=')
if idx > 0:
start = arg.rfind('-', 0, idx)
if start > 0:
params[arg[start+1:idx]] = arg[idx+1:].strip()
else:
func = globals().get('cmd_' + arg)
if func:
commands.append(func)
else:
print('ERROR: unknown argument: ' + arg)
usage()
if not commands:
usage()
for func in commands:
try:
func(params)
except:
print('ERROR: exception:')
print(sys.exc_info()[1])
print("")
usage()
def usage():
### print something
print('serfmake [cmd] [options]')
print('Commands:')
print('\tbuild\tBuilds (default)')
print('\tcheck\tRuns test cases')
print('\tinstall\tInstalls serf into PREFIX')
print('\tclean\tCleans')
print('Options:')
print('\t--with-apr=PATH\t\tprefix for installed APR and APR-util')
print('\t\t\t\t(needs apr-1-config and apu-1-config; will look in PATH)')
print('\t--with-gssapi=PATH\tbuild serf with GSSAPI support')
print('\t\t\t\t(needs krb5-config; will look in PATH/bin)')
print('\t--prefix=PATH\t\tinstall serf into PATH (default: /usr/local)')
print('Quick guide:')
print('\tserfmake --prefix=/usr/local/serf --with-apr=/usr/local/apr install')
sys.exit(1)
def cmd_build(param):
builder = Builder(param)
builder.build_target(File('.', LIBNAME, 'la'), False)
builder.build_target(File('.', PCFILE, 'pc'), False)
def cmd_install(param):
builder = Builder(param)
builder.build_target(File('.', PCFILE, 'pc'), False)
### should be called .install_all()
builder.install_target(File('.', LIBNAME, 'la'), False)
def cmd_check(param):
builder = Builder(param)
for dirpath, fname in TEST_FILES:
builder.build_target(File(dirpath, fname, None), False)
for dirpath, fname in TESTCASES:
case = os.path.join(dirpath, fname)
print('== Testing %s ==' % case)
result = os.system('%s %s' % (os.path.join('test', 'serf_response'), case))
if result:
raise TestError("", result)
# run the test suite based on the CuTest framework
result = os.system(os.path.join('test', 'test_all'))
if result:
raise TestError(case, result)
def cmd_clean(param):
targets = [File(dirpath, fname, 'o') for dirpath, fname in LIB_FILES]
targets += [File(dirpath, fname, 'lo') for dirpath, fname in LIB_FILES]
targets += [File('.', LIBNAME, 'la'),
File('.', PCFILE, 'pc'),
]
targets += [File(dirpath, fname, 'o') for dirpath, fname in TEST_FILES]
targets += [File(dirpath, fname, 'lo') for dirpath, fname in TEST_FILES]
targets += [File(dirpath, fname, None) for dirpath, fname in TEST_FILES]
targets += [File(dirpath, fname, 'o') for dirpath, fname in TEST_DEPS]
targets += [File(dirpath, fname, 'lo') for dirpath, fname in TEST_DEPS]
clean = [file for file in targets if file.mtime]
if clean:
sys.stdout.write('Cleaning %d files... ' % len(clean))
for i in clean:
if i.mtime:
os.remove(i.fname)
print('done.')
else:
print('Clean.')
class Builder(object):
def __init__(self, params):
# use apr option if set
if 'apr' in params:
self.apr = APRConfig(params['apr'])
self.apu = APUConfig(params['apr'])
else:
self.apr = APRConfig(None)
self.apu = APUConfig(None)
# build with gssapi if option is set
if 'gssapi' in params:
self.gssapi = GSSAPIConfig(params['gssapi'])
else:
self.gssapi = None
try:
self.prefix = params['prefix']
except:
self.prefix = '/usr/local'
### no way to tweak these
self.libdir = os.path.join(self.prefix, 'lib')
self.pkgconfigdir = os.path.join(self.prefix, 'lib', 'pkgconfig')
self.includedir = os.path.join(self.prefix, 'include', INCLUDES)
self.load_vars()
self.load_deps()
def load_vars(self):
self.CC = self.apr.get_value('CC', '--cc')
self.CFLAGS = self.apr.get_value('CFLAGS', '--cflags')
self.CPPFLAGS = self.apr.get_value('CPPFLAGS', '--cppflags')
self.LIBTOOL = self.apr.get_value('LIBTOOL', '--apr-libtool')
self.LDFLAGS = self.apr.get_value('LDFLAGS', '--ldflags') \
+ ' ' + self.apu.get_value('LDFLAGS', '--ldflags')
self.INCLUDES = '-I%s -I%s -I%s' % (
'.',
self.apr.get_value(None, '--includedir'),
self.apu.get_value(None, '--includedir'),
)
if os.getenv('EXTRA_INCLUDES'):
self.INCLUDES += ' -I' + os.getenv('EXTRA_INCLUDES')
self.LIBS = self.apu.get_value(None, '--link-libtool') \
+ ' ' + self.apu.get_value(None, '--libs') \
+ ' ' + self.apr.get_value(None, '--link-libtool') \
+ ' ' + self.apr.get_value(None, '--libs') \
+ ' -lz'
self.SSL_LIBS = '-lssl -lcrypto'
if self.gssapi:
self.LIBS += ' ' + self.gssapi.get_value(None, '--libs gssapi')
self.CFLAGS += ' ' + self.gssapi.get_value('CFLAGS', '--cflags gssapi')\
+ ' -DSERF_HAVE_GSSAPI -g'
self.MODE = 644
def load_deps(self):
self.deps = { }
hdrs = [File(dirpath, fname, 'h') for dirpath, fname in FILES_HDR]
libfiles = [File(dirpath, fname, 'c') for dirpath, fname in LIB_FILES]
libobjs = [File(dirpath, fname, 'lo') for dirpath, fname in LIB_FILES]
for src, obj in zip(libfiles, libobjs):
self._add_compile(src, obj, hdrs)
self.hdrs = hdrs
all_libs = self.LIBS + ' ' + self.SSL_LIBS
lib = File('.', LIBNAME, 'la')
cmd = '%s --silent --mode=link %s %s -rpath %s -o %s %s %s' % (
self.LIBTOOL, self.CC, self.LDFLAGS, self.libdir,
lib.fname, ' '.join([l.fname for l in libobjs]), all_libs)
self._add_dep(lib, libobjs, cmd)
# load the test program dependencies now
testhdrs = copy.deepcopy(hdrs)
testhdrs += [File(dirpath, fname, 'h') for dirpath, fname in TEST_HDR_FILES]
testdeps = [File(dirpath, fname, 'c') for dirpath, fname in TEST_DEPS]
testobjs = [File(dirpath, fname, 'lo') for dirpath, fname in TEST_DEPS]
for testsrc, testobj in zip(testdeps, testobjs):
self._add_compile(testsrc, testobj, testhdrs)
for dirpath, fname in TEST_FILES:
src = File(dirpath, fname, 'c')
obj = File(dirpath, fname, 'lo')
prog = File(dirpath, fname, None)
self._add_compile(src, obj, hdrs)
# test_all requires extra dependencies
if fname == "test_all":
cmd = '%s --silent --mode=link %s %s -static -o %s %s %s %s' % (
self.LIBTOOL, self.CC, self.LDFLAGS,
prog.fname, lib.fname, ' '.join([l.fname for l in [obj] + testobjs]),
all_libs)
self._add_dep(prog, [lib, obj] + testobjs, cmd)
else:
cmd = '%s --silent --mode=link %s %s -static -o %s %s %s %s' % (
self.LIBTOOL, self.CC, self.LDFLAGS,
prog.fname, lib.fname, obj.fname, all_libs)
self._add_dep(prog, [lib, obj], cmd)
# create 'serf-1.pc' if it doesn't exist.
pcfile = File('.', PCFILE, 'pc')
self._add_dep(pcfile, [], self._write_pcfile)
def _add_compile(self, src, obj, hdrs):
cmd = '%s --silent --mode=compile %s %s %s %s -c -o %s %s' % (
self.LIBTOOL, self.CC, self.CFLAGS, self.CPPFLAGS, self.INCLUDES,
obj.fname, src.fname)
self._add_dep(obj, [src] + hdrs, cmd)
def _add_dep(self, target, deps, cmd):
if target.mtime:
for dep in deps:
if dep in self.deps or (dep.mtime and dep.mtime > target.mtime):
# a dep is newer. this needs to be rebuilt.
break
else:
# this is up to date. don't add it to the deps[] structure.
return
# else non-existent, so it must be rebuilt.
# Commands that are strings are cmdline invocations. Otherwise, it
# should be a callable.
if isinstance(cmd, str):
cmd = CommandLine(cmd)
# register the dependency so this will get built
self.deps[target] = deps, cmd
def _write_pcfile(self):
"""Generating serf-1.pc ..."""
open(PCFILE + '.pc', 'w').write(
"""SERF_MAJOR_VERSION=%d
prefix=%s
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include/%s
Name: serf
Description: HTTP client library
Version: %s
Requires.private: libssl libcrypto
Libs: -L${libdir} -lserf-${SERF_MAJOR_VERSION}
Libs.private: %s
Cflags: -I${includedir}
""" % (MAJOR, self.prefix, INCLUDES, get_version(), self.LIBS))
def build_target(self, target, dry_run):
deps, cmd = self.deps.get(target, (None, None))
if cmd is None:
# it's already up to date. all done.
return
for f in deps:
subdep = self.deps.get(f)
if subdep:
self.build_target(f, dry_run)
# build the target now
print(cmd.__doc__)
if not dry_run:
result = cmd()
if result:
raise BuildError(cmd.__doc__, result)
# FALLTHROUGH
# it's a dry run. pretend we built the target.
del self.deps[target]
return 0
def install_target(self, target, dry_run):
self.build_target(target, dry_run)
# install the target now
if not dry_run:
for path in (self.libdir, self.pkgconfigdir, self.includedir):
if not os.path.exists(path):
try:
os.makedirs(path)
except OSError:
raise BuildError('os.makedirs',
'can not create install directories')
for f in self.hdrs:
print("Installing: %s" % (os.path.basename(f.fname),))
shutil.copy(f.fname, self.includedir)
print("Installing: %s.pc" % (PCFILE,))
shutil.copy(PCFILE + '.pc', self.pkgconfigdir)
cmd = '%s --silent --mode=install %s -c -m %d %s %s' % (
self.LIBTOOL, '/usr/bin/install', self.MODE, target.fname,
self.libdir)
print("Installing: %s" % (os.path.basename(target.fname),))
result = os.system(cmd)
if result:
raise BuildError(cmd, result)
# FALLTHROUGH
return 0
class ConfigScript(object):
script_name = None
locations = [
'/usr/bin',
'/usr/local/bin',
'/usr/local/apache2/bin',
]
def __init__(self, search_dir):
if search_dir:
locations = [search_dir, os.path.join(search_dir, 'bin')]
else:
locations = self.locations
for dirname in locations:
bin = os.path.join(dirname, self.script_name)
if os.access(bin, os.X_OK):
self.bin = bin
break
else:
raise ConfigScriptNotFound(self.script_name)
def get_value(self, env_name, switch):
if env_name and os.getenv(env_name):
return os.getenv(env_name)
return os.popen('%s %s' % (self.bin, switch), 'r').read().strip()
class APRConfig(ConfigScript):
script_name = 'apr-1-config'
class APUConfig(ConfigScript):
script_name = 'apu-1-config'
class GSSAPIConfig(ConfigScript):
script_name = 'krb5-config'
class CommandLine(object):
"""Simple helper to invoke a system command when called."""
def __init__(self, cmd):
self.cmd = cmd
self.__doc__ = cmd # when we print the execution of this command
def __call__(self):
return os.system(self.cmd)
class File:
def __init__(self, dirpath, fname, ext):
if ext:
self.fname = os.path.join(dirpath, fname + '.' + ext)
else:
self.fname = os.path.join(dirpath, fname)
try:
s = os.stat(self.fname)
except OSError:
self.mtime = None
else:
self.mtime = s[stat.ST_MTIME]
def __eq__(self, other):
return self.fname == other.fname
def __hash__(self):
return hash(self.fname)
def get_version():
match = re.search('SERF_MAJOR_VERSION ([0-9]+).*'
'SERF_MINOR_VERSION ([0-9]+).*'
'SERF_PATCH_VERSION ([0-9]+)',
open('serf.h').read(),
re.DOTALL)
major, minor, patch = match.groups()
return '%s.%s.%s' % (major, minor, patch)
class BuildError(Exception):
"An error occurred while building a target."
class TestError(Exception):
"An error occurred while running a unit test."
class ConfigScriptNotFound(Exception):
def __init__(self, value):
self.value = "ERROR: A configuration script was not found: " + value
def __str__(self):
return self.value
if __name__ == '__main__':
main(sys.argv)
###
### TODO:
### * obey DESTDIR
### * arfrever says LDFLAGS is passed twice
### * be able to specify libdir and includedir
###

View File

@ -159,17 +159,16 @@ apr_status_t serf__ssltunnel_connect(serf_connection_t *conn)
ctx = apr_palloc(ssltunnel_pool, sizeof(*ctx));
ctx->pool = ssltunnel_pool;
ctx->uri = apr_psprintf(ctx->pool, "%s:%d", conn->host_info.hostinfo,
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);
/* TODO: should be the first request on the connection. */
serf_connection_priority_request_create(conn,
setup_request,
ctx);
serf__ssltunnel_request_create(conn,
setup_request,
ctx);
conn->state = SERF_CONN_SETUP_SSLTUNNEL;
serf__log(CONN_VERBOSE, __FILE__,