Update to neon trunk.

CVS patchset: 7523
CVS date: 2004/10/29 13:57:41
This commit is contained in:
jbj 2004-10-29 13:57:41 +00:00
parent e603ae4198
commit 69227ecd1b
93 changed files with 4700 additions and 1494 deletions

View File

@ -7,12 +7,6 @@ minor=`echo $1 | awk -F. '{print $2;}'`
rel=`echo $1 | awk -F. '{print $3;}'`
version=$1
# check that release version matches build version!
grep ^NEON_VERSION_MAJOR=$major\$ macros/neon.m4 || exit 1
grep ^NEON_VERSION_MINOR=$minor\$ macros/neon.m4 || exit 1
grep ^NEON_VERSION_RELEASE=$rel\$ macros/neon.m4 || exit 1
grep '^NEON_VERSION_TAG=$' macros/neon.m4 || exit 1
for f in config.hw; do
in=$f.in
out=$f

View File

@ -1 +1 @@
0.24.7
0.0.0-dev

View File

@ -1 +1,6 @@
Joe Orton <joe@orton.demon.co.uk>
neon is Copyright (C) 1999-2004 Joe Orton <joe@manyfish.co.uk>
Portions are:
Copyright (C) 1999-2000 Tommi Komulainen <Tommi.Komulainen@iki.fi>
Copyright (C) 1999-2000 Peter Boos <pedib@colorfullife.com>
Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
Copyright (C) 2004 Aleix Conchillo Flaque <aleix@member.fsf.org>

View File

@ -2,6 +2,8 @@
Known problems/bugs in neon -*- text -*-
---------------------------
* look at escaping logic again w.r.t. ?, # characters?
* 2818 requires that a on rejection of the SSL server cert, a "bad certificate"
message should be sent - this is not being done currently (and can probably
only be done with OpenSSL by actually doing cert verification in the verify
@ -10,19 +12,32 @@ Known problems/bugs in neon -*- text -*-
* ne_lock_discover does not handle multiple (shared) locks on
a single resource.
* ne_lock_refresh does not update the passed-in lock structure.
* SSL session caching issues; only cache for clean shutdowns, and
only cache on shutdown, since the SSL_SESSION may change during
an ne_session.
an ne_session?
* what is passed as 'path' to req create hook: auth needs Request-URI;
how does that interact with proxies? also they will be passed NULL
for a CONNECT request, or "*" possibly as well.
* expect100 support is broken.
* It would be nice to fail with a friendly error message if a client
cert is requested by the srever but one is not provided. Currently,
returning -1 from the provide_client_cert function would allow that
(as it forces the SSL handshake to fail), but that would prevent
opportunistic use of client certificates, of the "SSLVerifyClient
optional" variety.
* D.J. Heap has a proxy which returns a 401 in response to a CONNECT;
relax the ne_auth rules to allow this since it's unambiguous.
* Error handling from ne__pull_request_body/send_request_body is
buggy: socket errors are not distinguished from body provider errors;
the connection must be closed in ne_request after a body provider
error.
* Check whether the following always return UTF-8-encoded strings:
- ne_ssl_clicert_name
- ne_ssl_cert_identity

View File

@ -1,15 +1,59 @@
Mon May 17 21:25:44 2004 Joe Orton <joe@manyfish.co.uk>
* neon.mak: Fix handling of paths with spaces, and simplify (Jon
Foster <jon@jon-foster.co.uk>).
* neon.mak: Fix for handling of paths with spaces, and
simplify (Jon Foster <jon@jon-foster.co.uk>).
Thu May 13 11:42:07 2004 Joe Orton <joe@manyfish.co.uk>
* configure.in: Don't rely on echo -n in ne_version.
Fri Mar 26 12:07:04 2004 Joe Orton <joe@manyfish.co.uk>
Sun Feb 22 20:29:04 2004 Joe Orton <joe@manyfish.co.uk>
* Makefile.in (distclean): Clean more.
* configure.in: Move memleak.h include to end of config.h.
Sun Feb 22 18:44:55 2004 Joe Orton <joe@manyfish.co.uk>
* configure.in: Fix to run DAV tests when an XML parser is
configured.
Sat Jan 24 17:50:52 2004 Joe Orton <joe@manyfish.co.uk>
* configure.in: AC_DEFINE _GNU_SOURCE again so that it's used
during compiler checks.
Sat Jan 24 17:33:54 2004 Joe Orton <joe@manyfish.co.uk>
* configure.in: Cleanup; move all AC_SUBSTs together; use a single
AH_TOP for config.h.in header; require autoconf 2.58.
Thu Jan 1 17:40:34 2004 Joe Orton <joe@manyfish.co.uk>
* neon-config.in: Handle 'lfs' feature.
Sat Nov 15 09:42:40 2003 Joe Orton <joe@manyfish.co.uk>
* neon-config.in: Print help output on stderr for unknown arguments.
(usage): Update help output for new NE_FLAG_ substitutions.
Sat Nov 15 09:24:49 2003 Joe Orton <joe@manyfish.co.uk>
* configure.in: Update for use latest autoconf best-practice:
s/AC_HELP_STRING/AS_HELP_STRING.
Fri Nov 14 11:28:24 2003 Joe Orton <joe@manyfish.co.uk>
* configure.in, neon-config.in: Use new NE_FLAG substitutions
for feature detection.
Fri Nov 14 09:08:10 2003 Joe Orton <joe@manyfish.co.uk>
* configure.in: Add -export-symbols-regex to NEON_LINK_FLAGS to
prevent export of ne__ symbols where possible.
Sun Oct 26 12:42:15 2003 Joe Orton <joe@manyfish.co.uk>
* neon-config.in: Fix to exit with failure for an unrecognized
option.
Sat Oct 25 10:37:59 2003 Joe Orton <joe@manyfish.co.uk>

View File

@ -1,14 +1,140 @@
To install neon on Windows you need expat-lite already installed on your system.
It can be taken from the Apache distribution or downloaded from the expat website.
Now simply point make to the expat sources:
nmake /f neon.mak EXPAT_SRC=\path\to\expat-lite
This should work with Microsoft VC++ 5 and 6.
After compiling the Release subdirectory contains neons.lib, against which you can
link your program. When you run your program make sure the XMLPARSE.DLL from
expat is accessable, i.e. is in your PATH.
Building neon on Windows uses a single Nmake neon.mak file. By
placing various parameters on nmake's command line, you can specify
exactly the features and behavior of the Neon libraries. The
parameters are additive, so to add more features, add the command line
options specified in the particular section below.
All the builds described below should work with Microsoft VC++ 5 and
6.
Build neon
__________
This is the most basic version of the Neon library you can build. It
does not require any third party libraries, but you do not get the
full capabilities of Neon.
Compile Neon with no parameters
nmake /f neon.mak
After compiling the library, the directory contains libneon.lib,
against which you can link your program.
Build neon with WebDAV support
______________________________
To compile Neon with WebDAV support, Neon must compile and link
against a third-party XML parser, either expat, expat-lite, libxml or
libxml2. This Windows neon.mak file is designed to compile and link
against the pre-built Expat Windows libraries version 1.95.X or newer.
This library is available for download from
http://sourceforge.net/projects/expat/
Download the latest expat_win32bin package named
expat_win32bin_X_YY_Z.exe
and install it on your system. It wants to install itself into
Q:\some\dir\Expat-X.Y.ZZ. Choose your installation location for expat
and then compile Neon with
nmake /f neon.mak EXPAT_SRC=\path\to\Expat-X.YY.Z
NOTE: When you run your program make sure the LIBEXPAT.DLL from expat
is accessible, i.e. is in your PATH.
This should work with Microsoft VC++ 5 and 6.
Build neon with dynamically linked SSL support
______________________________________________
To build neon on Windows with SSL support you need OpenSSL already
installed on your system (I used OpenSSL 0.9.6g). It can be
downloaded from
http://www.openssl.org/source/openssl-0.9.6g.tar.gz
After compiling OpenSSL, now simply point make to the OpenSSL sources:
nmake /f neon.mak OPENSSL_SRC=\path\to\openssl
NOTE: The include files for OpenSSL reside in inc32/ directory
("../openssl-0.9.6g/inc32").
NOTE: Make sure that your program is linked against libeay32.lib and
ssleay32.lib (normally in "../openssl-0.9.6g/out32dll") and that
libeay32.dll and ssleay32.dll is accessible, i.e. is in your PATH.
Build neon with statically linked OpenSSL support
_________________________________________________
If you want to statically link against OpenSSL, then add the
OPENSSL_STATIC parameter.
nmake /f neon.mak OPENSSL_SRC=\path\to\openssl OPENSSL_STATIC=yes
Build neon with statically linked Zlib support
______________________________________________
If you want to build Neon with the capability to decompress compressed
content, then you need to compile against the Zlib library.
Currently, the Neon's neon.mak file expects to compile and link a self
compiled version of Zlib. You need Zlib 1.1.4 or greater. Zlib 1.1.3
and older has a serious security issue.
Here's how to compile Zlib.
1) Get one of the Zlib source file packages in Zip format from
http://www.gzip.org/zlib/
2) Unzip it.
3) Get the package
http://www.gzip.org/zlib/contrib/zlib113-win32.zip
4) Unzip it and copy the Makefile from this package to the Zlib
1.1.4 or greater package.
5) Run nmake in the Zlib 1.1.4 or greater directory.
Now add the ZLIB_SRC parameter to Neon's neon.mak pointing to your
newly compiled zlib.
nmake /f neon.mak ZLIB_SRC=\path\to\zlib
Build neon with dynamically linked Zlib support
_______________________________________________
To build Neon with dynamically linked Zlib support, use the
instructions for the statically linked Zlib support above and add the
ZLIB_DLL parameter
nmake /f neon.mak ZLIB_SRC=\path\to\zlib ZLIB_DLL=yes
Build neon with IPv6 support
____________________________
To build neon with support for IPv6, use parameter ENABLE_IPV6.
nmake /f neon.mak ENABLE_IPV6=yes
This requires a copy of the Platform SDK which contains the IPv6
headers and libraries.
Build neon with debugging support
_________________________________
Set the DEBUG_BUILD parameter
nmake /f neon.mak DEBUG_BUILD=yes
It does not matter what value DEBUG_BUILD is set to, as long as it is
not set to "".
After compiling the library, the directory contains libneonD.lib,
against which you can link your program.

View File

@ -99,7 +99,7 @@ clean:
cd test && $(MAKE) clean
distclean: clean
rm -rf Makefile config.h config.status libtool config.log config.cache neon-config autom4te.cache neon.pc test/Makefile test/common/Makefile src/Makefile
rm -rf Makefile config.h neon.pc config.status src/Makefile libtool config.log config.cache neon-config autom4te*.cache test/Makefile
again: clean

View File

@ -1,3 +1,22 @@
Changes in release 0.25.0:
* New feature detection interface, ne_has_feature():
- replaces ne_supports_ssl(); NEON_SSL is no longer defined by neon-config.
* ne_set_request_body_fd takes offset and length arguments and returns void.
* ne_set_request_body_provider takes an off_t length argument.
* Support for non-ASCII hostnames following the IDNA spec, using GNU libidn:
- if enabled, ne_session_create can be passed a UTF-8 encoded hostname.
* ne_xml_failed() replaces ne_xml_valid(), with different return value logic.
* Support for >2Gb request/response bodies on 32-bit Unixes with LFS support:
- new ne_set_request_body_fd64() call for using an fd opened using O_LARGEFILE
- new ne_set_request_body_provider64() which takes an off64_t length argument
* ne_xml interface now rejects more invalid XML element names (e.g. "foo::bar").
* Add ne_set_addrlist() interface to bypass normal DNS resolution.
* Use a per-request flag to enable "Expect: 100-continue" support:
- ne_set_request_expect100() replaces ne_set_expect100()
* Fix handling of multiple Authentication challenges per request.
* Win32: Fix timezone handling (Jiang Lei).
* Win32: Add IPv6 support using ENABLE_IPV6 flag (Kai Sommerfeld).
Changes in release 0.24.7:
* Compression interface fixes:
- fix issues handling content decoding and request retries from

View File

@ -1,5 +1,14 @@
neon is an HTTP and WebDAV client library.
neon is an HTTP and WebDAV client library, with a C language API.
Bindings for other languages may also be available, see the web site
for more details.
Mailing list: neon@webdav.org || Web site: http://www.webdav.org/neon/
PLEASE NOTE: The neon API is subject to backwards-incompatible change
over minor releases (0.23.x -> 0.24.x) until the 1.0.0 release, but
maintains source and binary backwards compatibility through patch
releases (0.24.0 -> 0.24.7).
Current features:
@ -9,17 +18,32 @@ Current features:
- Persistent connection support (HTTP/1.1 and HTTP/1.0 aware)
- Basic and digest authentication (RFC2617) (including auth-int, md5-sess)
- Proxy support (including basic/digest authentication)
- SSL/TLS support using OpenSSL (including client certificate support)
- Generic WebDAV 207 XML response handling mechanism
- XML parsing using expat or libxml parser
- XML parsing using expat or libxml (1.x or 2.x) parser
- Easy generation of error messages from 207 error responses
- Basic HTTP/1.1 methods: GET, PUT, HEAD, OPTIONS, conditional PUT
- WebDAV resource manipulation: MOVE, COPY, DELETE, MKCOL.
- WebDAV metadata support: set and remove properties (PROPPATCH), query
any set of properties (PROPFIND).
- WebDAV locking support
- Autoconf macros supplied for easily embedding neon directly inside
an application source tree.
Provides lower-level interfaces to directly implement new HTTP
methods, and higher-level interfaces so that you don't have to
worry about the lower-level stuff.
methods, and higher-level interfaces so that you don't have to worry
about the lower-level stuff.
Joe Orton
<joe@orton.demon.co.uk>
neon is licensed under the GNU Library GPL; see src/COPYING.LIB for
full details. The manual is licensed under the terms of the GNU FDL;
see doc/fdl.sgml or the generated documentation. The autoconf macros
in the "macros" directory are under a less restrictive license, see
each file for details. The test suite is licensed under the GNU GPL;
see test/COPYING for full details.
neon is Copyright (C) 1999-2004 Joe Orton
Portions are:
Copyright (C) 1999-2000 Tommi Komulainen <Tommi.Komulainen@iki.fi>
Copyright (C) 1999-2000, Peter Boos <pedib@colorfullife.com>
Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
Copyright (C) 2004 Aleix Conchillo Flaque <aleix@member.fsf.org>

View File

@ -1,52 +1,14 @@
In alphabetical order:
Thanks go to the following people for contributing to neon development
with code, patches, or good bug reports or suggestions.
Arun Garg <arung@pspl.co.in>
Blair Zajac <blair@orcaware.com>
Branko Èibej <brane@xbc.nu>
Daniel Berlin <dberlin@dberlin.org>
David Sloat <d.sloat@f5.com>
David Reid <dreid@jetnet.co.uk>
Dirk Bergstrom <dirk@juniper.net>
Gerald Richter <richter@ecos.de>
Greg Stein <gstein@lyra.org>
Gregor Bornemann <Gregor.Bornemann@germany.sun.com>
Jeff Johnson <jbj@redhat.com>
Jeremy Elson <jelson@circlemud.org>
Jim Whitehead <ejw@cse.ucsc.edu>
Johan Lindh <johan@linkdata.se>
Justin Erenkrantz <jerenkrantz@apache.org>
Kai Sommerfeld <kai.sommerfeld@germany.sun.com>
Keith Wannamaker <keith@wannamaker.org>
Lee Mallabone <lee0@callnetuk.com>
Magnus Sirwiö <sirwio@hotmail.com>
Markus Mueller <markus-m.mueller@ubs.com>
Max Bowsher <maxb@ukf.net>
Michael Sobolev <mss@despair.spb.ru>
Mike Rosellini <m@icopyright.com>
Mo DeJong <mdejong@cygnus.com>
Noriaki Takamiya <takamiya@po.ntts.co.jp>
Olof Oberg <mill@pedgr571.sn.umu.se>
Pawel Golaszewski <blues@ds.pg.gda.pl>
Peter Boos <PediB@colorfullife.com>
Peter Moulder <pjm@bofh.asn.au>
rado <dzusto@yahoo.com>
Risko Gergely <risko@risko.hu>
Rodney Dawes <dobey@ximian.com>
Sam TH <sam@uchicago.edu>
Sander Alberink <sander.alberink@cmg.nl>
Sander Striker <striker@apache.org>
Stefan Esser <s.esser@e-matters.de>
Shane Mayer <shanemayer42@yahoo.com>
Taisuke Yamada <tai@iij.ad.jp>
Teng Xu <txu@soe.ucsc.edu>
Tom Bednarz <tombednarz@hotmail.com>
Tom Lee <i_am_gnomey@hotmail.com>
Torsten Kalix <torsten.kalix@bredex.de>
Wilfredo Sánchez <wsanchez@mit.edu>
Arun Garg, Blair Zajac, Branko Èibej, Daniel Berlin, David Sloat,
David Reid, Dirk Bergstrom, Ulrich Drepper, Gerald Richter, Greg
Stein, Gregor Bornemann, Jeff Johnson, Jeremy Elson, Jim Whitehead,
Johan Lindh, Justin Erenkrantz, Kai Sommerfeld, Keith Wannamaker, Lee
Mallabone, Magnus Sirwiö, Markus Mueller, Max Bowsher, Michael
Sobolev, Mike Rosellini, Mo DeJong, Noriaki Takamiya, Olof Oberg,
Pawel Golaszewski, Peter Boos, Peter Moulder, rado, Risko Gergely,
Rodney Dawes, Sam TH, Sander Alberink, Sander Striker, Stefan Esser,
Shane Mayer, Taisuke Yamada, Teng Xu, Tom Bednarz, Tom Lee, Tommi
Komulainen, Torsten Kalix, Wilfredo Sánchez, Daniel Veillard,
Originators of stolen code:
Tommi Komulainen <Tommi.Komulainen@iki.fi>
Daniel Veillard <Daniel.Veillard@w3.org>
Eric S Raymond <esr@snark.thyrsus.com>
Ulrich Drepper <drepper@gnu.org>

View File

@ -32,7 +32,7 @@ For one-point-oh
62. Select which auth mechanisms are allowed, e.g. JUST SAY NO to
basic might very well be useful to some apps.
63. Unconditionally turn off Nagle algorithm.
64. Add options to only enable SSLv2 support, etc.
Longer term
-----------
@ -116,3 +116,5 @@ Longer term
57. Add function to map of status-code values to i18n-ized reason
phrase.
65. Add ne_uri_copy function and use it in ne_lock_copy. (patch
sent to neon@webdav.org)

View File

@ -11,12 +11,12 @@ if test ! -f .version; then
echo -n 0.0.0-dev > doc/version.xml
fi
set -e
echo -n "libtoolize... "
${LIBTOOLIZE:-libtoolize} --copy --force >/dev/null
echo -n "aclocal... "
${ACLOCAL:-aclocal} -I macros
echo -n "autoheader... "
${AUTOHEADER:-autoheader}
echo -n "libtoolize... "
${LIBTOOLIZE:-libtoolize} --copy --force >/dev/null
echo -n "autoconf... "
${AUTOCONF:-autoconf} -Wall
echo okay.

View File

@ -1,6 +1,7 @@
/*
Win32 config.h
Copyright (C) 1999-2000, Peter Boos <pedib@colorfullife.com>
Copyright (C) 2002, 2004, Joe Orton <joe@manyfish.co.uk>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@ -18,25 +19,31 @@
MA 02111-1307, USA
*/
#ifdef _WIN32
#define WIN32
#endif
#if defined(_WIN32) && !defined(WIN32)
#define WIN32
#endif
#ifdef WIN32
#define NEON_VERSION "@VERSION@"
#define NEON_VERSION_MAJOR (@MAJOR@)
#define NEON_VERSION_MINOR (@MINOR@)
#define HAVE_STRING_H
#define HAVE_EXPAT
#define HAVE_OLD_EXPAT
#define HAVE_MEMCPY
#define NEON_VERSION "@VERSION@"
#define NEON_VERSION_MAJOR (@MAJOR@)
#define NEON_VERSION_MINOR (@MINOR@)
#define HAVE_ERRNO_H
#define HAVE_LIMITS_H
#define HAVE_STDLIB_H
#define HAVE_STRING_H
#define HAVE_LIMITS_H
#define HAVE_MEMCPY
#define HAVE_SETSOCKOPT
#ifndef NEON_NODAV
#define USE_DAV_LOCKS
#endif
#define NE_FMT_SIZE_T "u"
#define NE_FMT_SSIZE_T "d"
#define NE_FMT_OFF_T "ld"
/* Win32 uses a underscore, so we use a macro to eliminate that. */
#define snprintf _snprintf
@ -44,10 +51,10 @@
#define strcasecmp strcmpi
#define strncasecmp strnicmp
#define ssize_t int
#define inline __inline
#define off_t _off_t
#define inline __inline
#define off_t _off_t
#include <io.h>
#define read _read
#endif

View File

@ -1,6 +1,4 @@
dnl Require autoconf 2.53 for an AC_C_BIGENDIAN which supports
dnl cross-compiling.
AC_PREREQ(2.53)
AC_PREREQ(2.58) dnl 2.58 required for AS_HELP_STRING
dnl Extract the version (sans LF) from .version, created at release-time.
m4_define(ne_version, [m4_translit(m4_include(.version), [
@ -8,7 +6,7 @@ m4_define(ne_version, [m4_translit(m4_include(.version), [
AC_INIT(neon, ne_version, [neon@webdav.org])
AC_COPYRIGHT([Copyright (c) 2000, 2001, 2002 Joe Orton
AC_COPYRIGHT([Copyright 2000-2004 Joe Orton
This configure script may be copied, distributed and modified under the
terms of the GNU Library General Public license; see COPYING for more details])
@ -21,16 +19,22 @@ NEON_WITH_LIBS
# libraries which are detected (e.g. OpenSSL) can still be found when
# building using the --libs output of neon-config.
user_LDFLAGS=$LDFLAGS
AC_SUBST(user_LDFLAGS)
# By default, allow 'make install' to work.
ALLOW_INSTALL=yes
AC_SUBST(ALLOW_INSTALL)
# Always defined
AC_DEFINE([_GNU_SOURCE], 1, [Unconditionally define _GNU_SOURCE])
# Defined when neon is built as library
AC_DEFINE(NEON_IS_LIBRARY, 1, [Define when building neon as a library])
AC_DEFINE([_GNU_SOURCE], 1, [Always defined to enable GNU extensions])
dnl Place straight into config.h.in:
AH_TOP([
/* Only defined when neon source directory built as a standalone library */
#define NEON_IS_LIBRARY 1])
AH_BOTTOM([
/* Enable leak-tracking versions of ne_*alloc when NEON_MEMLEAK is enabled */
#ifdef NEON_MEMLEAK
# include "memleak.h"
#endif])
AC_PROG_INSTALL
@ -43,11 +47,8 @@ AC_PROG_LIBTOOL
AC_EXEEXT
top_builddir=`pwd`
AC_SUBST(top_builddir)
AC_ARG_ENABLE(webdav,
AC_HELP_STRING([--disable-webdav], [disable WebDAV support]))
AC_ARG_ENABLE(webdav,
AS_HELP_STRING([--disable-webdav],[disable WebDAV support]))
if test "$enable_webdav" = "no"; then
NEON_WITHOUT_WEBDAV
@ -60,7 +61,6 @@ fi
# The bundled macros also set this, which makes sure we recurse
# into the 'src' directory.
NEON_BUILD_BUNDLED=yes
AC_SUBST(NEON_BUILD_BUNDLED)
# Define NEON_VERSION* and make the appropriate substitutions.
NEON_VERSIONS
@ -68,6 +68,10 @@ NEON_VERSIONS
# Pass the interface version on to libtool when linking libneon.la
NEON_LINK_FLAGS="-version-info ${NEON_INTERFACE_VERSION}"
# Library-internal symbols are in the ne__ namespace: tell libtool
# to not export these from the built library if possible.
NEON_LINK_FLAGS="$NEON_LINK_FLAGS -export-symbols-regex '^ne_[[^_]]'"
# Checks to compile test suite
NEON_TEST
@ -82,20 +86,11 @@ NEON_DEBUG
# Leave till last to prevent CFLAGS affecting checks.
NEON_WARNINGS
CFLAGS="$CFLAGS -I\${top_builddir}"
dnl Substitute NEON_VERSION for neon-config too.
AC_SUBST(NEON_VERSION)
CPPFLAGS="$CPPFLAGS -I\${top_builddir}"
AC_ARG_ENABLE(memleak,
AC_HELP_STRING([--enable-memleak], [for test builds only: enable memory leak checking]))
dnl Have autoheader include the following template in config.h.in:
AH_VERBATIM([NEON_MEMLEAK],
[/* Enable memory leak detection. */
#ifdef NEON_MEMLEAK
# include "memleak.h"
#endif])
AS_HELP_STRING([--enable-memleak],
[for test builds only: enable memory leak checking]))
if test "$enable_memleak" = "yes"; then
CPPFLAGS="$CPPFLAGS -DNEON_MEMLEAK -I\$(top_srcdir)/src"
@ -106,7 +101,7 @@ fi
# Enable tests for optional features
TESTS="\$(BASIC_TESTS)"
HELPERS=""
if test "$NEON_SUPPORTS_SSL" = "yes"; then
if test $NE_FLAG_SSL = yes; then
# Only enable SSL tests if an openssl binary is found (needed to make
# certs etc).
AC_PATH_PROG(OPENSSL, openssl, notfound)
@ -117,19 +112,25 @@ if test "$NEON_SUPPORTS_SSL" = "yes"; then
AC_MSG_WARN([no openssl binary in \$PATH: SSL tests disabled])
fi
fi
if test "$NEON_SUPPORTS_DAV" = "yes"; then
TESTS="$TESTS \$(DAV_TESTS)"
fi
if test "$NEON_SUPPORTS_ZLIB" = "yes"; then
if test $NE_FLAG_ZLIB = yes; then
TESTS="$TESTS \$(ZLIB_TESTS)"
HELPERS="$HELPERS \$(ZLIB_HELPERS)"
fi
AC_SUBST(HELPERS)
AC_SUBST(TESTS)
if test x$enable_webdav != xno; then
TESTS="$TESTS \$(DAV_TESTS)"
fi
AC_CONFIG_FILES([neon-config], [chmod +x neon-config])
AC_CONFIG_FILES([Makefile src/Makefile test/Makefile neon.pc])
AC_SUBST(NEON_VERSION)
AC_SUBST(NEON_BUILD_BUNDLED)
AC_SUBST(top_builddir)
AC_SUBST(user_LDFLAGS)
AC_SUBST(HELPERS)
AC_SUBST(TESTS)
AC_SUBST(ALLOW_INSTALL)
AC_OUTPUT
# for VPATH builds:
@ -140,8 +141,8 @@ AC_MSG_NOTICE([Configured to build AC_PACKAGE_STRING:
Install prefix: ${prefix}
Compiler: ${CC}
XML Parser: ${neon_xml_parser_message}
SSL library: ${neon_ssl_message}
zlib support: ${neon_zlib_message}
SSL library: ${ne_SSL_message}
zlib support: ${ne_ZLIB_message}
Build libraries: Shared=${enable_shared}, Static=${enable_static}
Now run 'make' to compile the neon library.

View File

@ -10,12 +10,11 @@
<pubdate>March 2001</pubdate>
</biblioentry>
<biblioentry id="bib.xsltrec">
<biblioentry id="bib.xmlnames">
<abbrev>REC-XML-names</abbrev>
<editor><firstname>James</firstname><surname>Clark</surname></editor>
<title><ulink url="http://www.w3.org/TR/xslt">XSL Transformations
(XSLT) Version 1.0</ulink></title> <publishername>W3C
Recommendation</publishername> <pubdate>16 November 1999</pubdate>
<corpauthor>World Wide Web Consortium</corpauthor>
<title><ulink url="http://www.w3.org/TR/REC-xml-names">Namespaces in XML</ulink></title>
<pubdate>January 1999</pubdate>
</biblioentry>
<biblioentry id="bib.rfc2616">

View File

@ -1 +1 @@
5 July 2004
29 October 2004

View File

@ -69,6 +69,7 @@
<!ENTITY refresolve SYSTEM "ref/resolve.xml">
<!ENTITY refiaddr SYSTEM "ref/iaddr.xml">
<!ENTITY refclicert SYSTEM "ref/clicert.xml">
<!ENTITY refxml SYSTEM "ref/xml.xml">
]>
@ -170,6 +171,7 @@ ignoring the WebDAV support if desired.</para>
&refstatus; <!-- ne_status -->
&reftok; <!-- ne_token -->
&refvers; <!-- ne_version_match -->
&refxml; <!-- ne_xml_parser -->
<!-- REFEND -->
<!-- ******************************************************************* -->

View File

@ -62,9 +62,9 @@
<para>The <function>ne_ssl_clicert_read</function> function reads
a <firstterm>client certificate</firstterm> from a
PKCS#12-formatted file, and returns an
<type>ne_ssl_client_certificate</type> object. If the client
<type>ne_ssl_client_cert</type> object. If the client
certificate is encrypted, it must be decrypted before it is used.
An <type>ne_ssl_client_certificate</type> object holds a client
An <type>ne_ssl_client_cert</type> object holds a client
certificate and the associated private key, not just a
certificate; the term "<glossterm>client certificate</glossterm>"
will used to refer to this pair.</para>
@ -124,7 +124,7 @@
<para>The following code reads a client certificate and decrypts
it if necessary, then loads it into an HTTP session.</para>
<programlisting>ne_ssl_client_certificate *ccert;
<programlisting>ne_ssl_client_cert *ccert;
ccert = ne_ssl_clicert_read("/path/to/client.p12");

View File

@ -9,6 +9,7 @@
<refname id="ne_iaddr_make">ne_iaddr_make</refname>
<refname id="ne_iaddr_cmp">ne_iaddr_cmp</refname>
<refname id="ne_iaddr_print">ne_iaddr_print</refname>
<refname id="ne_iaddr_typeof">ne_iaddr_typeof</refname>
<refname id="ne_iaddr_free">ne_iaddr_free</refname>
<refpurpose>functions to manipulate and compare network addresses</refpurpose>
</refnamediv>
@ -32,8 +33,8 @@ typedef enum {
<funcprototype>
<funcdef>int <function>ne_iaddr_cmp</function></funcdef>
<paramdef>const ne_inet_addr *<parameter>i1</parameter></paramdef>
<paramdef>const ne_inet_addr *<parameter>i2</parameter></paramdef>
<paramdef>const ne_inet_addr *<parameter>ia1</parameter></paramdef>
<paramdef>const ne_inet_addr *<parameter>ia2</parameter></paramdef>
</funcprototype>
<funcprototype>
@ -43,9 +44,14 @@ typedef enum {
<paramdef>size_t <parameter>bufsiz</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>ne_iaddr_type <function>ne_iaddr_typeof</function></funcdef>
<paramdef>const ne_inet_addr *<parameter>ia</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>void <function>ne_iaddr_free</function></funcdef>
<paramdef>const ne_inet_addr *<parameter>addr</parameter></paramdef>
<paramdef>const ne_inet_addr *<parameter>ia</parameter></paramdef>
</funcprototype>
</funcsynopsis>
@ -76,6 +82,9 @@ typedef enum {
buffer, for instance the string
<literal>"127.0.0.1"</literal>.</para>
<para><function>ne_iaddr_type</function> returns the type of the
given network address.</para>
<para><function>ne_iaddr_free</function> releases the memory
associated with a network address object.</para>

81
neon/doc/ref/sslca.xml Normal file
View File

@ -0,0 +1,81 @@
<refentry id="refsslca">
<refmeta>
<refentrytitle>ne_ssl_load_ca</refentrytitle>
<manvolnum>3</manvolnum>
</refmeta>
<refnamediv>
<refname id="ne_ssl_load_ca">ne_ssl_load_ca</refname>
<refname id="ne_ssl_load_default_ca">ne_ssl_load_default_ca</refname>
<refpurpose>load SSL Certificate Authorities</refpurpose>
</refnamediv>
<refsynopsisdiv>
<funcsynopsis>
<funcsynopsisinfo>#include &lt;ne_session.h&gt;</funcsynopsisinfo>
<funcprototype>
<funcdef>int <function>ne_ssl_load_ca</function></funcdef>
<paramdef>ne_session *<parameter>session</parameter></paramdef>
<paramdef>const char *<parameter>filename</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>ne_ssl_load_default_ca</function></funcdef>
<paramdef>ne_session *<parameter>session</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>To indicate that a given CA certificate is trusted by the user,
the certificate can be loaded using the <function>ne_ssl_load_ca</function>
function. The <parameter>filename</parameter> parameter given must specify
the location of a PEM-encoded CA certificate.</para>
<para>The SSL library in use by neon may include a default set
of CA certificates; calling the
<function>ne_ssl_load_default_ca</function> function will indicate
that these CAs are trusted by the user.</para>
<para>If no CA certificates are loaded, or the server presents
a certificate which is invalid in some way, then the certificate must
be manually verified (see <xref linkend="ne_ssl_set_verify"/>), otherwise the
connection will fail.</para>
</refsect1>
<refsect1>
<title>Return value</title>
<para>Both <function>ne_ssl_load_ca</function> and
<function>ne_ssl_load_default_ca</function> functions return
<literal>0</literal> on success, or non-zero on failure.</para>
</refsect1>
<refsect1>
<title>Examples</title>
<para>Load the CA certificate stored in <filename>/path/to/cacert.pem</filename>:</para>
<programlisting>&egsess;
if (ne_ssl_load_ca(sess, "/path/to/cacert.pem")) {
printf("Could not load CA cert: %s\n", ne_get_error(sess));
}</programlisting>
</refsect1>
<refsect1>
<title>See also</title>
<para><xref linkend="ne_get_error"/>, <xref
linkend="ne_ssl_set_verify"/></para> </refsect1>
</refentry>

56
neon/doc/ref/xml.xml Normal file
View File

@ -0,0 +1,56 @@
<refentry id="refxml">
<refmeta>
<refentrytitle>ne_xml_create</refentrytitle>
<manvolnum>3</manvolnum>
</refmeta>
<refnamediv>
<refname id="ne_xml_create">ne_xml_create</refname>
<refname id="ne_xml_destroy">ne_xml_destroy</refname>
<refpurpose>create and destroy an XML parser</refpurpose>
</refnamediv>
<refsynopsisdiv>
<funcsynopsis>
<funcsynopsisinfo>#include &lt;ne_xml.h&gt;</funcsynopsisinfo>
<funcprototype>
<funcdef>ne_xml_parser *<function>ne_xml_create</function></funcdef>
<void/>
</funcprototype>
<funcprototype>
<funcdef>void <function>ne_xml_destroy</function></funcdef>
<paramdef>ne_xml_parser *<parameter>parser</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>The <function>ne_xml_create</function> function creates an
XML parser object, which can be used for parsing XML documents
using stacked SAX handlers.</para>
</refsect1>
<refsect1>
<title>Return value</title>
<para><function>ne_xml_create</function> returns a pointer to an
XML parser object, and never &null;</para> </refsect1>
<refsect1>
<title>See also</title>
<para>XXX</para>
</refsect1>
</refentry>

View File

@ -73,11 +73,11 @@
</sect1>
<sect1 id="compliance">
<title>Protocol compliance</title>
<title>Standards compliance</title>
<para>&neon; is intended to be compliant with the IETF
protocol standards it implements, with a few exceptions where
real-world use has necessitated minor deviations. These
<para>&neon; is intended to be compliant with the IETF and W3C
standards which it implements, with a few exceptions due to
practical necessity or interoperability issues. These
exceptions are documented in this section.</para>
<sect2><title>RFC 2518, HTTP Extensions for Distributed Authoring&mdash;WebDAV</title>
@ -116,4 +116,25 @@
quotes&mdash;this is not known to cause any problems with
other server implementations.</para></sect2>
<sect2>
<title>Namespaces in XML</title>
<para>The &neon; XML parser interface will accept and parse
without error some XML documents which are well-formed
according to the XML specification but do not conform to the
"Namespaces in XML" specification <xref
linkend="bib.xmlnames"/>. Specifically: the restrictions on
the first character of the <literal>NCName</literal> rule are
not all implemented; &neon; will allow any
<literal>CombiningChar</literal>, <literal>Extender</literal>
and some characters from the <literal>Digit</literal> class in
this position.</para> </sect2>
<!-- a few RFC2818/3280 issues: rules about when to cache
sessions in the face of unclean shutdown are strict, neon is
probably not compliant: document or fix. Likewise SSL
shutdown issues in general. Cert hostname checks allow
wildcard "*." syntax which is less than 2818 but more than
3280 requires. -->
</sect1>

View File

@ -1 +1 @@
0.24.7
0.0.0-dev

View File

@ -1,13 +1,24 @@
Sun Sep 12 18:38:13 2004 Joe Orton <joe@manyfish.co.uk>
* neon.m4 (NEON_USE_EXTERNAL): Check for IDNA, LFS, SOCKS
support.
(NEON_SOCKS): Use common feature code for SOCKSv5 support.
Fri Sep 10 20:52:54 2004 Joe Orton <joe@manyfish.co.uk>
* neon.m4 (LIBNEON_SOURCE_CHECKS): Safer autoheader template for
declaring stpcpy as necessary for bundled neon builds.
(NEON_WARNINGS): Drop -Winline.
Wed Aug 25 19:44:26 2004 Joe Orton <joe@manyfish.co.uk>
* neon.m4 (LIBNEON_SOURCE_CHECKS): Check for poll.
Sat Jul 3 11:39:01 2004 Joe Orton <joe@manyfish.co.uk>
* neon.m4 (LIBNEON_SOURCE_CHECKS): Pick up gethostbyname in
-lsocket for QNX.
Wed May 19 08:36:44 2004 Joe Orton <joe@manyfish.co.uk>
* neon.m4 (LIBNEON_SOURCE_CHECKS): Declare stpcpy on modern
"Linux-like" AIXes.
Fri Apr 16 11:43:10 2004 Joe Orton <joe@manyfish.co.uk>
* neon-xml-parser.m4 (NEON_XML_PARSER): If built using libtool,
@ -21,6 +32,87 @@ Tue Apr 13 20:51:59 2004 Joe Orton <joe@manyfish.co.uk>
* neon.m4 (NEON_GSSAPI): Check for presence of
gssapi/gssapi_generic.h.
Wed Apr 7 13:16:33 2004 Joe Orton <joe@manyfish.co.uk>
* neon.m4 (NE_LARGEFILE): Check for strtoq.
Mon Mar 15 19:59:36 2004 Joe Orton <joe@manyfish.co.uk>
* neon.m4 (LIBNEON_SOURCE_CHECKS): Be safer around getaddrinfo
blacklist for HP-UX and reference why it's needed.
Sun Mar 7 11:15:44 2004 Joe Orton <joe@manyfish.co.uk>
* neon.m4 (LIBNEON_SOURCE_CHECKS): Use NE_LARGEFILE in-place
rather than AC_REQUIRE'ing it.
(NE_LARGEFILE): Add NE_LFS to CPPFLAGS for use in bundled builds.
Mon Feb 23 23:02:54 2004 Joe Orton <joe@manyfish.co.uk>
* neon.m4 (NE_SNPRINTF): Define HAVE_TRIO if trio is used.
Mon Feb 23 00:22:39 2004 Joe Orton <joe@manyfish.co.uk>
* neon.m4 (LIBNEON_SOURCE_CHECKS): Give INCLUDES argument to
AC_CHECK_HEADERS; prevent warning from cpp test for netinet/in.h
on some platforms.
Sun Feb 22 17:52:42 2004 Joe Orton <joe@manyfish.co.uk>
* neon.m4 (NE_SEARCH_LIBS): Fix to run actions-if-found if
function is found without needing additional libraries.
(LIBNEON_SOURCE_CHECKS): Only check for gethostbyname if
getaddrinfo is not found. Disable getaddrinfo on HP-UX 11.[01]*
here rather than ne_socket.c.
Sat Jan 24 17:49:50 2004 Joe Orton <joe@manyfish.co.uk>
* neon.m4 (LIBNEON_SOURCE_CHECKS): Also check for __tm_gmtoff in
struct tm.
Sat Jan 24 17:16:48 2004 Joe Orton <joe@manyfish.co.uk>
* neon.m4: Remove -ansi-pedantic and -Wimplicit-prototypes for gcc
3.4 compatibility (thanks to Olaf Hering).
Sat Jan 3 14:11:14 2004 Joe Orton <joe@manyfish.co.uk>
* neon-test.m4: Check for stdint.h.
Sat Jan 3 13:17:21 2004 Joe Orton <joe@manyfish.co.uk>
* neon.m4 (NE_LARGEFILE): Add NE_LFS to neon-config --cflags
output.
Thu Jan 1 18:42:56 2004 Joe Orton <joe@manyfish.co.uk>
* neon.m4 (NEON_FORMAT): Use C99 'll' rather than non-standard 'q'
length modifier.
Thu Jan 1 17:36:39 2004 Joe Orton <joe@manyfish.co.uk>
* neon.m4 (NE_LARGEFILE): New macro.
(LIBNEON_SOURCE_CHECKS): Call it.
Sat Nov 15 09:25:43 2003 Joe Orton <joe@manyfish.co.uk>
* neon.m4, neon-xml-parser.m4: Update for latest autoconf
best-practice: s/AC_HELP_STRING/AS_HELP_STRING, replace AC_TRY_RUN
with AC_RUN_IFELSE, AC_TRY_LINK_FUNC with AC_LINK_IFELSE,
AC_TRY_COMPILE with AC_COMPILE_IFELSE, remove AC_LANG_C and
AC_PROG_CC_STDC,
Fri Nov 14 13:12:10 2003 Joe Orton <joe@manyfish.co.uk>
* neon.m4 (NEON_LIBIDN): New macro.
(LIBNEON_SOURCE_CHECKS): Use NEON_LIBIDN.
Fri Nov 14 11:28:58 2003 Joe Orton <joe@manyfish.co.uk>
* neon.m4 (NE_ENABLE_SUPPORT, NE_DISABLE_SUPPORT): New macros.
Use throughout to flag support or lack of support for optional
features.
Thu Nov 13 20:25:28 2003 Joe Orton <joe@manyfish.co.uk>
* neon.m4 (LIBNEON_SOURCE_CHECKS): Check for gethostbyname in
@ -293,6 +385,11 @@ Sun May 19 20:23:55 2002 Joe Orton <joe@manyfish.co.uk>
* neon.m4 (NEON_WARNINGS): Remove with_warnings variable;
simplify.
Wed May 19 08:36:44 2004 Joe Orton <joe@manyfish.co.uk>
* neon.m4 (LIBNEON_SOURCE_CHECKS): Declare stpcpy on modern
"Linux-like" AIXes.
Sun May 19 09:35:08 2002 Joe Orton <joe@manyfish.co.uk>
* neon.m4 (NE_FIND_AR): Fix $PATH handling on some Linux

View File

@ -1,4 +1,4 @@
# Copyright (C) 2001-2002 Joe Orton <joe@manyfish.co.uk> -*- autoconf -*-
# Copyright (C) 2001-2004 Joe Orton <joe@manyfish.co.uk> -*- autoconf -*-
#
# This file is free software; you may copy and/or distribute it with
# or without modifications, as long as this notice is preserved.
@ -29,7 +29,7 @@ dnl CPPFLAGS which make "gcc -Werror" fail in NEON_FORMAT; suggest
dnl this macro is used first.
AC_BEFORE([$0], [NEON_XML_PARSER])
AC_CHECK_HEADERS(sys/time.h)
AC_CHECK_HEADERS(sys/time.h stdint.h)
AC_CHECK_FUNCS(pipe isatty usleep shutdown)

View File

@ -86,14 +86,14 @@ AC_DEFUN([NEON_XML_PARSER], [
dnl Switches to force choice of library
AC_ARG_WITH([libxml2],
AC_HELP_STRING([--with-libxml2], [force use of libxml 2.x]))
AS_HELP_STRING([--with-libxml2], [force use of libxml 2.x]))
AC_ARG_WITH([expat],
AC_HELP_STRING([--with-expat], [force use of expat]))
AS_HELP_STRING([--with-expat], [force use of expat]))
dnl Flag to force choice of included expat, if available.
ifelse($#, 1, [
AC_ARG_WITH([included-expat],
AC_HELP_STRING([--with-included-expat], [use bundled expat sources]),,
AS_HELP_STRING([--with-included-expat], [use bundled expat sources]),,
with_included_expat=no)],
with_included_expat=no)

View File

@ -1,4 +1,5 @@
# Copyright (C) 1998-2004 Joe Orton <joe@manyfish.co.uk> -*- autoconf -*-
# Copyright (C) 2004 Aleix Conchillo Flaque <aleix@member.fsf.org>
#
# This file is free software; you may copy and/or distribute it with
# or without modifications, as long as this notice is preserved.
@ -88,7 +89,7 @@ AC_DEFUN([NEON_COMMON_BUNDLED],[
AC_PREREQ(2.50)
AC_ARG_WITH(included-neon,
AC_HELP_STRING([--with-included-neon], [force use of included neon library]),
AS_HELP_STRING([--with-included-neon], [force use of included neon library]),
[neon_force_included="$withval"], [neon_force_included="no"])
NEON_COMMON
@ -121,9 +122,9 @@ AC_DEFUN([NEON_VERSIONS], [
# Define the current versions.
NEON_VERSION_MAJOR=0
NEON_VERSION_MINOR=24
NEON_VERSION_RELEASE=7
NEON_VERSION_TAG=
NEON_VERSION_MINOR=25
NEON_VERSION_RELEASE=0
NEON_VERSION_TAG=-dev
NEON_VERSION="${NEON_VERSION_MAJOR}.${NEON_VERSION_MINOR}.${NEON_VERSION_RELEASE}${NEON_VERSION_TAG}"
@ -173,15 +174,16 @@ else
ne_libver=`$NEON_CONFIG --version | sed -e "s/neon //g"`
# Check whether it's possible to link against neon
AC_CACHE_CHECK([linking against neon], [ne_cv_lib_neon],
AC_TRY_LINK_FUNC([ne_version_match],
[ne_cv_lib_neon=yes], [ne_cv_lib_neon=no]))
[AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[#include <ne_utils.h>]], [[ne_version_match(0, 0);]])],
[ne_cv_lib_neon=yes], [ne_cv_lib_neon=no])])
if test "$ne_cv_lib_neon" = "yes"; then
# Now check whether the neon library version is satisfactory
AC_CACHE_CHECK([neon library version], [ne_cv_lib_neonver],
AC_TRY_RUN([#include <ne_utils.h>
int main(int argc, char **argv) {
return ne_version_match($neon_require_major, $neon_require_minor);
}], ne_cv_lib_neonver=yes, ne_cv_lib_neonver=no))
[AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[#include <ne_utils.h>]],
[[return ne_version_match($neon_require_major, $neon_require_minor);]])],
[ne_cv_lib_neonver=yes], [ne_cv_lib_neonver=no], [ne_cv_lib_neonver=no])])
fi
ne_goodver=$ne_cv_lib_neonver
LIBS=$ne_save_LIBS
@ -195,17 +197,38 @@ else
$2
fi])
dnl NEON_CHECK_SUPPORT(feature, var)
dnl NEON_CHECK_SUPPORT(feature, var, name)
AC_DEFUN([NEON_CHECK_SUPPORT], [
if $NEON_CONFIG --support $1 >/dev/null; then
neon_$1_message="supported by neon"
$2=yes
NE_ENABLE_SUPPORT($2, [$3 is supported by neon])
else
neon_$1_message="not supported by neon"
$2=no
NE_DISABLE_SUPPORT($2, [$3 is not supported by neon])
fi
])
dnl enable support for feature $1 with define $2, message $2
AC_DEFUN([NE_ENABLE_SUPPORT], [
NE_FLAG_$1=yes
AC_SUBST(NE_FLAG_$1)
AC_DEFINE([NE_HAVE_]$1, 1, [Defined if $1 is supported])
m4_if([$2], [],
[ne_$1_message="support enabled"
AC_MSG_NOTICE([$1 support is enabled])],
[ne_$1_message="$2"
AC_MSG_NOTICE([$2])])
])
dnl Disable support for feature $1 with define $1, message $3
AC_DEFUN([NE_DISABLE_SUPPORT], [
NE_FLAG_$1=no
AC_SUBST(NE_FLAG_$1)
m4_if([$2], [],
[ne_$1_message="not supported"
AC_MSG_NOTICE([$1 support is not enabled])],
[ne_$1_message="$2"
AC_MSG_NOTICE([$2])])
])
AC_DEFUN([NEON_USE_EXTERNAL], [
# Configure to use an external neon, given a neon-config script
# found at $NEON_CONFIG.
@ -215,8 +238,12 @@ NEON_CHECK_VERSION([
NEON_LIBS="$NEON_LIBS `$NEON_CONFIG --libs`"
neon_library_message="library in ${neon_prefix} (`$NEON_CONFIG --version`)"
neon_xml_parser_message="using whatever neon uses"
NEON_CHECK_SUPPORT([ssl], [NEON_SUPPORTS_SSL])
NEON_CHECK_SUPPORT([zlib], [NEON_SUPPORTS_ZLIB])
NEON_CHECK_SUPPORT([ssl], [SSL], [SSL])
NEON_CHECK_SUPPORT([zlib], [ZLIB], [zlib])
NEON_CHECK_SUPPORT([idna], [IDNA], [IDNA])
NEON_CHECK_SUPPORT([ipv6], [IPV6], [IPv6])
NEON_CHECK_SUPPORT([lfs], [LFS], [LFS])
NEON_CHECK_SUPPORT([socks], [SOCKS], [SOCKSv5])
neon_got_library=yes
], [neon_got_library=no])
])
@ -311,21 +338,27 @@ dnl give an error and fail configure.
AC_DEFUN([NE_SEARCH_LIBS], [
AC_CACHE_CHECK([for library containing $1], [ne_cv_libsfor_$1], [
AC_TRY_LINK_FUNC($1, [ne_cv_libsfor_$1="none needed"], [
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([], [[$1();]])],
[ne_cv_libsfor_$1="none needed"], [
ne_sl_save_LIBS=$LIBS
ne_cv_libsfor_$1="not found"
for lib in $2; do
LIBS="$ne_sl_save_LIBS -l$lib $NEON_LIBS"
AC_TRY_LINK_FUNC($1, [ne_cv_libsfor_$1="-l$lib"; break])
AC_LINK_IFELSE([AC_LANG_PROGRAM([], [[$1();]])],
[ne_cv_libsfor_$1="-l$lib"; break])
m4_if($3, [], [], dnl If $3 is specified, then...
[LIBS="$ne_sl_save_LIBS -l$lib $3 $NEON_LIBS"
AC_TRY_LINK_FUNC($1, [ne_cv_libsfor_$1="-l$lib $3"; break])])
AC_LINK_IFELSE([AC_LANG_PROGRAM([], [[$1();]])],
[ne_cv_libsfor_$1="-l$lib $3"; break])])
done
LIBS=$ne_sl_save_LIBS])])
if test "$ne_cv_libsfor_$1" = "not found"; then
m4_if($4, [], [AC_MSG_ERROR([could not find library containing $1])], [$4])
elif test "$ne_cv_libsfor_$1" != "none needed"; then
m4_if([$4], [], [AC_MSG_ERROR([could not find library containing $1])], [$4])
elif test "$ne_cv_libsfor_$1" = "none needed"; then
m4_if([$5], [], [:], [$5])
else
NEON_LIBS="$ne_cv_libsfor_$1 $NEON_LIBS"
$5
fi])
@ -333,23 +366,18 @@ fi])
dnl Check for presence and suitability of zlib library
AC_DEFUN([NEON_ZLIB], [
AC_ARG_WITH(zlib, AC_HELP_STRING([--without-zlib], [disable zlib support]),
AC_ARG_WITH(zlib, AS_HELP_STRING([--without-zlib], [disable zlib support]),
ne_use_zlib=$withval, ne_use_zlib=yes)
NEON_SUPPORTS_ZLIB=no
AC_SUBST(NEON_SUPPORTS_ZLIB)
if test "$ne_use_zlib" = "yes"; then
AC_CHECK_HEADER(zlib.h, [
AC_CHECK_LIB(z, inflate, [
NEON_LIBS="$NEON_LIBS -lz"
NEON_CFLAGS="$NEON_CFLAGS -DNEON_ZLIB"
NEON_SUPPORTS_ZLIB=yes
neon_zlib_message="found in -lz"
], [neon_zlib_message="zlib not found"])
], [neon_zlib_message="zlib not found"])
NE_ENABLE_SUPPORT(ZLIB, [zlib support enabled, using -lz])
], [NE_DISABLE_SUPPORT(ZLIB, [zlib library not found])])
], [NE_DISABLE_SUPPORT(ZLIB, [zlib header not found])])
else
neon_zlib_message="zlib disabled"
NE_DISABLE_SUPPORT(ZLIB, [zlib not enabled])
fi
])
@ -372,8 +400,6 @@ AC_DEFUN([NEON_COMMON_CHECKS], [
# is used.
AC_REQUIRE([AC_PROG_CC])
AC_REQUIRE([AC_PROG_CC_STDC])
AC_REQUIRE([AC_LANG_C])
AC_REQUIRE([AC_ISC_POSIX])
AC_REQUIRE([AC_C_INLINE])
AC_REQUIRE([AC_C_CONST])
@ -403,8 +429,8 @@ if test "$GCC" = "yes"; then
# See whether a simple test program will compile without errors.
ne_save_CPPFLAGS=$CPPFLAGS
CPPFLAGS="$CPPFLAGS -Wformat -Werror"
AC_TRY_COMPILE([#include <sys/types.h>
#include <stdio.h>], [int i = 42; printf("%d", i);],
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
#include <stdio.h>]], [[int i = 42; printf("%d", i);]])],
[ne_cv_cc_werror=yes], [ne_cv_cc_werror=no])
CPPFLAGS=$ne_save_CPPFLAGS])
ne_fmt_trycompile=$ne_cv_cc_werror
@ -413,6 +439,39 @@ else
fi
])
dnl Check for LFS support
AC_DEFUN([NE_LARGEFILE], [
dnl Need the size of off_t
AC_REQUIRE([NEON_COMMON_CHECKS])
if test -z "$ac_cv_sizeof_off_t"; then
NE_DISABLE_SUPPORT(LFS, [LFS support omitted: off_t size unknown!])
elif test $ac_cv_sizeof_off_t != 4; then
NE_DISABLE_SUPPORT(LFS, [LFS support unnecessary, off_t is not 32-bit])
AC_CHECK_FUNCS([strtoll strtoq], [break])
elif test -z "$ac_cv_sizeof_long_long"; then
NE_DISABLE_SUPPORT(LFS, [LFS support omitted: long long size unknown])
elif test $ac_cv_sizeof_long_long != 8; then
NE_DISABLE_SUPPORT(LFS, [LFS support omitted: long long not 64-bit])
else
ne_save_CPPFLAGS=$CPPFLAGS
CPPFLAGS="$CPPFLAGS -D_LARGEFILE64_SOURCE"
AC_CHECK_TYPE(off64_t, [
NEON_FORMAT(off64_t)
ne_lfsok=no
AC_CHECK_FUNCS([strtoll strtoq], [ne_lfsok=yes; break])
AC_CHECK_FUNCS([lseek64 fstat64], [], [ne_lfsok=no; break])
if test x$ne_lfsok = xyes; then
NE_ENABLE_SUPPORT(LFS, [LFS (large file) support enabled])
NEON_CFLAGS="$NEON_CFLAGS -D_LARGEFILE64_SOURCE -DNE_LFS"
ne_save_CPPFLAGS="$CPPFLAGS -DNE_LFS"
else
NE_DISABLE_SUPPORT(LFS,
[LFS support omitted: 64-bit support functions not found])
fi], [NE_DISABLE_SUPPORT(LFS, [LFS support omitted: off64_t type not found])])
CPPFLAGS=$ne_save_CPPFLAGS
fi])
dnl NEON_FORMAT(TYPE[, HEADERS[, [SPECIFIER]])
dnl
dnl This macro finds out which modifier is needed to create a
@ -436,11 +495,11 @@ if test $ne_fmt_trycompile = yes; then
oflags="$CPPFLAGS"
# Consider format string mismatches as errors
CPPFLAGS="$CPPFLAGS -Wformat -Werror"
dnl obscured for m4 quoting: "for str in d ld qd; do"
for str in ne_spec l]ne_spec[ q]ne_spec[; do
AC_TRY_COMPILE([#include <sys/types.h>
dnl obscured for m4 quoting: "for str in d ld lld; do"
for str in ne_spec l]ne_spec[ ll]ne_spec[; do
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
$2
#include <stdio.h>], [$1 i = 1; printf("%$str", i);],
#include <stdio.h>]], [[$1 i = 1; printf("%$str", i);]])],
[ne_cv_fmt_$1=$str; break])
done
CPPFLAGS=$oflags
@ -481,47 +540,74 @@ AC_REQUIRE([AC_C_BIGENDIAN])
dnl Is strerror_r present; if so, which variant
AC_REQUIRE([AC_FUNC_STRERROR_R])
AC_CHECK_HEADERS([strings.h sys/time.h limits.h sys/select.h arpa/inet.h \
signal.h sys/socket.h netinet/in.h netinet/tcp.h netdb.h])
AC_CHECK_HEADERS([sys/time.h limits.h sys/select.h arpa/inet.h \
signal.h sys/socket.h netinet/in.h netinet/tcp.h netdb.h sys/poll.h],,,
[AC_INCLUDES_DEFAULT
/* netinet/tcp.h requires netinet/in.h on some platforms. */
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif])
AC_REQUIRE([NE_SNPRINTF])
dnl Check for large file support
NE_LARGEFILE
AC_REPLACE_FUNCS(strcasecmp)
AC_CHECK_FUNCS(signal setvbuf setsockopt stpcpy)
AC_CHECK_FUNCS(signal setvbuf setsockopt stpcpy poll)
if test "x${ac_cv_func_poll}${ac_cv_header_sys_poll_h}y" = "xyesyesy"; then
AC_DEFINE([NE_USE_POLL], 1, [Define if poll() should be used])
fi
if test "$ac_cv_func_stpcpy" = "yes"; then
AC_CHECK_DECLS(stpcpy)
fi
# Modern AIXes with the "Linux-like" libc have an undeclared stpcpy
AH_BOTTOM([#if defined(HAVE_STPCPY) && !HAVE_DECL_STPCPY && !defined(stpcpy)
AH_BOTTOM([#if defined(HAVE_STPCPY) && defined(HAVE_DECL_STPCPY) && !HAVE_DECL_STPCPY && !defined(stpcpy)
char *stpcpy(char *, const char *);
#endif])
# Enable getaddrinfo support if it, gai_strerror and inet_ntop are
# all available. Solaris etc hide things in -lsocket, use that too.
# Unixware 7 can only link gethostbyname with -lnsl -lsocket
# Pick up -lsocket first, then the gethostbyname check will work.
# QNX has gethostbyname in -lsocket. BeOS only has it in -lbind.
NE_SEARCH_LIBS(socket, socket inet)
# CygWin/Winsock2 has it in -lws2_32, allegedly.
NE_SEARCH_LIBS(socket, socket inet ws2_32)
NE_SEARCH_LIBS(gethostbyname, socket nsl bind)
# Enable getaddrinfo() support only if all the necessary functions
# are found.
ne_enable_gai=yes
NE_CHECK_FUNCS(getaddrinfo gai_strerror inet_ntop,,[ne_enable_gai=no; break])
NE_SEARCH_LIBS(getaddrinfo, nsl,,
[ne_enable_gai=no],
[# HP-UX boxes commonly get into a state where getaddrinfo is present
# but borked: http://marc.theaimsgroup.com/?l=apr-dev&m=107730955207120&w=2
case x`uname -sr 2>/dev/null`y in
xHP-UX*11.[[01]]*y)
AC_MSG_NOTICE([getaddrinfo support disabled on HP-UX 11.0x/11.1x]) ;;
*)
ne_enable_gai=yes
NE_CHECK_FUNCS(gai_strerror inet_ntop,,[ne_enable_gai=no; break]) ;;
esac
])
if test $ne_enable_gai = yes; then
NE_ENABLE_SUPPORT(IPV6, [IPv6 support is enabled])
AC_DEFINE(USE_GETADDRINFO, 1, [Define if getaddrinfo() should be used])
AC_CACHE_CHECK([for working AI_ADDRCONFIG], [ne_cv_gai_addrconfig], [
AC_RUN_IFELSE([AC_LANG_PROGRAM([#include <netdb.h>],
[struct addrinfo hints = {0}, *result;
hints.ai_flags = AI_ADDRCONFIG;
if (getaddrinfo("localhost", NULL, &hints, &result) != 0) return 1;])],
ne_cv_gai_addrconfig=yes, ne_cv_gai_addrconfig=no)])
ne_cv_gai_addrconfig=yes, ne_cv_gai_addrconfig=no, ne_cv_gai_addrconfig=no)])
if test $ne_cv_gai_addrconfig = yes; then
AC_DEFINE(USE_GAI_ADDRCONFIG, 1, [Define if getaddrinfo supports AI_ADDRCONFIG])
fi
else
# Checks for non-getaddrinfo() based resolver interfaces.
NE_SEARCH_LIBS(gethostbyname, nsl bind)
NE_SEARCH_LIBS(hstrerror, resolv,,[:])
NE_CHECK_FUNCS(hstrerror)
# Older Unixes don't declare h_errno.
@ -529,16 +615,16 @@ else
#include <netdb.h>])
fi
AC_CHECK_MEMBERS(struct tm.tm_gmtoff,,
AC_MSG_WARN([no timezone handling in date parsing on this platform]),
[#include <time.h>])
AC_CHECK_MEMBERS([struct tm.tm_gmtoff, struct tm.__tm_gmtoff],,,
[#include <time.h>])
ifdef([neon_no_zlib], [
neon_zlib_message="zlib disabled"
NEON_SUPPORTS_ZLIB=no
], [
NEON_ZLIB()
])
if test $ac_cv_member_struct_tm_tm_gmtoff$ac_cv_member_struct_tm___tm_gmtoff = nono; then
AC_MSG_WARN([no timezone handling in date parsing on this platform])
fi
ifdef([neon_no_zlib],
[NE_DISABLE_SUPPORT(ZLIB, [zlib not supported])],
[NEON_ZLIB()])
# Conditionally enable ACL support
AC_MSG_CHECKING([whether to enable ACL support in neon])
@ -551,6 +637,7 @@ fi
NEON_SSL()
NEON_SOCKS()
NEON_LIBIDN()
NEON_GSSAPI()
AC_SUBST(NEON_CFLAGS)
@ -601,27 +688,17 @@ ne="$NEON_EXTRAOBJS"
NEON_EXTRAOBJS=
for o in $ne; do
NEON_EXTRAOBJS="$NEON_EXTRAOBJS $o.$NEON_OBJEXT"
done
done
AC_MSG_CHECKING(whether to enable WebDAV support in neon)
dnl Did they want DAV support?
# Was DAV support explicitly turned off?
if test "x$neon_no_webdav" = "xyes"; then
# No WebDAV support
AC_MSG_RESULT(no)
NEONOBJS="$NEONOBJS \$(NEON_BASEOBJS)"
NEON_CFLAGS="$NEON_CFLAGS -DNEON_NODAV"
NEON_SUPPORTS_DAV=no
AC_DEFINE(NEON_NODAV, 1, [Enable if built without WebDAV support])
NE_DISABLE_SUPPORT(DAV, [WebDAV support is not enabled])
else
# WebDAV support
NEON_SUPPORTS_DAV=yes
NEONOBJS="$NEONOBJS \$(NEON_DAVOBJS)"
# Turn on DAV locking please then.
AC_DEFINE(USE_DAV_LOCKS, 1, [Support WebDAV locking through the library])
AC_MSG_RESULT(yes)
NE_ENABLE_SUPPORT(DAV, [WebDAV support is enabled])
fi
AC_SUBST(NEON_TARGET)
@ -629,7 +706,6 @@ AC_SUBST(NEON_OBJEXT)
AC_SUBST(NEONOBJS)
AC_SUBST(NEON_EXTRAOBJS)
AC_SUBST(NEON_LINK_FLAGS)
AC_SUBST(NEON_SUPPORTS_DAV)
])
@ -677,16 +753,16 @@ AC_CHECK_FUNCS(snprintf vsnprintf,,[
AC_MSG_ERROR([trio installation problem? libtrio found but not trio.h]))
AC_MSG_NOTICE(using trio printf replacement library)
NEON_LIBS="$NEON_LIBS -ltrio -lm"
NEON_CFLAGS="$NEON_CFLAGS -DNEON_TRIO"],
AC_DEFINE(HAVE_TRIO, 1, [Use trio printf replacement library])],
[AC_MSG_NOTICE([no vsnprintf/snprintf detected in C library])
AC_MSG_ERROR([Install the trio library from http://daniel.haxx.se/trio/])])
LIBS=$ne_save_LIBS
break
])])
dnl Usage: NE_CHECK_SSLVER(variable, version-string, version-hex)
dnl Usage: NE_CHECK_OPENSSLVER(variable, version-string, version-hex)
dnl Define 'variable' to 'yes' if OpenSSL version is >= version-hex
AC_DEFUN([NE_CHECK_SSLVER], [
AC_DEFUN([NE_CHECK_OPENSSLVER], [
AC_CACHE_CHECK([OpenSSL version is >= $2], $1, [
AC_EGREP_CPP(good, [#include <openssl/opensslv.h>
#if OPENSSL_VERSION_NUMBER >= $3
@ -719,17 +795,22 @@ else
fi
fi])
dnl Check for OpenSSL
dnl Check for an SSL library (GNU TLS or OpenSSL)
AC_DEFUN([NEON_SSL], [
AC_ARG_WITH(ssl, [AC_HELP_STRING([--with-ssl], [enable OpenSSL support])])
AC_ARG_WITH(ssl,
AS_HELP_STRING([--with-ssl=openssl|gnutls],
[enable SSL support (default OpenSSL)]))
AC_ARG_WITH(egd,
[[ --with-egd[=PATH] enable EGD support [using EGD socket at PATH]]])
case $with_ssl in
yes)
/*)
AC_MSG_NOTICE([to use SSL libraries in non-standard locations, try --with-ssl --with-libs=$with_ssl])
AC_MSG_ERROR([--with-ssl does not take a path argument])
;;
yes|openssl)
NE_PKG_CONFIG(NE_SSL, openssl,
[AC_MSG_NOTICE(using SSL library configuration from pkg-config)
CPPFLAGS="$CPPFLAGS ${NE_SSL_CFLAGS}"
@ -742,17 +823,17 @@ yes)
[AC_MSG_ERROR([OpenSSL headers not found, cannot enable SSL support])])
# Enable EGD support if using 0.9.7 or newer
NE_CHECK_SSLVER(ne_cv_lib_ssl097, 0.9.7, 0x00907000L)
NE_CHECK_OPENSSLVER(ne_cv_lib_ssl097, 0.9.7, 0x00907000L)
if test "$ne_cv_lib_ssl097" = "yes"; then
AC_MSG_NOTICE([OpenSSL >= 0.9.7; EGD support not needed in neon])
neon_ssl_message="OpenSSL (0.9.7 or later)"
NE_ENABLE_SUPPORT(SSL, [SSL support enabled, using OpenSSL (0.9.7 or later)])
else
# Fail if OpenSSL is older than 0.9.6
NE_CHECK_SSLVER(ne_cv_lib_ssl096, 0.9.6, 0x00906000L)
NE_CHECK_OPENSSLVER(ne_cv_lib_ssl096, 0.9.6, 0x00906000L)
if test "$ne_cv_lib_ssl096" != "yes"; then
AC_MSG_ERROR([OpenSSL 0.9.6 or later is required])
fi
neon_ssl_message="OpenSSL (0.9.6 or later)"
NE_ENABLE_SUPPORT(SSL, [SSL support enabled, using OpenSSL (0.9.6 or later)])
case "$with_egd" in
yes|no) ne_cv_lib_sslegd=$with_egd ;;
@ -774,22 +855,63 @@ yes)
fi
fi
NEON_SUPPORTS_SSL=yes
NEON_CFLAGS="$NEON_CFLAGS -DNEON_SSL"
AC_DEFINE([HAVE_OPENSSL], 1, [Define if OpenSSL support is enabled])
NEON_EXTRAOBJS="$NEON_EXTRAOBJS ne_openssl"
;;
gnutls)
AC_PATH_PROG(GNUTLS_CONFIG, libgnutls-config, no)
if test "$GNUTLS_CONFIG" = "no"; then
AC_MSG_ERROR([could not find libgnutls-config in \$PATH])
fi
ne_gnutls_ver=`$GNUTLS_CONFIG --version`
case $ne_gnutls_ver in
1.*) ;;
*) AC_MSG_ERROR([GNU TLS major version "$ne_gnutls_ver" not supported]) ;;
esac
CPPFLAGS="$CPPFLAGS `$GNUTLS_CONFIG --cflags`"
AC_CHECK_HEADER([gnutls/gnutls.h],,
[AC_MSG_ERROR([could not find gnutls/gnutls.h in include path])])
NE_ENABLE_SUPPORT(SSL, [SSL support enabled, using GnuTLS $ne_gnutls_ver])
NEON_EXTRAOBJS="$NEON_EXTRAOBJS ne_gnutls"
NEON_LIBS="$NEON_LIBS `$GNUTLS_CONFIG --libs`"
AC_DEFINE([HAVE_GNUTLS], 1, [Define if GnuTLS support is enabled])
;;
*) # Default to off; only create crypto-enabled binaries if requested.
neon_ssl_message="No SSL support"
NEON_SUPPORTS_SSL=no
NE_DISABLE_SUPPORT(SSL, [SSL support is not enabled])
NEON_EXTRAOBJS="$NEON_EXTRAOBJS ne_stubssl"
;;
esac
AC_SUBST(NEON_SUPPORTS_SSL)
])
dnl Check for GNU libidn
AC_DEFUN([NEON_LIBIDN], [
AC_ARG_WITH(libidn, AS_HELP_STRING(--without-libidn, disable IDNA support))
if test "$with_libidn" != "no"; then
ne_use_idna=no
AC_CHECK_HEADER(idna.h,
[NE_SEARCH_LIBS(idna_to_ascii_8z,idn,,,[ne_use_idna=yes])])
if test $ne_use_idna = yes; then
NE_ENABLE_SUPPORT(IDNA, [IDNA support enabled using GNU libidn])
else
NE_DISABLE_SUPPORT(IDNA,
[IDNA support not enabled; GNU libidn >=0.2.0 required])
fi
fi])
dnl Check for Kerberos installation
AC_DEFUN([NEON_GSSAPI], [
AC_PATH_PROG([KRB5_CONFIG], krb5-config, none, $PATH:/usr/kerberos/bin)
AC_ARG_WITH(gssapi, AS_HELP_STRING(--without-gssapi, disable GSSAPI support))
if test "$with_gssapi" != "no"; then
AC_PATH_PROG([KRB5_CONFIG], krb5-config, none, $PATH:/usr/kerberos/bin)
else
KRB5_CONFIG=none
fi
if test "x$KRB5_CONFIG" != "xnone"; then
ne_save_CPPFLAGS=$CPPFLAGS
ne_save_LIBS=$NEON_LIBS
@ -803,7 +925,7 @@ if test "x$KRB5_CONFIG" != "xnone"; then
AC_MSG_NOTICE([GSSAPI authentication support enabled])
AC_DEFINE(HAVE_GSSAPI, 1, [Define if GSSAPI support is enabled])
AC_CHECK_HEADERS(gssapi/gssapi_generic.h)
# MIT Kerberos lacks GSS_C_NT_HOSTBASED_SERVICE
# Older versions of MIT Kerberos lack GSS_C_NT_HOSTBASED_SERVICE
AC_CHECK_DECL([GSS_C_NT_HOSTBASED_SERVICE],,
[AC_DEFINE([GSS_C_NT_HOSTBASED_SERVICE], gss_nt_service_name,
[Define if GSS_C_NT_HOSTBASED_SERVICE is not defined otherwise])],
@ -825,12 +947,12 @@ AC_DEFUN([NEON_WARNINGS],[
AC_REQUIRE([AC_PROG_CC]) dnl so that $GCC is set
AC_ARG_ENABLE(warnings,
AC_HELP_STRING(--enable-warnings, [enable compiler warnings]))
AS_HELP_STRING(--enable-warnings, [enable compiler warnings]))
if test "$enable_warnings" = "yes"; then
case $GCC:`uname` in
yes:*)
CFLAGS="$CFLAGS -Wall -ansi-pedantic -Wmissing-declarations -Winline -Wshadow -Wreturn-type -Wsign-compare -Wundef -Wpointer-arith -Wcast-align -Wbad-function-cast -Wimplicit-prototypes -Wformat-security"
CFLAGS="$CFLAGS -Wall -Wmissing-declarations -Wshadow -Wreturn-type -Wsign-compare -Wundef -Wpointer-arith -Wcast-align -Wbad-function-cast -Wformat-security"
if test -z "$with_ssl" -o "$with_ssl" = "no"; then
# OpenSSL headers fail strict prototypes checks
CFLAGS="$CFLAGS -Wstrict-prototypes"
@ -852,7 +974,7 @@ dnl
AC_DEFUN([NEON_DEBUG], [
AC_ARG_ENABLE(debug,
AC_HELP_STRING(--disable-debug,[disable runtime debugging messages]))
AS_HELP_STRING(--disable-debug,[disable runtime debugging messages]))
# default is to enable debugging
case $enable_debug in
@ -867,21 +989,21 @@ esac])
dnl Macro to optionally enable socks support
AC_DEFUN([NEON_SOCKS], [
AC_ARG_WITH([socks], AC_HELP_STRING([--with-socks],[use SOCKSv5 library]))
AC_ARG_WITH([socks], AS_HELP_STRING([--with-socks],[use SOCKSv5 library]))
if test "$with_socks" = "yes"; then
ne_save_LIBS=$LIBS
AC_CHECK_HEADERS(socks.h,
[AC_CHECK_LIB(socks5, connect,
[AC_MSG_NOTICE([SOCKSv5 support enabled])],
[AC_CHECK_LIB(socks5, connect, [:],
[AC_MSG_ERROR([could not find libsocks5 for SOCKS support])])],
[AC_MSG_ERROR([could not find socks.h for SOCKS support])])
CFLAGS="$CFLAGS -DNEON_SOCKS"
NE_ENABLE_SUPPORT(SOCKS, [SOCKSv5 support is enabled])
NEON_LIBS="$NEON_LIBS -lsocks5"
LIBS=$ne_save_LIBS
else
NE_DISABLE_SUPPORT(SOCKS, [SOCKSv5 support is not enabled])
fi])
AC_DEFUN([NEON_WITH_LIBS], [

View File

@ -1,6 +1,6 @@
#! /bin/sh
# Originally from libxml, Copyright (C) Daniel Veillard
# Modifications for neon Copyright (C) 2000-2002 Joe Orton.
# Modifications for neon Copyright (C) 2000-2004 Joe Orton.
prefix=@prefix@
exec_prefix=@exec_prefix@
@ -21,7 +21,7 @@ Known values for OPTION are:
--help display this help and exit
--version output version information
--support FEATURE exit with success if feature is supported
Known features: dav [@NEON_SUPPORTS_DAV@], ssl [@NEON_SUPPORTS_SSL@], zlib [@NEON_SUPPORTS_ZLIB@]
Known features: dav [@NE_FLAG_DAV@], ssl [@NE_FLAG_SSL@], zlib [@NE_FLAG_ZLIB@], idna [@NE_FLAG_IDNA@], ipv6 [@NE_FLAG_IPV6@], lfs [@NE_FLAG_LFS@]
EOF
@ -87,16 +87,18 @@ while test $# -gt 0; do
shift
case "$1" in
ssl|SSL) support @NEON_SUPPORTS_SSL@ ;;
zlib|ZLIB) support @NEON_SUPPORTS_ZLIB@ ;;
dav|DAV) support @NEON_SUPPORTS_DAV@ ;;
ssl|SSL) support @NE_FLAG_SSL@ ;;
zlib|ZLIB) support @NE_FLAG_ZLIB@ ;;
ipv6|IPV6) support @NE_FLAG_IPV6@ ;;
dav|DAV) support @NE_FLAG_DAV@ ;;
idna|IDNA) support @NE_FLAG_IDNA@ ;;
lfs|LFS) support @NE_FLAG_LFS@ ;;
*) support no ;;
esac
;;
*)
usage
exit 1
usage 1 1>&2
;;
esac
shift

View File

@ -63,6 +63,11 @@ ZLIB_LIBS = "$(ZLIB_SRC)\zlibdll.lib"
!ENDIF
!ENDIF
########
# Support for IPv6
!IF "$(ENABLE_IPV6)" == "yes"
IPV6_FLAGS = /D USE_GETADDRINFO
!ENDIF
!IF "$(DEBUG_BUILD)" == ""
INTDIR = Release
@ -78,7 +83,7 @@ TARGET = .\libneonD.lib
WIN32_DEFS = /D WIN32_LEAN_AND_MEAN /D NOUSER /D NOGDI /D NONLS /D NOCRYPT
CPP=cl.exe
CPP_PROJ = /c /nologo $(CFLAGS) $(WIN32_DEFS) $(EXPAT_FLAGS) $(OPENSSL_FLAGS) $(ZLIB_FLAGS) /D "HAVE_CONFIG_H" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\"
CPP_PROJ = /c /nologo $(CFLAGS) $(WIN32_DEFS) $(EXPAT_FLAGS) $(OPENSSL_FLAGS) $(ZLIB_FLAGS) $(IPV6_FLAGS) /D "HAVE_CONFIG_H" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\"
LIB32=link.exe -lib
LIB32_FLAGS=/nologo /out:"$(TARGET)"

View File

@ -1,3 +1,94 @@
Sun Sep 12 19:21:30 2004 Joe Orton <joe@manyfish.co.uk>
* ne_locks.c (ne_lock_refresh): Fix to pass correct userdata to
callbacks, and do call lk_cdata.
Sun Sep 12 18:53:15 2004 Joe Orton <joe@manyfish.co.uk>
* Makefile.in (libneon.a): Remove the archive first, avoiding
strange problems when build $(OBJECTS) change.
Sun Sep 12 18:40:50 2004 Joe Orton <joe@manyfish.co.uk>
* ne_utils.h: Add NE_FEATURE_SOCKS.
* ne_utils.c (ne_has_support): Add NE_FEATURE_SOCKS.
(version_string): Use NE_HAVE_SOCKS, add NE_HAVE_IDNA.
* ne_socket.c (ne_sock_init): Use NE_HAVE_SOCKS.
Sun Sep 12 17:29:54 2004 Joe Orton <joe@manyfish.co.uk>
* ne_utils.c (version_string): Declare as array rather than
pointer; include "IPv6" component as necessary
Sun Sep 12 15:51:38 2004 Joe Orton <joe@manyfish.co.uk>
* ne_socket.c (ne_iaddr_typeof): New function.
Sun Sep 12 12:00:10 2004 Joe Orton <joe@manyfish.co.uk>
* ne_defs.h (ne_attribute_malloc): New macro.
* ne_alloc.h: Use it to avoid warnings with older GCCs.
Wed Aug 25 21:03:40 2004 Joe Orton <joe@manyfish.co.uk>
* ne_string.h (split_string, split_string_c, pair_string,
split_string_free, pair_string_free): Remove obsolete interfaces.
Wed Aug 25 21:01:03 2004 Joe Orton <joe@manyfish.co.uk>
* ne_cookies.c, ne_cookies.h: Drop cookies support: used old spec
revision and wasn't very complete anyway.
Wed Aug 25 20:40:26 2004 Joe Orton <joe@manyfish.co.uk>
* ne_socket.c: Remove ne_read, ne_write macros and just use recv
and send; remove unused SOCK_ERR macro.
Wed Aug 25 20:27:43 2004 Joe Orton <joe@manyfish.co.uk>
* ne_xml.c (declare_nspaces): Drop rejection of names including a
colon to prevent breaking SVN deployments.
Wed Aug 25 19:45:20 2004 Joe Orton <joe@manyfish.co.uk>
* ne_socket.c (readable_raw): Use poll where available.
(ne_sock_connect): Fail if not using poll and fd returned by
socket() is greater than FD_SETSIZE.
Wed Aug 25 18:40:28 2004 Joe Orton <joe@manyfish.co.uk>
* ne_xml.h (ne_xml_parse): Clarify that a len=0 call is required
to signify end-of-document.
Wed Aug 25 18:37:13 2004 Joe Orton <joe@manyfish.co.uk>
* ne_request.c (resolve_first, resolve_next): New functions.
(lookup_host): Use them to allow user-forced addresses.
* ne_session.c (ne_set_addrlist): New function.
* ne_private.h (struct ne_session_s): Add addrlist, numaddrs,
curaddr fields.
Wed Aug 25 18:25:31 2004 Joe Orton <joe@manyfish.co.uk>
* ne_xml.c (struct ne_xml_parser_s): Add bom_pos field.
(ne_xml_parse): Skip over the UTF-8 Byte Order Mark since
the XML parsers do not support it yet.
Wed Jul 7 16:07:44 2004 Joe Orton <joe@manyfish.co.uk>
* ne_request.c (do_connect): Fix ne_conn_connected status call
(Shameek Basu).
Mon Jul 5 18:40:35 2004 Joe Orton <joe@manyfish.co.uk>
* ne_basic.c (ne_content_type_handler): Use us-ascii as default
charset for text/xml, as per RFC3280.
Mon Jul 5 10:56:19 2004 Joe Orton <joe@manyfish.co.uk>
* ne_compress.c (struct ne_decompress_s): Add acceptor field.
@ -12,20 +103,16 @@ Mon Jul 5 10:52:40 2004 Joe Orton <joe@manyfish.co.uk>
(process_footer): Call the reader callback with size=0 to indicate
end-of-response for a good checksum match.
Mon Jul 5 10:42:14 2004 Joe Orton <joe@manyfish.co.uk>
* ne_compress.c (gz_destroy, gz_pre_send): New functions.
(ne_decompress_reader): Register pre-send and destroy hooks,
to initialize the compression context before each request attempt.
(Justin Erenkrantz).
* ne_private.h, ne_request.c (ne_kill_pre_send): New function.
Sat Jul 3 14:33:56 2004 Joe Orton <joe@manyfish.co.uk>
* ne_auth.c (auth_challenge): Fix to set got_qop in challenge
correctly (Hideaki Takahashi).
Mon May 17 15:03:54 2004 Joe Orton <joe@manyfish.co.uk>
* ne_socket.h (ne_addr_resolve): Clarify that 'flags' must
be passed as zero for forwards-compat.
Sun May 2 21:14:14 2004 Joe Orton <joe@manyfish.co.uk>
Fix buffer overflow in RFC1036 date parser, CVE CAN-2004-0389.
@ -35,17 +122,19 @@ Sun May 2 21:14:14 2004 Joe Orton <joe@manyfish.co.uk>
(ne_rfc1123_parse, ne_rfc1036_parse, ne_asctime_parse): Make
thread-safe; remove static buffers.
Thu Mar 11 23:38:01 2004 Joe Orton <joe@manyfish.co.uk>
* ne_openssl.c (provide_client_cert): Avoid malloc(0) when server
sends no CA names in CertificateRequest.
(ne_ssl_cert_write): Be paranoid and clear the OpenSSL error stack
on write failures.
Sun May 2 16:59:39 2004 Joe Orton <joe@manyfish.co.uk>
* ne_dates.c [RFC1123_TEST] (main): Remove embedded test cases.
Sun May 2 13:18:29 2004 Joe Orton <joe@manyfish.co.uk>
* Makefile.in (LINK): Add -no-undefined.
Fri Apr 16 22:53:59 2004 Joe Orton <joe@manyfish.co.uk>
* ne_xml.c (declare_nspaces, expand_qname): Don't try to include
document context in error strings.
Fri Apr 16 11:44:34 2004 Joe Orton <joe@manyfish.co.uk>
* Makefile.in (LIBS): Include NEON_LTLIBS.
@ -77,11 +166,83 @@ Thu Apr 8 13:40:03 2004 Joe Orton <joe@manyfish.co.uk>
* ne_props.h: Don't use an anonymous enum for the proppatch
operation type, as some C++ compilers don't like it.
Wed Apr 7 13:50:10 2004 Joe Orton <joe@manyfish.co.uk>
* ne_request.c (add_fixed_headers): Don't both sending Keep-Alive
header if persistent connections are disabled.
Wed Apr 7 13:47:46 2004 Joe Orton <joe@manyfish.co.uk>
* ne_auth.c (auth_challenge): Allow Negotiate challenges from
a proxy.
Wed Apr 7 13:36:55 2004 Joe Orton <joe@manyfish.co.uk>
* ne_auth.c (clean_session): Remove redundant assignment of
GSS_C_NO_CONTEXT; gss_delete_sec_context already does this.
Wed Apr 7 13:33:10 2004 Joe Orton <joe@manyfish.co.uk>
* ne_auth.c (get_gss_name): Handle failure case internally.
(auth_register): Updated accordingly.
Wed Apr 7 13:15:57 2004 Joe Orton <joe@manyfish.co.uk>
* ne_request.c: Use strtoq to print off_t's where necessary.
Wed Apr 7 11:14:24 2004 Joe Orton <joe@manyfish.co.uk>
* ne_auth.c (get_gss_name): Take a hostname string.
(auth_register): Pass proxy or server hostname to get_gss_name as
appropriate.
Wed Apr 7 11:09:50 2004 Joe Orton <joe@manyfish.co.uk>
* ne_auth.c (continue_negotiate): If given no input token, and the
gssctx is not in the initial state, reset it.
Mon Mar 29 17:06:49 2004 Joe Orton <joe@manyfish.co.uk>
* ne_auth.c: Adjust to cope with GSSAPI continuation:
(struct auth_session_s): Store GSSAPI context, name and mechanism.
(get_gss_name): Take an ne_session.
(continue_negotiate): Renamed from gssapi_challenge; take input
token, handle GSS_S_CONTINUE_NEEDED return value.
(verify_digest_response): Renamed from verify_response.
(verify_negotiate_response): New function.
(auth_challenge): Cope with Negotiate responses which gratuitously
break the auth-param grammar.
(ah_post_send): Handle Negotiate responses.
(free_auth, clean_session): Free persisted GSSAPI objects.
(auth_register): Initialize GSSAPI objects.
Sun Mar 28 03:03:17 2004 Joe Orton <joe@manyfish.co.uk>
* ne_auth.c (get_gss_name): Don't leak token.value.
Sun Mar 28 02:59:58 2004 Joe Orton <joe@manyfish.co.uk>
* ne_auth.c (get_cnonce): Only use RAND_pseudo_bytes() if the PRNG
is seeded.
Sun Mar 28 02:47:20 2004 Joe Orton <joe@manyfish.co.uk>
* ne_auth.c (gssapi_challenge, get_gss_name): Simplify.
Sun Mar 28 02:35:48 2004 Joe Orton <joe@manyfish.co.uk>
* ne_auth.c (request_gssapi, get_gss_name, auth_challenge):
Implement the Negotiate protocol rather than the obsoleted
GSS-Negotiate.
(make_gss_error): New function.
(gssapi_challenge): Use it for better error handling (set session
error string); fix memory leaks. Don't delegate credentials.
Sat Mar 27 20:49:24 2004 Joe Orton <joe@manyfish.co.uk>
* ne_auth.c (ah_post_send): Clear auth header collector buffers
after each request.
Fri Mar 26 12:16:15 2004 Joe Orton <joe@manyfish.co.uk>
* ne_socket.c (init_ssl): Just initialize the SSL library; delay
@ -95,12 +256,72 @@ Fri Mar 26 12:01:38 2004 Joe Orton <joe@manyfish.co.uk>
* ne_utils.c: Include zlib.h before ne_*.h to fix issues
on platforms where zconf.h does "#define const".
Fri Mar 26 11:55:06 2004 Joe Orton <joe@manyfish.co.uk>
Thu Mar 11 23:38:01 2004 Joe Orton <joe@manyfish.co.uk>
* ne_auth.c (get_gss_name, request_gssapi, gssapi_challenge,
auth_challenge): Implement the Negotiate auth scheme rather than
the obsolete GSS-Negotiate, and fix memory leaks. Only accept
Negotiate challenges over SSL.
* ne_openssl.c (provide_client_cert): Avoid malloc(0) when server
sends no CA names in CertificateRequest.
(ne_ssl_cert_write): Be paranoid and clear the OpenSSL error stack
on write failures.
Sun Mar 7 11:17:04 2004 Joe Orton <joe@manyfish.co.uk>
* Makefile.in (CFLAGS): Don't use NEON_CFLAGS.
Mon Feb 23 23:03:08 2004 Joe Orton <joe@manyfish.co.uk>
* ne_string.c (ne_vsnprintf, ne_snprintf): New functions.
Sun Feb 22 23:34:47 2004 Joe Orton <joe@manyfish.co.uk>
* ne_private.h (struct ne_session_s): Remove expect100_works field.
* ne_request.c (ne_set_request_expect100): New function.
(ne_begin_request): Remove req->use_expect100 manipulation.
(send_request): Handle enabling 100continue without a request
body.
* ne_session.c (ne_set_expect100): Removed function.
Sun Feb 22 20:17:04 2004 Joe Orton <joe@manyfish.co.uk>
* ne_socket.c (error_ossl): Check for ERR_reason_error_string
returning NULL.
Sun Feb 22 17:54:43 2004 Joe Orton <joe@manyfish.co.uk>
* ne_socket.c: Don't disable getaddrinfo support here.
Sun Feb 22 17:40:07 2004 Joe Orton <joe@manyfish.co.uk>
* ne_utils.h (min): Remove definition to...
* ne_uri.c (min): ...here.
Sun Feb 22 17:31:35 2004 Joe Orton <joe@manyfish.co.uk>
* ne_props.h: Give the 'type' enum a tag name.
Sun Feb 22 17:27:28 2004 Joe Orton <joe@manyfish.co.uk>
* ne_207.c (end_element): Strip whitespace from cdata.
Sun Feb 22 16:27:58 2004 Joe Orton <joe@manyfish.co.uk>
* ne_auth.c (struct auth_request): Make auth_hdr, auth_info_hdr
fields into ne_buffer *'s.
(ah_collect_header): New function.
(ah_create): Create ne_buffers for auth_{,info_}hdr; use
ah_collect_header rather than ne_duplicate_header to fix handling
of multiple auth challenge headers.
(ah_post_send): Adjust for char * -> ne_buffer *.
(tokenize): Recognize a challenge scheme which is terminated with
a comma (i.e. with no challange parameters).
(auth_challenge): Fix handling of unrecognized challenges.
(ah_destroy): Destroy ne_buffers.
Sun Feb 22 15:04:46 2004 Joe Orton <joe@manyfish.co.uk>
* ne_request.c (ne_set_request_body_provider64): New function.
Sun Feb 15 13:37:03 2004 Joe Orton <joe@manyfish.co.uk>
@ -110,11 +331,112 @@ Sun Feb 15 13:37:03 2004 Joe Orton <joe@manyfish.co.uk>
* ne_openssl.c (ne_ssl_readable_dname): Convert dname strings to
UTF-8, or use "???".
Sat Feb 14 21:57:25 2004 Joe Orton <joe@manyfish.co.uk>
* ne_xml.c (invalid_ncname_ch1): New macro.
(declare_nspaces): Use it, to reject some more invalid namespace
prefixes; also check for a colon anywhere in the NCName.
(expand_qname): Likewise for the element name.
Mon Feb 9 21:38:03 2004 Joe Orton <joe@manyfish.co.uk>
* ne_dates.c [WIN32] (GMTOFF): Use gmt_to_local_win32;
(gmt_to_local_win32): New function, from Jiang Lei.
Mon Jan 26 14:38:05 2004 Joe Orton <joe@manyfish.co.uk>
* ne_socket.c (ne_sock_connect_ssl): Check that OpenSSL version
matches between library at run-time and headers at compile-time.
Sat Jan 24 17:49:27 2004 Joe Orton <joe@manyfish.co.uk>
* ne_dates.c (HAVE_STRUCT_TM___TM_GMTOFF): Alternative GMTOFF()
macro.
Sat Jan 24 16:49:30 2004 Joe Orton <joe@manyfish.co.uk>
* ne_auth.c (basic_challenge): Cast first parameter to ne_base64
to unsigned char * to fix warnings with some compilers.
Sat Jan 3 13:17:36 2004 Joe Orton <joe@manyfish.co.uk>
* ne_request.h (ne_set_request_body_fd64): Define conditional on
NE_LFS.
* ne_request.c (ne_set_request_body_fd64): Likewise.
Thu Jan 1 18:01:45 2004 Joe Orton <joe@manyfish.co.uk>
* ne_request.c: Use NE_HAVE_LFS not _LARGEFILE64_SOURCE in
conditional support for off64_t.
Thu Jan 1 17:38:55 2004 Joe Orton <joe@manyfish.co.uk>
* ne_request.h [_LARGEFILE64_SOURCE] (ne_set_request_body_fd64):
New function.
* ne_request.c: Define ne_lseek, ne_off_t, ne_strtoff,
NE_OFFT_MAX, FMT_NE_OFF_T appropriately for _LARGEFILE64_SOURCE or
otherwise.
(struct ne_request_s): Use ne_off_t in place of off_t throughout.
(body_fd_send): Use ne_lseek; reset 'remain' after seeking.
(clength_hdr_handler): Use ne_off_t, ne_strtoff and NE_OFFT_MAX.
(set_body_length): Take an ne_off_t length parameter; use
FMT_NE_OFF_T to print it.
(ne_set_request_body_fd64): New function.
* ne_utils.h (NE_FEATURE_LFS): New feature.
* ne_utils.c (ne_has_support): Support NE_FEATURE_LFS.
Mon Nov 24 20:13:14 2003 Joe Orton <joe@manyfish.co.uk>
* ne_request.c (struct ne_response): Split handling for chunked vs
clength-delimited responses into a union. Use off_t for storing
whole-length-of-response values.
(read_response_block, ne_read_response_block): Update accordingly.
(ne_begin_request): Remove unnecessary variable assignments.
Sun Nov 23 16:03:22 2003 Joe Orton <joe@manyfish.co.uk>
* ne_request.h (ne_set_request_body_fd): Take offset and length
arguments, return void.
(ne_set_request_body_provider): Take off_t length argument.
* ne_request.c (struct ne_request_s): Store current position
within buffer/file used as request body source. Store request
body lengths using off_t type.
(body_string_send): Adjust for renamed fields.
(body_fd_send): Seek to requested offset; don't read past
requested body length.
(set_body_length): Renamed from set_body_size.
* ne_basic.c (ne_put): Determine file size here; adjust for new
ne_set_request_body_fd API.
Sun Nov 23 15:05:12 2003 Joe Orton <joe@manyfish.co.uk>
* ne_basic.c, ne_basic.h: Remove two-functions-in-one,
ne_put_if_unmodified.
Fri Nov 14 14:05:32 2003 Joe Orton <joe@manyfish.co.uk>
* ne_utils.c (ne_has_support): Add NE_FEATURE_IDNA.
Fri Nov 14 13:11:49 2003 Joe Orton <joe@manyfish.co.uk>
* ne_session.c (set_hostinfo): [NE_HAVE_LIBIDN]: Use string from
IDNA ToAscii operation on provided hostname if successful.
Fri Nov 14 11:23:16 2003 Joe Orton <joe@manyfish.co.uk>
All files: replace use of NEON_NODAV with NE_HAVE_DAV, NEON_SSL
with NE_HAVE_SSL, NEON_ZLIB with NE_HAVE_ZLIB. Use NE_HAVE_DAV
not USE_DAV_LOCKS.
* ne_utils.c (ne_has_support): New feature detection interface,
replaces ne_supports_ssl.
Thu Nov 13 20:38:28 2003 Joe Orton <joe@manyfish.co.uk>
* ne_request.c (ne_begin_request): Presume a 205 response has no
@ -126,6 +448,42 @@ Thu Nov 13 20:31:07 2003 Joe Orton <joe@manyfish.co.uk>
request as a valid proxy auth challenge, to work around buggy
proxies.
Tue Nov 11 21:13:18 2003 Joe Orton <joe@manyfish.co.uk>
Place library-internal symbols in the "ne__" namespace.
* ne_request.c (ne__pull_request_body): Renamed from
ne_pull_request_body; all callers updated.
* ne_session.c (ne__negotiate_ssl): Renamed from
ne_negotiate_ssl; all callers updated.
Tue Nov 11 21:08:54 2003 Joe Orton <joe@manyfish.co.uk>
* ne_alloc.h: Mark all allocation functions as having 'malloc'
attribute for GCC.
Tue Nov 11 20:36:12 2003 Joe Orton <joe@manyfish.co.uk>
* ne_xml.h (ne_xml_failure): Replaces ne_xml_valid,
inverted and more useful return value.
* ne_xml.c (struct ne_xml_parser_s): Replace 'valid' field with
'failure', with inverted logic.
(start_element, end_element, char_data): Check failure flag
appropriately. Set failure flag to return value of callback.
Set failure flag to positive integer on a parse error.
(ne_xml_create): Don't initialize failure flag.
(ne_xml_parse): Check/set failure flag appropriately.
(sax_error): Only set an error string (and the error flag)
if failure is zero.
* ne_207.c (ne_simple_request): Adjust to use ne_xml_failure.
* ne_locks.c (ne_lock, ne_lock_refresh): Likewise.
* ne_props.c (propfind): Likewise.
Wed Oct 22 22:19:19 2003 Joe Orton <joe@manyfish.co.uk>
* ne_request.c (read_response_block): Treat an EOF without clean

View File

@ -14,7 +14,7 @@ libdir = @libdir@
# Build paths
VPATH = @srcdir@
top_builddir = ..
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
# Toolchain settings.
@ -25,7 +25,7 @@ LIBTOOL = @LIBTOOL@
# Flags
CPPFLAGS = @DEFS@ @CPPFLAGS@
CFLAGS = @CFLAGS@ @NEON_CFLAGS@
CFLAGS = @CFLAGS@
LDFLAGS = @LDFLAGS@
NEON_LINK_FLAGS = @NEON_LINK_FLAGS@
# Note: don't substitute @LIBS@ in here; during a bundled
@ -33,15 +33,14 @@ NEON_LINK_FLAGS = @NEON_LINK_FLAGS@
LIBS = @NEON_LIBS@ @NEON_LTLIBS@
COMPILE = $(CC) $(CPPFLAGS) $(CFLAGS)
LINK = $(LIBTOOL) --quiet --mode=link $(CC) $(LDFLAGS)
LINK = $(LIBTOOL) --quiet --mode=link $(CC) -no-undefined $(LDFLAGS)
NEON_BASEOBJS = ne_request.@NEON_OBJEXT@ ne_session.@NEON_OBJEXT@ \
ne_basic.@NEON_OBJEXT@ ne_string.@NEON_OBJEXT@ \
ne_uri.@NEON_OBJEXT@ ne_dates.@NEON_OBJEXT@ ne_alloc.@NEON_OBJEXT@ \
ne_md5.@NEON_OBJEXT@ ne_utils.@NEON_OBJEXT@ \
ne_socket.@NEON_OBJEXT@ ne_auth.@NEON_OBJEXT@ \
ne_cookies.@NEON_OBJEXT@ ne_redirect.@NEON_OBJEXT@ \
ne_compress.@NEON_OBJEXT@
ne_redirect.@NEON_OBJEXT@ ne_compress.@NEON_OBJEXT@
NEON_DAVOBJS = $(NEON_BASEOBJS) \
ne_207.@NEON_OBJEXT@ ne_xml.@NEON_OBJEXT@ \
@ -70,6 +69,7 @@ libneon.la: $(OBJECTS)
$(LINK) -rpath $(libdir) $(NEON_LINK_FLAGS) -o $@ $(OBJECTS) $(LIBS)
libneon.a: $(OBJECTS)
@rm -f $@
$(AR) cru $@ $(OBJECTS)
$(RANLIB) $@
@ -102,6 +102,9 @@ ne_session.@NEON_OBJEXT@: ne_session.c ne_session.h ne_alloc.h \
ne_openssl.@NEON_OBJEXT@: ne_openssl.c ne_session.h ne_ssl.h ne_privssl.h \
ne_private.h $(top_builddir)/config.h
ne_gnutls.@NEON_OBJEXT@: ne_gnutls.c ne_session.h ne_ssl.h ne_privssl.h \
ne_private.h $(top_builddir)/config.h
ne_socket.@NEON_OBJEXT@: ne_socket.c ne_socket.h $(top_builddir)/config.h \
ne_privssl.h ne_string.h
@ -139,9 +142,8 @@ ne_locks.@NEON_OBJEXT@: ne_locks.c $(neonreq) ne_locks.h ne_207.h ne_xml.h
ne_redirect.@NEON_OBJEXT@: ne_redirect.c $(neonreq) ne_redirect.h \
ne_uri.h ne_private.h
ne_cookies.@NEON_OBJEXT@: ne_cookies.c $(neonreq) ne_cookies.h ne_uri.h \
ne_private.h
ne_compress.@NEON_OBJEXT@: ne_compress.c $(neonreq) ne_compress.h
ne_acl.@NEON_OBJEXT@: ne_acl.c ne_acl.h $(neonreq)
ne_stubssl.@NEON_OBJEXT@: ne_stubssl.c $(neonreq)

View File

@ -142,8 +142,12 @@ static int start_element(void *userdata, int parent,
state != ELM_href)
return NE_XML_DECLINE;
if (state == ELM_propstat && p->start_propstat)
if (state == ELM_propstat && p->start_propstat) {
p->propstat = p->start_propstat(p->userdata, p->response);
if (p->propstat == NULL) {
return NE_XML_ABORT;
}
}
ne_buffer_clear(p->cdata);
@ -158,7 +162,7 @@ static int
end_element(void *userdata, int state, const char *nspace, const char *name)
{
ne_207_parser *p = userdata;
const char *cdata = p->cdata->data;
const char *cdata = ne_shave(p->cdata->data, "\r\n\t ");
switch (state) {
case ELM_responsedescription:
@ -318,7 +322,7 @@ int ne_simple_request(ne_session *sess, ne_request *req)
if (ret == NE_OK) {
if (ne_get_status(req)->code == 207) {
if (!ne_xml_valid(p)) {
if (ne_xml_failed(p)) {
/* The parse was invalid */
ne_set_error(sess, "%s", ne_xml_get_error(p));
ret = NE_ERROR;

View File

@ -1,6 +1,6 @@
/*
WebDAV 207 multi-status response handling
Copyright (C) 1999-2003, Joe Orton <joe@manyfish.co.uk>
Copyright (C) 1999-2004, Joe Orton <joe@manyfish.co.uk>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@ -54,7 +54,9 @@ typedef void ne_207_end_response(void *userdata, void *response,
* the response in which this propstat is contains is passed as the
* 'response' parameter. The return value of each 'start_propstat' is
* passed as the 'propstat' parameter' to the corresponding
* 'end_propstat' callback. */
* 'end_propstat' callback. If the start_propstat callback returns
* NULL, parsing is aborted (the XML parser error must be set by the
* callback). */
typedef void *ne_207_start_propstat(void *userdata, void *response);
typedef void ne_207_end_propstat(void *userdata, void *propstat,
const ne_status *status,

View File

@ -41,6 +41,7 @@
#include "ne_string.h"
#include "ne_acl.h"
#include "ne_uri.h"
#include "ne_xml.h" /* for NE_XML_MEDIA_TYPE */
static ne_buffer *acl_body(ne_acl_entry *right, int count)
{
@ -110,12 +111,12 @@ int ne_acl_set(ne_session *sess, const char *uri,
ne_request *req = ne_request_create(sess, "ACL", uri);
ne_buffer *body = acl_body(entries, numentries);
#ifdef USE_DAV_LOCKS
#ifdef NE_HAVE_DAV
ne_lock_using_resource(req, uri, 0);
#endif
ne_set_request_body_buffer(req, body->data, ne_buffer_size(body));
ne_add_request_header(req, "Content-Type", "text/xml");
ne_add_request_header(req, "Content-Type", NE_XML_MEDIA_TYPE);
ret = ne_request_dispatch(req);
ne_buffer_destroy(body);

View File

@ -1,6 +1,6 @@
/*
Replacement memory allocation handling etc.
Copyright (C) 1999-2002, Joe Orton <joe@manyfish.co.uk>
Copyright (C) 1999-2004, Joe Orton <joe@manyfish.co.uk>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@ -41,11 +41,11 @@ void ne_oom_callback(void (*callback)(void));
* neon will abort(); calling an OOM callback beforehand if one is
* registered. The C library will only ever return NULL if the
* operating system does not use optimistic memory allocation. */
void *ne_malloc(size_t size);
void *ne_calloc(size_t size);
void *ne_realloc(void *ptr, size_t s);
char *ne_strdup(const char *s);
char *ne_strndup(const char *s, size_t n);
void *ne_malloc(size_t size) ne_attribute_malloc;
void *ne_calloc(size_t size) ne_attribute_malloc;
void *ne_realloc(void *ptr, size_t s) ne_attribute_malloc;
char *ne_strdup(const char *s) ne_attribute_malloc;
char *ne_strndup(const char *s, size_t n) ne_attribute_malloc;
#define ne_free free
#endif

View File

@ -50,7 +50,7 @@
#include <windows.h> /* for GetCurrentThreadId() etc */
#endif
#ifdef NEON_SSL
#ifdef HAVE_OPENSSL
#include <openssl/rand.h>
#endif
@ -161,8 +161,11 @@ typedef struct {
/* This used for Basic auth */
char *basic;
#ifdef HAVE_GSSAPI
/* This used for GSSAPI auth */
/* for the GSSAPI/Negotiate scheme: */
char *gssapi_token;
gss_ctx_id_t gssctx;
gss_name_t gssname;
gss_OID gssmech;
#endif
/* These all used for Digest auth */
char *realm;
@ -202,7 +205,7 @@ struct auth_request {
struct ne_md5_ctx response_body;
/* Results of response-header callbacks */
char *auth_hdr, *auth_info_hdr;
ne_buffer *auth_hdr, *auth_info_hdr;
};
static void clean_session(auth_session *sess)
@ -214,6 +217,17 @@ static void clean_session(auth_session *sess)
NE_FREE(sess->opaque);
NE_FREE(sess->realm);
#ifdef HAVE_GSSAPI
{
int major;
if (sess->gssctx != GSS_C_NO_CONTEXT)
gss_delete_sec_context(&major, sess->gssctx, GSS_C_NO_BUFFER);
if (sess->gssmech != GSS_C_NO_OID) {
gss_release_oid(&major, &sess->gssmech);
sess->gssmech = GSS_C_NO_OID;
}
}
NE_FREE(sess->gssapi_token);
#endif
}
@ -227,7 +241,7 @@ static char *get_cnonce(void)
ne_md5_init_ctx(&hash);
#ifdef NEON_SSL
#ifdef HAVE_OPENSSL
if (RAND_status() == 1 && RAND_pseudo_bytes(data, sizeof data) >= 0)
ne_md5_process_bytes(data, sizeof data, &hash);
else {
@ -260,7 +274,7 @@ static char *get_cnonce(void)
ne_md5_process_bytes(&pid, sizeof pid, &hash);
}
#ifdef NEON_SSL
#ifdef HAVE_OPENSSL
}
#endif
@ -321,69 +335,162 @@ static char *request_basic(auth_session *sess)
/* Add GSSAPI authentication credentials to a request */
static char *request_gssapi(auth_session *sess)
{
return ne_concat("Negotiate ", sess->gssapi_token, "\r\n", NULL);
if (sess->gssapi_token)
return ne_concat("Negotiate ", sess->gssapi_token, "\r\n", NULL);
else
return NULL;
}
static int get_gss_name(gss_name_t *server, auth_session *sess)
/* Create an GSSAPI name for server HOSTNAME; returns non-zero on
* error. */
static void get_gss_name(gss_name_t *server, const char *hostname)
{
unsigned int major_status, minor_status;
unsigned int major, minor;
gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
token.value = ne_concat("HTTP@", sess->sess->server.hostname, NULL);
token.value = ne_concat("HTTP@", hostname, NULL);
token.length = strlen(token.value);
major_status = gss_import_name(&minor_status, &token,
GSS_C_NT_HOSTBASED_SERVICE,
server);
return GSS_ERROR(major_status) ? -1 : 0;
major = gss_import_name(&minor, &token, GSS_C_NT_HOSTBASED_SERVICE,
server);
ne_free(token.value);
if (GSS_ERROR(major)) {
NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: gss_import_name failed.\n");
*server = GSS_C_NO_NAME;
}
}
/* Examine a GSSAPI auth challenge; returns 0 if a valid challenge,
* else non-zero. */
static int
gssapi_challenge(auth_session *sess, struct auth_challenge *parms)
/* Append GSSAPI error(s) for STATUS of type TYPE to BUF; prepending
* ": " to each error if *FLAG is non-zero, setting *FLAG after an
* error has been appended. */
static void make_gss_error(ne_buffer *buf, int *flag,
unsigned int status, int type)
{
gss_ctx_id_t context;
gss_name_t server_name;
unsigned int major_status, minor_status;
gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
int major, minor;
int context = 0;
do {
gss_buffer_desc msg;
major = gss_display_status(&minor, status, type,
GSS_C_NO_OID, &context, &msg);
if (major == GSS_S_COMPLETE && msg.length) {
if ((*flag)++) ne_buffer_append(buf, ": ", 2);
ne_buffer_append(buf, msg.value, msg.length);
}
if (msg.length) gss_release_buffer(&minor, &msg);
} while (context);
}
clean_session(sess);
/* Continue a GSS-API Negotiate exchange, using input TOKEN if
* non-NULL. Returns non-zero on error. */
static int continue_negotiate(auth_session *sess, const char *token)
{
unsigned int major, minor;
gss_buffer_desc input = GSS_C_EMPTY_BUFFER;
gss_buffer_desc output = GSS_C_EMPTY_BUFFER;
unsigned char *bintoken = NULL;
int ret;
gss_OID mech = sess->gssmech;
if (get_gss_name(&server_name, sess))
if (token) {
input.length = ne_unbase64(token, &bintoken);
if (input.length == 0) {
NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: Invalid input [%s].\n",
token);
return -1;
}
input.value = bintoken;
NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: Continuation token [%s]\n", token);
}
else if (sess->gssctx != GSS_C_NO_CONTEXT) {
NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: Reset incomplete context.\n");
gss_delete_sec_context(&minor, &sess->gssctx, GSS_C_NO_BUFFER);
}
major = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL, &sess->gssctx,
sess->gssname, mech,
GSS_C_MUTUAL_FLAG, GSS_C_INDEFINITE,
GSS_C_NO_CHANNEL_BINDINGS,
&input, &sess->gssmech, &output, NULL, NULL);
/* done with the input token. */
if (bintoken) ne_free(bintoken);
if (GSS_ERROR(major)) {
ne_buffer *err = ne_buffer_create();
int flag = 0;
make_gss_error(err, &flag, major, GSS_C_GSS_CODE);
make_gss_error(err, &flag, minor, GSS_C_MECH_CODE);
NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: Error: %s\n", err->data);
ne_set_error(sess->sess, _("GSSAPI authentication error (%s)"),
err->data);
ne_buffer_destroy(err);
return -1;
}
major_status = gss_init_sec_context(&minor_status,
GSS_C_NO_CREDENTIAL,
&context,
server_name,
GSS_C_NO_OID,
0,
GSS_C_INDEFINITE,
GSS_C_NO_CHANNEL_BINDINGS,
&input_token,
NULL,
&output_token,
NULL,
NULL);
gss_release_name(&minor_status, &server_name);
if (major == GSS_S_CONTINUE_NEEDED || major == GSS_S_COMPLETE) {
NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: init_sec_context OK. (major=%d)\n",
major);
ret = 0;
}
else {
NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: Init failure %d.\n", major);
ret = -1;
}
if (GSS_ERROR(major_status)) {
NE_DEBUG(NE_DBG_HTTPAUTH, "gss_init_sec_context failed.\n");
if (major != GSS_S_CONTINUE_NEEDED) {
/* context no longer needed: destroy it */
gss_delete_sec_context(&minor, &sess->gssctx, GSS_C_NO_BUFFER);
}
if (output.length) {
sess->gssapi_token = ne_base64(output.value, output.length);
NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: Output token: [%s]\n",
sess->gssapi_token);
gss_release_buffer(&minor, &output);
} else {
NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: No output token.\n");
}
return ret;
}
/* Process a Negotiate challange CHALL in session SESS; returns zero
* if challenge is accepted. */
static int gssapi_challenge(auth_session *sess, struct auth_challenge *chall)
{
int ret = continue_negotiate(sess, chall->opaque);
if (ret == 0)
sess->scheme = auth_scheme_gssapi;
return ret;
}
/* Verify the header HDR in a Negotiate response. */
static int verify_negotiate_response(auth_session *sess, char *hdr)
{
char *sep, *ptr = strchr(hdr, ' ');
if (strncmp(hdr, "Negotiate", ptr - hdr) != 0) {
NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: Not a Negotiate response!\n");
return -1;
}
if (output_token.length == 0)
return -1;
ptr++;
sess->gssapi_token = ne_base64(output_token.value, output_token.length);
gss_release_buffer(&major_status, &output_token);
if (strlen(ptr) == 0) {
NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: No token in Negotiate response!\n");
return 0;
}
NE_DEBUG(NE_DBG_HTTPAUTH,
"Base64 encoded GSSAPI challenge: %s.\n", sess->gssapi_token);
sess->scheme = auth_scheme_gssapi;
return 0;
if ((sep = strchr(ptr, ',')) != NULL)
*sep = '\0';
if ((sep = strchr(ptr, ' ')) != NULL)
*sep = '\0';
NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: Negotiate response token [%s]\n", ptr);
return continue_negotiate(sess, ptr);
}
#endif
@ -532,7 +639,7 @@ static char *request_digest(auth_session *sess, struct auth_request *req)
* where-ever it is coming from, and calculate the digest. */
NE_DEBUG(NE_DBG_HTTPAUTH, "Digesting request body...\n");
ne_pull_request_body(req->request, digest_body, &body);
ne__pull_request_body(req->request, digest_body, &body);
NE_DEBUG(NE_DBG_HTTPAUTH, "Digesting request body done.\n");
ne_md5_finish_ctx(&body, tmp_md5);
@ -637,7 +744,8 @@ static int tokenize(char **hdr, char **key, char **value, int ischall)
*pnt = '\0';
*value = pnt + 1;
state = AFTER_EQ;
} else if (*pnt == ' ' && ischall && *key != NULL) {
} else if ((*pnt == ' ' || *pnt == ',')
&& ischall && *key != NULL) {
*value = NULL;
*pnt = '\0';
*hdr = pnt + 1;
@ -679,8 +787,8 @@ static int tokenize(char **hdr, char **key, char **value, int ischall)
* 0 if it gives a valid authentication for the server
* non-zero otherwise (don't believe the response in this case!).
*/
static int verify_response(struct auth_request *req, auth_session *sess,
const char *value)
static int verify_digest_response(struct auth_request *req, auth_session *sess,
const char *value)
{
char *hdr, *pnt, *key, *val;
auth_qop qop = auth_qop_none;
@ -842,36 +950,39 @@ static int auth_challenge(auth_session *sess, const char *value)
while (!tokenize(&pnt, &key, &val, 1)) {
if (val == NULL) {
/* We have a new challenge */
NE_DEBUG(NE_DBG_HTTPAUTH, "New challenge for scheme [%s]\n", key);
chall = ne_calloc(sizeof *chall);
auth_scheme scheme;
chall->next = challenges;
challenges = chall;
/* Initialize the challenge parameters */
/* Which auth-scheme is it (case-insensitive matching) */
if (strcasecmp(key, "basic") == 0) {
NE_DEBUG(NE_DBG_HTTPAUTH, "Basic scheme.\n");
chall->scheme = auth_scheme_basic;
scheme = auth_scheme_basic;
} else if (strcasecmp(key, "digest") == 0) {
NE_DEBUG(NE_DBG_HTTPAUTH, "Digest scheme.\n");
chall->scheme = auth_scheme_digest;
#ifdef HAVE_GSSAPI
scheme = auth_scheme_digest;
}
#ifdef HAVE_GSSAPI
/* cope with a Negotiate parameter which doesn't match the
* auth-param due to the broken spec. */
else if (chall && chall->scheme == auth_scheme_gssapi
&& chall->opaque == NULL) {
chall->opaque = key;
continue;
} else if (strcasecmp(key, "negotiate") == 0) {
NE_DEBUG(NE_DBG_HTTPAUTH, "GSSAPI scheme.\n");
chall->scheme = auth_scheme_gssapi;
scheme = auth_scheme_gssapi;
}
#endif
} else {
NE_DEBUG(NE_DBG_HTTPAUTH, "Unknown scheme.\n");
ne_free(chall);
challenges = NULL;
break;
else {
NE_DEBUG(NE_DBG_HTTPAUTH, "Ignoring challenge '%s'.\n", key);
chall = NULL;
continue;
}
NE_DEBUG(NE_DBG_HTTPAUTH, "New '%s' challenge.\n", key);
chall = ne_calloc(sizeof *chall);
chall->scheme = scheme;
chall->next = challenges;
challenges = chall;
continue;
} else if (chall == NULL) {
/* If we haven't got an auth-scheme, and we're
* haven't yet found a challenge, skip this pair.
*/
/* Ignore pairs for an unknown challenge. */
NE_DEBUG(NE_DBG_HTTPAUTH, "Ignored pair: %s = %s\n", key, val);
continue;
}
@ -924,15 +1035,17 @@ static int auth_challenge(auth_session *sess, const char *value)
success = 0;
#ifdef HAVE_GSSAPI
if (strcmp(ne_get_scheme(sess->sess), "https") == 0) {
/* Ignore Negotiate challenges from origin servers which don't
* come over SSL. */
if (sess->spec == &ah_proxy_class || sess->context != AUTH_ANY) {
NE_DEBUG(NE_DBG_HTTPAUTH, "Looking for GSSAPI.\n");
/* Try a GSSAPI challenge */
for (chall = challenges; chall != NULL; chall = chall->next) {
if (chall->scheme == auth_scheme_gssapi) {
if (!gssapi_challenge(sess, chall)) {
success = 1;
break;
}
if (!gssapi_challenge(sess, chall)) {
success = 1;
break;
}
}
}
}
@ -985,12 +1098,21 @@ static int auth_challenge(auth_session *sess, const char *value)
}
/* The body reader callback. */
static void auth_body_reader(void *cookie, const char *block, size_t length)
static int auth_body_reader(void *cookie, const char *block, size_t length)
{
struct ne_md5_ctx *ctx = cookie;
NE_DEBUG(NE_DBG_HTTPAUTH,
"Digesting %" NE_FMT_SIZE_T " bytes of response body.\n", length);
ne_md5_process_bytes(block, length, ctx);
return 0;
}
/* Collect auth challenges into an ne_buffer */
static void ah_collect_header(void *userdata, const char *value)
{
ne_buffer *ar = userdata;
if (ne_buffer_size(ar)) ne_buffer_append(ar, ", ", 2);
ne_buffer_zappend(ar, value);
}
static void ah_create(ne_request *req, void *session, const char *method,
@ -1009,14 +1131,14 @@ static void ah_create(ne_request *req, void *session, const char *method,
areq->method = method;
areq->uri = uri;
areq->request = req;
areq->auth_hdr = ne_buffer_create();
areq->auth_info_hdr = ne_buffer_create();
ne_add_response_header_handler(req, sess->spec->resp_hdr,
ne_duplicate_header, &areq->auth_hdr);
ah_collect_header, areq->auth_hdr);
ne_add_response_header_handler(req, sess->spec->resp_info_hdr,
ne_duplicate_header,
&areq->auth_info_hdr);
ah_collect_header, areq->auth_info_hdr);
sess->attempt = 0;
@ -1035,7 +1157,7 @@ static void ah_pre_send(ne_request *r, void *cookie, ne_buffer *request)
} else {
char *value;
NE_DEBUG(NE_DBG_HTTPAUTH, "Handling.");
NE_DEBUG(NE_DBG_HTTPAUTH, "Handling auth session.\n");
req->will_handle = 1;
if (sess->qop == auth_qop_auth_int) {
@ -1082,22 +1204,44 @@ static int ah_post_send(ne_request *req, void *cookie, const ne_status *status)
if (!areq) return NE_OK;
#ifdef HAVE_GSSAPI
/* whatever happens: forget the GSSAPI token cached thus far */
if (sess->gssapi_token) {
ne_free(sess->gssapi_token);
sess->gssapi_token = NULL;
}
#endif
NE_DEBUG(NE_DBG_HTTPAUTH,
"ah_post_send (#%d), code is %d (want %d), %s is %s\n",
sess->attempt, status->code, sess->spec->status_code,
sess->spec->resp_hdr, SAFELY(areq->auth_hdr));
if (areq->auth_info_hdr != NULL &&
verify_response(areq, sess, areq->auth_info_hdr)) {
NE_DEBUG(NE_DBG_HTTPAUTH, "Response authentication invalid.\n");
ne_set_error(sess->sess, "%s", _(sess->spec->fail_msg));
ret = NE_ERROR;
} else if ((status->code == sess->spec->status_code ||
(status->code == 401 && sess->context == AUTH_CONNECT)) &&
areq->auth_hdr != NULL) {
sess->spec->resp_hdr, areq->auth_hdr->data);
if (ne_buffer_size(areq->auth_info_hdr)
&& sess->scheme == auth_scheme_digest) {
if (verify_digest_response(areq, sess, areq->auth_info_hdr->data)) {
NE_DEBUG(NE_DBG_HTTPAUTH, "Response authentication invalid.\n");
ne_set_error(sess->sess, "%s", _(sess->spec->fail_msg));
ret = NE_ERROR;
}
}
#ifdef HAVE_GSSAPI
/* one must wonder... has Mr Brezak actually read RFC2617? */
else if (sess->scheme == auth_scheme_gssapi
&& (status->klass == 2 || status->klass == 3)
&& ne_buffer_size(areq->auth_hdr)) {
if (verify_negotiate_response(sess, areq->auth_hdr->data)) {
NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: Mutual auth failed.\n");
ret = NE_ERROR;
}
}
#endif /* HAVE_GSSAPI */
else if ((status->code == sess->spec->status_code ||
(status->code == 401 && sess->context == AUTH_CONNECT)) &&
ne_buffer_size(areq->auth_hdr)) {
/* note above: allow a 401 in response to a CONNECT request
* from a proxy since some buggy proxies send that. */
NE_DEBUG(NE_DBG_HTTPAUTH, "Got challenge with code %d.\n", status->code);
if (!auth_challenge(sess, areq->auth_hdr)) {
NE_DEBUG(NE_DBG_HTTPAUTH, "Got challenge (code %d).\n", status->code);
if (!auth_challenge(sess, areq->auth_hdr->data)) {
ret = NE_RETRY;
} else {
clean_session(sess);
@ -1105,9 +1249,9 @@ static int ah_post_send(ne_request *req, void *cookie, const ne_status *status)
}
}
NE_FREE(areq->auth_info_hdr);
NE_FREE(areq->auth_hdr);
ne_buffer_clear(areq->auth_hdr);
ne_buffer_clear(areq->auth_info_hdr);
return ret;
}
@ -1115,13 +1259,25 @@ static void ah_destroy(ne_request *req, void *session)
{
auth_session *sess = session;
struct auth_request *areq = ne_get_request_private(req, sess->spec->id);
if (areq) ne_free(areq);
if (areq) {
ne_buffer_destroy(areq->auth_info_hdr);
ne_buffer_destroy(areq->auth_hdr);
ne_free(areq);
}
}
static void free_auth(void *cookie)
{
auth_session *sess = cookie;
#ifdef HAVE_GSSAPI
if (sess->gssname != GSS_C_NO_NAME) {
int major;
gss_release_name(&major, sess->gssname);
}
#endif
clean_session(sess);
ne_free(sess);
}
@ -1137,10 +1293,19 @@ static void auth_register(ne_session *sess, int isproxy,
ahs->sess = sess;
ahs->spec = ahc;
if (strcmp(ne_get_scheme(sess), "https") == 0)
if (strcmp(ne_get_scheme(sess), "https") == 0) {
ahs->context = isproxy ? AUTH_CONNECT : AUTH_NOTCONNECT;
else
#ifdef HAVE_GSSAPI
{
get_gss_name(&ahs->gssname, (isproxy ? sess->proxy.hostname
: sess->server.hostname));
ahs->gssctx = GSS_C_NO_CONTEXT;
ahs->gssmech = GSS_C_NO_OID;
}
#endif
} else {
ahs->context = AUTH_ANY;
}
/* Register hooks */
ne_hook_create_request(sess, ah_create, ahs);

View File

@ -1,6 +1,6 @@
/*
Basic HTTP and WebDAV methods
Copyright (C) 1999-2003, Joe Orton <joe@manyfish.co.uk>
Copyright (C) 1999-2004, Joe Orton <joe@manyfish.co.uk>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@ -22,6 +22,7 @@
#include "config.h"
#include <sys/types.h>
#include <sys/stat.h> /* for struct stat */
#ifdef HAVE_STRING_H
#include <string.h>
@ -41,13 +42,11 @@
#include "ne_basic.h"
#include "ne_207.h"
#ifndef NEON_NODAV
#ifdef NE_HAVE_DAV
#include "ne_uri.h"
#endif
#ifdef USE_DAV_LOCKS
#include "ne_locks.h"
#endif
#include "ne_dates.h"
#include "ne_i18n.h"
@ -82,15 +81,27 @@ int ne_getmodtime(ne_session *sess, const char *uri, time_t *modtime)
/* PUT's from fd to URI */
int ne_put(ne_session *sess, const char *uri, int fd)
{
ne_request *req = ne_request_create(sess, "PUT", uri);
ne_request *req;
struct stat st;
int ret;
if (fstat(fd, &st)) {
int errnum = errno;
char buf[200];
ne_set_error(sess, _("Could not determine file size: %s"),
ne_strerror(errnum, buf, sizeof buf));
return NE_ERROR;
}
#ifdef USE_DAV_LOCKS
req = ne_request_create(sess, "PUT", uri);
#ifdef NE_HAVE_DAV
ne_lock_using_resource(req, uri, 0);
ne_lock_using_parent(req, uri);
#endif
ne_set_request_body_fd(req, fd);
ne_set_request_body_fd(req, fd, 0, st.st_size);
ret = ne_request_dispatch(req);
@ -102,59 +113,6 @@ int ne_put(ne_session *sess, const char *uri, int fd)
return ret;
}
/* Conditional HTTP put.
* PUTs from fd to uri, returning NE_FAILED if resource as URI has
* been modified more recently than 'since'.
*/
int
ne_put_if_unmodified(ne_session *sess, const char *uri, int fd,
time_t since)
{
ne_request *req;
char *date;
int ret;
if (ne_version_pre_http11(sess)) {
time_t modtime;
/* Server is not minimally HTTP/1.1 compliant. Do a HEAD to
* check the remote mod time. Of course, this makes the
* operation very non-atomic, but better than nothing. */
ret = ne_getmodtime(sess, uri, &modtime);
if (ret != NE_OK) return ret;
if (modtime != since)
return NE_FAILED;
}
req = ne_request_create(sess, "PUT", uri);
date = ne_rfc1123_date(since);
/* Add in the conditionals */
ne_add_request_header(req, "If-Unmodified-Since", date);
ne_free(date);
#ifdef USE_DAV_LOCKS
ne_lock_using_resource(req, uri, 0);
/* FIXME: this will give 412 if the resource doesn't exist, since
* PUT may modify the parent... does that matter? */
#endif
ne_set_request_body_fd(req, fd);
ret = ne_request_dispatch(req);
if (ret == NE_OK) {
if (ne_get_status(req)->code == 412) {
ret = NE_FAILED;
} else if (ne_get_status(req)->klass != 2) {
ret = NE_ERROR;
}
}
ne_request_destroy(req);
return ret;
}
struct get_context {
int error;
ne_session *session;
@ -163,27 +121,32 @@ struct get_context {
ne_content_range *range;
};
static void get_to_fd(void *userdata, const char *block, size_t length)
static int get_to_fd(void *userdata, const char *block, size_t length)
{
struct get_context *ctx = userdata;
ssize_t ret;
if (ctx->error) {
return -1;
}
if (!ctx->error) {
while (length > 0) {
ret = write(ctx->fd, block, length);
if (ret < 0) {
char err[200];
ctx->error = 1;
ne_strerror(errno, err, sizeof err);
ne_set_error(ctx->session, _("Could not write to file: %s"),
err);
break;
return -1;
} else {
length -= ret;
block += ret;
}
}
}
return 0;
}
static int accept_206(void *ud, ne_request *req, const ne_status *st)
@ -396,9 +359,14 @@ void ne_content_type_handler(void *userdata, const char *value)
/* set subtype, losing any trailing whitespace */
ct->subtype = ne_shave(stype, " \t");
/* 2616#3.7.1: subtypes of text/ default to charset ISO-8859-1. */
if (ct->charset == NULL && strcasecmp(ct->type, "text") == 0)
ct->charset = "ISO-8859-1";
if (ct->charset == NULL && strcasecmp(ct->type, "text") == 0) {
/* 3280§3.1: text/xml without charset implies us-ascii. */
if (strcasecmp(ct->subtype, "xml") == 0)
ct->charset = "us-ascii";
/* 2616§3.7.1: subtypes of text/ default to charset ISO-8859-1. */
else
ct->charset = "ISO-8859-1";
}
}
static void dav_hdr_handler(void *userdata, const char *value)
@ -445,7 +413,7 @@ int ne_options(ne_session *sess, const char *uri,
return ret;
}
#ifndef NEON_NODAV
#ifdef NE_HAVE_DAV
void ne_add_depth_header(ne_request *req, int depth)
{
@ -474,7 +442,7 @@ static int copy_or_move(ne_session *sess, int is_move, int overwrite,
ne_add_depth_header(req, depth);
}
#ifdef USE_DAV_LOCKS
#ifdef NE_HAVE_DAV
if (is_move) {
ne_lock_using_resource(req, src, NE_DEPTH_INFINITE);
}
@ -509,7 +477,7 @@ int ne_delete(ne_session *sess, const char *uri)
{
ne_request *req = ne_request_create(sess, "DELETE", uri);
#ifdef USE_DAV_LOCKS
#ifdef NE_HAVE_DAV
ne_lock_using_resource(req, uri, NE_DEPTH_INFINITE);
ne_lock_using_parent(req, uri);
#endif
@ -539,7 +507,7 @@ int ne_mkcol(ne_session *sess, const char *uri)
req = ne_request_create(sess, "MKCOL", real_uri);
#ifdef USE_DAV_LOCKS
#ifdef NE_HAVE_DAV
ne_lock_using_resource(req, real_uri, 0);
ne_lock_using_parent(req, real_uri);
#endif
@ -551,4 +519,4 @@ int ne_mkcol(ne_session *sess, const char *uri)
return ret;
}
#endif /* NEON_NODAV */
#endif /* NE_HAVE_DAV */

View File

@ -1,6 +1,6 @@
/*
HTTP/1.1 methods
Copyright (C) 1999-2001, Joe Orton <joe@light.plus.com>
Copyright (C) 1999-2002, Joe Orton <joe@manyfish.co.uk>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@ -28,58 +28,54 @@
BEGIN_NEON_DECLS
/* PUT resource at uri, reading request body from f */
int ne_put(ne_session *sess, const char *uri, int fd);
/* Perform a GET request on resource at 'path', writing the entity
* body which is returned to 'fd'. */
int ne_get(ne_session *sess, const char *path, int fd);
/* GET resource at uri, writing response body into f */
int ne_get(ne_session *sess, const char *uri, int fd);
#ifndef NEON_NODAV
/* Basic WebDAV methods:
* ne_copy: copy resoure from src to dest
* ne_move: move resource from src to dest
* -> if overwrite is non-zero, the destination resource
* will be overwritten if it exists.
* ne_delete: delete resource at uri
* ne_mkcol: create a collection at uri (uri MUST have a trailing slash).
*/
int ne_copy(ne_session *sess, int overwrite, const char *src, const char *dest);
int ne_move(ne_session *sess, int overwrite, const char *src, const char *dest);
int ne_delete(ne_session *sess, const char *uri);
int ne_mkcol(ne_session *sess, const char *uri);
/* Perform a PUT request on resource at 'path', reading the entity
* body to submit from 'fd'. */
int ne_put(ne_session *sess, const char *path, int fd);
#define NE_DEPTH_ZERO (0)
#define NE_DEPTH_ONE (1)
#define NE_DEPTH_INFINITE (2)
/* For ne_copy and ne_move:
*
* If a resource exists at "dest" and overwrite is zero, the operation
* will fail; if overwrite is non-zero, any existing resource will
* be over-written.
*/
/* Copy resource from 'src to 'dest' paths. If 'src' identifies a
* collection resource, depth may be NE_DEPTH_ZERO to request that the
* collection and its properties are to be copied, or
* NE_DEPTH_INFINITE to request that the collection and its contents
* are to be copied. */
int ne_copy(ne_session *sess, int overwrite, int depth,
const char *src, const char *dest);
/* Move resource from 'src' to dest 'path'. */
int ne_move(ne_session *sess, int overwrite,
const char *src, const char *dest);
/* Delete resource at 'path'. */
int ne_delete(ne_session *sess, const char *path);
/* Create a collection at 'path', which MUST have a trailing slash. */
int ne_mkcol(ne_session *sess, const char *path);
/* Adds a Depth: header to a request */
void ne_add_depth_header(ne_request *req, int depth);
#endif /* NEON_NODAV */
/* PUT resource at uri as above, only if it has not been modified
* since given modtime. If server is HTTP/1.1, uses If-Unmodified-Since
* header; guaranteed failure if resource is modified after 'modtime'.
* If server is HTTP/1.0, HEAD's the resource first to fetch current
* modtime; race condition if resource is modified between HEAD and PUT.
*/
int ne_put_if_unmodified(ne_session *sess,
const char *uri, int fd, time_t modtime);
/* GET resource at uri, passing response body blocks to 'reader' */
int ne_read_file(ne_session *sess, const char *uri,
ne_block_reader reader, void *userdata);
/* Retrieve modification time of resource at uri, place in *modtime.
* (uses HEAD) */
int ne_getmodtime(ne_session *sess, const char *uri, time_t *modtime);
/* Retrieve modification time of resource at location 'path', place in
* *modtime. (uses HEAD) */
int ne_getmodtime(ne_session *sess, const char *path, time_t *modtime);
typedef struct {
const char *type, *subtype;
const char *charset;
char *value;
} ne_content_type;
} ne_content_type;
/* Sets (*ne_content_type)userdata appropriately.
* Caller must free ->value after use */
@ -87,21 +83,15 @@ void ne_content_type_handler(void *userdata, const char *value);
/* Server capabilities: */
typedef struct {
unsigned int broken_expect100:1; /* True if the server is known to
* have broken Expect:
* 100-continue support; Apache
* 1.3.6 and earlier. */
unsigned int dav_class1; /* True if Class 1 WebDAV server */
unsigned int dav_class2; /* True if Class 2 WebDAV server */
unsigned int dav_executable; /* True if supports the 'executable'
* property a. la. mod_dav */
} ne_server_capabilities;
/* Determines server capabilities (using OPTIONS).
* Pass uri="*" to determine proxy server capabilities if using
* a proxy server. */
int ne_options(ne_session *sess, const char *uri,
/* Determines server capabilities (using OPTIONS). Pass 'path' as "*"
* to determine proxy server capabilities if using a proxy server. */
int ne_options(ne_session *sess, const char *path,
ne_server_capabilities *caps);
/* Defines a range of bytes, starting at 'start' and ending
@ -124,12 +114,12 @@ typedef struct {
* range.start = resume_from;
* range.end = range.start + 999; (= 1000 bytes)
* fseek(myfile, resume_from, SEEK_SET);
* ne_get_range(sess, uri, &range, myfile); */
int ne_get_range(ne_session *sess, const char *uri,
* ne_get_range(sess, path, &range, myfile); */
int ne_get_range(ne_session *sess, const char *path,
ne_content_range *range, int fd);
/* Post using buffer as request-body: stream response into f */
int ne_post(ne_session *sess, const char *uri, int fd, const char *buffer);
int ne_post(ne_session *sess, const char *path, int fd, const char *buffer);
END_NEON_DECLS

View File

@ -33,9 +33,7 @@
#include "ne_utils.h"
#include "ne_i18n.h"
#include "ne_private.h"
#ifdef NEON_ZLIB
#ifdef NE_HAVE_ZLIB
#include <zlib.h>
@ -89,8 +87,7 @@ struct ne_decompress_s {
NE_Z_POST_HEADER, /* waiting for the end of the NUL-terminated bits. */
NE_Z_INFLATING, /* inflating response bytes. */
NE_Z_AFTER_DATA, /* after data; reading CRC32 & ISIZE */
NE_Z_FINISHED, /* stream is finished. */
NE_Z_ERROR /* inflate bombed. */
NE_Z_FINISHED /* stream is finished. */
} state;
};
@ -105,7 +102,7 @@ struct ne_decompress_s {
* HDR_DONE: all done, bytes following are raw DEFLATE data.
* HDR_EXTENDED: all done, expect a NUL-termianted string
* before the DEFLATE data
* HDR_ERROR: invalid header, give up.
* HDR_ERROR: invalid header, give up (session error is set).
*/
static int parse_header(ne_decompress *ctx)
{
@ -115,7 +112,6 @@ static int parse_header(ne_decompress *ctx)
h->id1, h->id2, h->cmeth, h->flags);
if (h->id1 != ID1 || h->id2 != ID2 || h->cmeth != 8) {
ctx->state = NE_Z_ERROR;
ne_set_error(ctx->session, "Compressed stream invalid");
return HDR_ERROR;
}
@ -131,7 +127,6 @@ static int parse_header(ne_decompress *ctx)
ctx->state = NE_Z_POST_HEADER;
return HDR_EXTENDED;
} else if (h->flags != 0) {
ctx->state = NE_Z_ERROR;
ne_set_error(ctx->session, "Compressed stream not supported");
return HDR_ERROR;
}
@ -147,14 +142,14 @@ static int parse_header(ne_decompress *ctx)
/* Process extra 'len' bytes of 'buf' which were received after the
* DEFLATE data. */
static void process_footer(ne_decompress *ctx,
static int process_footer(ne_decompress *ctx,
const unsigned char *buf, size_t len)
{
if (len + ctx->footcount > 8) {
ne_set_error(ctx->session,
"Too many bytes (%" NE_FMT_SIZE_T ") in gzip footer",
len);
ctx->state = NE_Z_ERROR;
return -1;
} else {
memcpy(ctx->footer + ctx->footcount, buf, len);
ctx->footcount += len;
@ -170,10 +165,11 @@ static void process_footer(ne_decompress *ctx,
"given %lu vs computed %lu\n", crc, ctx->checksum);
ne_set_error(ctx->session,
"Checksum invalid for compressed stream");
ctx->state = NE_Z_ERROR;
return -1;
}
}
}
return 0;
}
/* A zlib function failed with 'code'; set the session error string
@ -197,7 +193,7 @@ static void set_zlib_error(ne_decompress *ctx, const char *msg, int code)
}
/* Inflate response buffer 'buf' of length 'len'. */
static void do_inflate(ne_decompress *ctx, const char *buf, size_t len)
static int do_inflate(ne_decompress *ctx, const char *buf, size_t len)
{
int ret;
@ -236,39 +232,56 @@ static void do_inflate(ne_decompress *ctx, const char *buf, size_t len)
ctx->zstr.avail_in);
/* process the footer. */
ctx->state = NE_Z_AFTER_DATA;
process_footer(ctx, ctx->zstr.next_in, ctx->zstr.avail_in);
return process_footer(ctx, ctx->zstr.next_in, ctx->zstr.avail_in);
} else if (ret != Z_OK) {
ctx->state = NE_Z_ERROR;
set_zlib_error(ctx, _("Could not inflate data"), ret);
return NE_ERROR;
}
return 0;
}
/* Callback which is passed blocks of the response body. */
static void gz_reader(void *ud, const char *buf, size_t len)
static int gz_reader(void *ud, const char *buf, size_t len)
{
ne_decompress *ctx = ud;
const char *zbuf;
size_t count;
if (len == 0) {
/* End of response: */
switch (ctx->state) {
case NE_Z_BEFORE_DATA:
if (ctx->enchdr && strcasecmp(ctx->enchdr, "gzip") == 0) {
/* response was truncated: break out. */
break;
}
/* else, fall through */
case NE_Z_FINISHED: /* complete gzip response */
case NE_Z_PASSTHROUGH: /* complete uncompressed response */
return ctx->reader(ctx->userdata, buf, 0);
default:
/* invalid state: truncated response. */
break;
}
/* else: truncated response, fail. */
ne_set_error(ctx->session, "Compressed response was truncated");
return NE_ERROR;
}
switch (ctx->state) {
case NE_Z_PASSTHROUGH:
/* move along there. */
ctx->reader(ctx->userdata, buf, len);
return;
case NE_Z_ERROR:
/* beyond hope. */
break;
return ctx->reader(ctx->userdata, buf, len);
case NE_Z_FINISHED:
/* Could argue for tolerance, and ignoring trailing content;
* but it could mean something more serious. */
if (len > 0) {
ctx->state = NE_Z_ERROR;
ne_set_error(ctx->session,
"Unexpected content received after compressed stream");
return NE_ERROR;
}
break;
break;
case NE_Z_BEFORE_DATA:
/* work out whether this is a compressed response or not. */
@ -280,7 +293,7 @@ static void gz_reader(void *ud, const char *buf, size_t len)
ret = inflateInit2(&ctx->zstr, -MAX_WBITS);
if (ret != Z_OK) {
set_zlib_error(ctx, _("Could not initialize zlib"), ret);
return;
return -1;
}
ctx->zstrinit = 1;
@ -290,8 +303,7 @@ static void gz_reader(void *ud, const char *buf, size_t len)
* would require add_resp_body_rdr to have defined
* ordering semantics etc etc */
ctx->state = NE_Z_PASSTHROUGH;
ctx->reader(ctx->userdata, buf, len);
return;
return ctx->reader(ctx->userdata, buf, len);
}
ctx->state = NE_Z_IN_HEADER;
@ -308,7 +320,7 @@ static void gz_reader(void *ud, const char *buf, size_t len)
ctx->incount += count;
/* have we got the full header yet? */
if (ctx->incount != 10) {
return;
return 0;
}
buf += count;
@ -317,14 +329,15 @@ static void gz_reader(void *ud, const char *buf, size_t len)
switch (parse_header(ctx)) {
case HDR_EXTENDED:
if (len == 0)
return;
return 0;
break;
case HDR_ERROR:
return NE_ERROR;
case HDR_DONE:
if (len > 0) {
do_inflate(ctx, buf, len);
return do_inflate(ctx, buf, len);
}
default:
return;
break;
}
/* FALLTHROUGH */
@ -334,7 +347,7 @@ static void gz_reader(void *ud, const char *buf, size_t len)
zbuf = memchr(buf, '\0', len);
if (zbuf == NULL) {
/* not found it yet. */
return;
return 0;
}
NE_DEBUG(NE_DBG_HTTP,
@ -346,26 +359,23 @@ static void gz_reader(void *ud, const char *buf, size_t len)
ctx->state = NE_Z_INFLATING;
if (len == 0) {
/* end of string was at end of buffer. */
return;
return 0;
}
/* FALLTHROUGH */
case NE_Z_INFLATING:
do_inflate(ctx, buf, len);
break;
return do_inflate(ctx, buf, len);
case NE_Z_AFTER_DATA:
process_footer(ctx, (unsigned char *)buf, len);
break;
return process_footer(ctx, (unsigned char *)buf, len);
}
return 0;
}
int ne_decompress_destroy(ne_decompress *ctx)
void ne_decompress_destroy(ne_decompress *ctx)
{
int ret;
if (ctx->zstrinit)
/* inflateEnd only fails if it's passed NULL etc; ignore
* return value. */
@ -374,50 +384,7 @@ int ne_decompress_destroy(ne_decompress *ctx)
if (ctx->enchdr)
ne_free(ctx->enchdr);
switch (ctx->state) {
case NE_Z_BEFORE_DATA:
case NE_Z_PASSTHROUGH:
case NE_Z_FINISHED:
ret = NE_OK;
break;
case NE_Z_ERROR:
/* session error already set. */
ret = NE_ERROR;
break;
default:
/* truncated response. */
ne_set_error(ctx->session, "Compressed response was truncated");
ret = NE_ERROR;
break;
}
ne_free(ctx);
return ret;
}
/* Prepare for a compressed response */
static void gz_pre_send(ne_request *r, void *ud, ne_buffer *req)
{
ne_decompress *ctx = ud;
NE_DEBUG(NE_DBG_HTTP, "compress: Initialization.\n");
/* (Re-)Initialize the context */
ctx->state = NE_Z_BEFORE_DATA;
if (ctx->zstrinit) inflateEnd(&ctx->zstr);
ctx->zstrinit = 0;
ctx->incount = ctx->footcount = 0;
ctx->checksum = crc32(0L, Z_NULL, 0);
if (ctx->enchdr) {
ne_free(ctx->enchdr);
ctx->enchdr = NULL;
}
}
/* Kill the pre-send hook */
static void gz_destroy(ne_request *req, void *userdata)
{
ne_kill_pre_send(ne_get_session(req), gz_pre_send, userdata);
}
/* Wrapper for user-passed acceptor function. */
@ -439,18 +406,18 @@ ne_decompress *ne_decompress_reader(ne_request *req, ne_accept_response acpt,
ne_add_response_body_reader(req, gz_acceptor, gz_reader, ctx);
ctx->state = NE_Z_BEFORE_DATA;
ctx->reader = rdr;
ctx->userdata = userdata;
ctx->session = ne_get_session(req);
/* initialize the checksum. */
ctx->checksum = crc32(0L, Z_NULL, 0);
ctx->acceptor = acpt;
ne_hook_pre_send(ctx->session, gz_pre_send, ctx);
ne_hook_destroy_request(ctx->session, gz_destroy, ctx);
return ctx;
}
#else /* !NEON_ZLIB */
#else /* !NE_HAVE_ZLIB */
/* Pass-through interface present to provide ABI compatibility. */
@ -467,4 +434,4 @@ int ne_decompress_destroy(ne_decompress *dc)
return 0;
}
#endif /* NEON_ZLIB */
#endif /* NE_HAVE_ZLIB */

View File

@ -1,6 +1,6 @@
/*
Compressed HTPT request/response Handling
Copyright (C) 2001, Joe Orton <joe@manyfish.co.uk>
Compressed HTTP response handling
Copyright (C) 2001-2004, Joe Orton <joe@manyfish.co.uk>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@ -33,12 +33,12 @@ typedef struct ne_decompress_s ne_decompress;
*
* Returns pointer to context object which must be passed to
* ne_decompress_destroy after the request has been dispatched, to
* free any internal state. */
* free any internal state. If an error occurs during decompression,
* the request will be aborted and session error string set. */
ne_decompress *ne_decompress_reader(ne_request *req, ne_accept_response accpt,
ne_block_reader rdr, void *userdata);
/* Free's up internal state. Returns non-zero if errors occured during
* decompression: the session error string will have the error. */
int ne_decompress_destroy(ne_decompress *ctx);
/* Destroys decompression state. */
void ne_decompress_destroy(ne_decompress *ctx);
#endif /* NE_COMPRESS_H */

View File

@ -1,6 +1,7 @@
/*
Date manipulation routines
Copyright (C) 1999-2004, Joe Orton <joe@manyfish.co.uk>
Copyright (C) 2004 Jiang Lei <tristone@deluxe.ocn.ne.jp>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@ -35,7 +36,7 @@
#include "ne_alloc.h"
#include "ne_dates.h"
#include "ne_utils.h"
#include "ne_string.h"
/* Generic date manipulation routines. */
@ -61,11 +62,35 @@ static const char *short_months[12] = {
#if defined(HAVE_STRUCT_TM_TM_GMTOFF)
#define GMTOFF(t) ((t).tm_gmtoff)
#elif defined(HAVE_STRUCT_TM___TM_GMTOFF)
#define GMTOFF(t) ((t).__tm_gmtoff)
#elif defined(WIN32)
#define GMTOFF(t) (gmt_to_local_win32())
#else
/* FIXME: work out the offset anyway. */
#define GMTOFF(t) (0)
#endif
#ifdef WIN32
time_t gmt_to_local_win32(void)
{
TIME_ZONE_INFORMATION tzinfo;
DWORD dwStandardDaylight;
long bias;
dwStandardDaylight = GetTimeZoneInformation(&tzinfo);
bias = tzinfo.Bias;
if (dwStandardDaylight == TIME_ZONE_ID_STANDARD)
bias += tzinfo.StandardBias;
if (dwStandardDaylight == TIME_ZONE_ID_DAYLIGHT)
bias += tzinfo.DaylightBias;
return (- bias * 60);
}
#endif
/* Returns the time/date GMT, in RFC1123-type format: eg
* Sun, 06 Nov 1994 08:49:37 GMT. */
char *ne_rfc1123_date(time_t anytime) {

View File

@ -1,6 +1,6 @@
/*
Standard definitions for neon headers
Copyright (C) 2003, Joe Orton <joe@manyfish.co.uk>
Copyright (C) 2003-2004, Joe Orton <joe@manyfish.co.uk>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@ -35,7 +35,13 @@
#endif
#ifdef __GNUC__
#if __GNUC__ >= 3
#define ne_attribute_malloc __attribute__((malloc))
#else
#define ne_attribute_malloc
#endif
#define ne_attribute(x) __attribute__(x)
#else
#define ne_attribute(x)
#define ne_attribute_malloc
#endif

853
neon/src/ne_gnutls.c Normal file
View File

@ -0,0 +1,853 @@
/*
neon SSL/TLS support using GNU TLS
Copyright (C) 2002-2004, Joe Orton <joe@manyfish.co.uk>
Copyright (C) 2004, Aleix Conchillo Flaque <aleix@member.fsf.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/
#include "config.h"
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <gnutls/gnutls.h>
#include <gnutls/pkcs12.h>
#include "ne_ssl.h"
#include "ne_string.h"
#include "ne_session.h"
#include "ne_i18n.h"
#include "ne_private.h"
#include "ne_privssl.h"
struct ne_ssl_dname_s {
int subject; /* non-zero if this is the subject DN object */
gnutls_x509_crt cert;
};
struct ne_ssl_certificate_s {
ne_ssl_dname subj_dn, issuer_dn;
gnutls_x509_crt subject;
ne_ssl_certificate *issuer;
char *identity;
};
struct ne_ssl_client_cert_s {
gnutls_pkcs12 p12;
int decrypted; /* non-zero if successfully decrypted. */
ne_ssl_certificate cert;
gnutls_x509_privkey pkey;
char *friendly_name;
};
/* Returns the highest used index in subject (or issuer) DN of
* certificate CERT for OID, or -1 if no RDNs are present in the DN
* using that OID. */
static int oid_find_highest_index(gnutls_x509_crt cert, int subject, const char *oid)
{
int ret, idx = -1;
do {
size_t len = 0;
if (subject)
ret = gnutls_x509_crt_get_dn_by_oid(cert, oid, ++idx, 0,
NULL, &len);
else
ret = gnutls_x509_crt_get_issuer_dn_by_oid(cert, oid, ++idx, 0,
NULL, &len);
} while (ret == GNUTLS_E_SHORT_MEMORY_BUFFER);
return idx - 1;
}
/* Appends the value of RDN with given oid from certitifcate x5
* subject (if subject is non-zero), or issuer DN to buffer 'buf': */
static void append_rdn(ne_buffer *buf, gnutls_x509_crt x5, int subject, const char *oid)
{
int idx, top, ret;
char rdn[50];
top = oid_find_highest_index(x5, subject, oid);
for (idx = top; idx >= 0; idx--) {
size_t rdnlen = sizeof rdn;
if (subject)
ret = gnutls_x509_crt_get_dn_by_oid(x5, oid, idx, 0, rdn, &rdnlen);
else
ret = gnutls_x509_crt_get_issuer_dn_by_oid(x5, oid, idx, 0, rdn, &rdnlen);
if (ret < 0)
return;
if (buf->used > 1) {
ne_buffer_append(buf, ", ", 2);
}
ne_buffer_append(buf, rdn, rdnlen);
}
}
char *ne_ssl_readable_dname(const ne_ssl_dname *name)
{
ne_buffer *buf = ne_buffer_create();
#if 0
/* this code can be used once there is a released version of GnuTLS
* with fixed _get_dn_oid functions */
int ret, idx = 0;
do {
char oid[32] = {0};
size_t oidlen = sizeof oid;
ret = name->subject
? gnutls_x509_crt_get_dn_oid(name->cert, idx, oid, &oidlen)
: gnutls_x509_crt_get_issuer_dn_oid(name->cert, idx, oid, &oidlen);
if (ret == 0) {
append_rdn(buf, name->cert, name->subject, oid);
idx++;
}
} while (ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
#else
#define APPEND_RDN(x) append_rdn(buf, name->cert, name->subject, GNUTLS_OID_##x)
APPEND_RDN(X520_ORGANIZATIONAL_UNIT_NAME);
APPEND_RDN(X520_ORGANIZATION_NAME);
APPEND_RDN(X520_LOCALITY_NAME);
APPEND_RDN(X520_STATE_OR_PROVINCE_NAME);
APPEND_RDN(X520_COUNTRY_NAME);
if (buf->used == 1) APPEND_RDN(X520_COMMON_NAME);
if (buf->used == 1) APPEND_RDN(PKCS9_EMAIL);
#undef APPEND_RDN
#endif
return ne_buffer_finish(buf);
}
int ne_ssl_dname_cmp(const ne_ssl_dname *dn1, const ne_ssl_dname *dn2)
{
#warning incomplete
return 1;
}
void ne_ssl_clicert_free(ne_ssl_client_cert *cc)
{
if (cc->p12)
gnutls_pkcs12_deinit(cc->p12);
if (cc->decrypted) {
if (cc->cert.identity) ne_free(cc->cert.identity);
if (cc->pkey) gnutls_x509_privkey_deinit(cc->pkey);
if (cc->cert.subject) gnutls_x509_crt_deinit(cc->cert.subject);
}
if (cc->friendly_name) ne_free(cc->friendly_name);
ne_free(cc);
}
void ne_ssl_cert_validity(const ne_ssl_certificate *cert,
char *from, char *until)
{
#warning FIXME strftime not portable
if (from) {
time_t t = gnutls_x509_crt_get_activation_time(cert->subject);
strftime(from, NE_SSL_VDATELEN, "%b %d %H:%M:%S %Y %Z", localtime(&t));
}
if (until) {
time_t t = gnutls_x509_crt_get_expiration_time(cert->subject);
strftime(until, NE_SSL_VDATELEN, "%b %d %H:%M:%S %Y %Z", localtime(&t));
}
}
/* Return non-zero if hostname from certificate (cn) matches hostname
* used for session (hostname). (Wildcard matching is no longer
* mandated by RFC3280, but certs are deployed which use wildcards) */
static int match_hostname(char *cn, const char *hostname)
{
const char *dot;
NE_DEBUG(NE_DBG_SSL, "Match %s on %s...\n", cn, hostname);
dot = strchr(hostname, '.');
if (dot == NULL) {
char *pnt = strchr(cn, '.');
/* hostname is not fully-qualified; unqualify the cn. */
if (pnt != NULL) {
*pnt = '\0';
}
}
else if (strncmp(cn, "*.", 2) == 0) {
hostname = dot + 1;
cn += 2;
}
return !strcasecmp(cn, hostname);
}
/* Check certificate identity. Returns zero if identity matches; 1 if
* identity does not match, or <0 if the certificate had no identity.
* If 'identity' is non-NULL, store the malloc-allocated identity in
* *identity. If 'server' is non-NULL, it must be the network address
* of the server in use, and identity must be NULL. */
static int check_identity(const char *hostname, gnutls_x509_crt cert,
char **identity)
{
char name[255];
unsigned int critical;
int ret, seq = 0;
int match = 0, found = 0;
size_t len;
do {
len = sizeof name;
ret = gnutls_x509_crt_get_subject_alt_name(cert, seq, name, &len,
&critical);
switch (ret) {
case GNUTLS_SAN_DNSNAME:
if (identity && !found) *identity = ne_strdup(name);
match = match_hostname(name, hostname);
found = 1;
break;
default:
break;
}
seq++;
} while (!match && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
/* Check against the commonName if no DNS alt. names were found,
* as per RFC3280. */
if (!found) {
seq = oid_find_highest_index(cert, 1, GNUTLS_OID_X520_COMMON_NAME);
if (seq >= 0) {
len = sizeof name;
name[0] = '\0';
ret = gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME,
seq, 0, name, &len);
if (ret == 0) {
if (identity) *identity = ne_strdup(name);
match = match_hostname(name, hostname);
}
} else {
return -1;
}
}
NE_DEBUG(NE_DBG_SSL, "Identity match: %s\n", match ? "good" : "bad");
return match ? 0 : 1;
}
/* Populate an ne_ssl_certificate structure from an X509 object. */
static ne_ssl_certificate *populate_cert(ne_ssl_certificate *cert,
gnutls_x509_crt x5)
{
cert->subj_dn.cert = x5;
cert->subj_dn.subject = 1;
cert->issuer_dn.cert = x5;
cert->issuer_dn.subject = 0;
cert->issuer = NULL;
cert->subject = x5;
cert->identity = NULL;
check_identity("", x5, &cert->identity);
return cert;
}
/* Returns a copy certificate of certificate SRC. */
static gnutls_x509_crt x509_crt_copy(gnutls_x509_crt src)
{
int ret;
size_t size;
gnutls_datum tmp;
gnutls_x509_crt dest;
if (gnutls_x509_crt_init(&dest) == 0) {
return NULL;
}
if (gnutls_x509_crt_export(src, GNUTLS_X509_FMT_DER, NULL, &size)
!= GNUTLS_E_SHORT_MEMORY_BUFFER) {
gnutls_x509_crt_deinit(dest);
return NULL;
}
tmp.data = ne_malloc(size);
ret = gnutls_x509_crt_export(src, GNUTLS_X509_FMT_DER, tmp.data, &size);
if (ret == 0) {
tmp.size = size;
ret = gnutls_x509_crt_import(dest, &tmp, GNUTLS_X509_FMT_DER);
}
if (ret) {
gnutls_x509_crt_deinit(dest);
dest = NULL;
}
ne_free(tmp.data);
return dest;
}
/* Duplicate a client certificate, which must be in the decrypted state. */
static ne_ssl_client_cert *dup_client_cert(const ne_ssl_client_cert *cc)
{
int ret;
ne_ssl_client_cert *newcc = ne_calloc(sizeof *newcc);
newcc->decrypted = 1;
ret = gnutls_x509_privkey_init(&newcc->pkey);
if (ret != 0) goto dup_error;
ret = gnutls_x509_privkey_cpy(newcc->pkey, cc->pkey);
if (ret != 0) goto dup_error;
newcc->cert.subject = x509_crt_copy(cc->cert.subject);
if (!newcc->cert.subject) goto dup_error;
if (cc->friendly_name) newcc->friendly_name = ne_strdup(cc->friendly_name);
populate_cert(&newcc->cert, newcc->cert.subject);
return newcc;
dup_error:
if (newcc->pkey) gnutls_x509_privkey_deinit(newcc->pkey);
if (newcc->cert.subject) gnutls_x509_crt_deinit(newcc->cert.subject);
ne_free(newcc);
return NULL;
}
void ne_ssl_set_clicert(ne_session *sess, const ne_ssl_client_cert *cc)
{
sess->client_cert = dup_client_cert(cc);
}
ne_ssl_context *ne_ssl_context_create(int flags)
{
ne_ssl_context *ctx = ne_malloc(sizeof *ctx);
gnutls_certificate_allocate_credentials(&ctx->cred);
return ctx;
}
int ne_ssl_context_keypair(ne_ssl_context *ctx,
const char *cert, const char *key)
{
gnutls_certificate_set_x509_key_file(ctx->cred, cert, key,
GNUTLS_X509_FMT_PEM);
return 0;
}
int ne_ssl_context_set_verify(ne_ssl_context *ctx, int required,
const char *ca_names, const char *verify_cas)
{
if (verify_cas) {
gnutls_certificate_set_x509_trust_file(ctx->cred, verify_cas,
GNUTLS_X509_FMT_PEM);
}
#warning argh
return 0;
}
void ne_ssl_context_destroy(ne_ssl_context *ctx)
{
gnutls_certificate_free_credentials(ctx->cred);
ne_free(ctx);
}
/* Return the certificate chain sent by the peer, or NULL on error. */
static ne_ssl_certificate *make_peers_chain(gnutls_session sock)
{
ne_ssl_certificate *current = NULL, *top = NULL;
const gnutls_datum *certs;
unsigned int n, count;
certs = gnutls_certificate_get_peers(sock, &count);
if (!certs) {
return NULL;
}
for (n = 0; n < count; n++) {
ne_ssl_certificate *cert = ne_malloc(sizeof *cert);
gnutls_x509_crt x5;
if (gnutls_x509_crt_init(&x5) ||
gnutls_x509_crt_import(x5, &certs[n], GNUTLS_X509_FMT_DER)) {
/* leak! */
return NULL;
}
populate_cert(cert, x5);
if (top == NULL) {
current = top = cert;
} else {
current->issuer = cert;
current = cert;
}
}
return top;
}
/* Verifies an SSL server certificate. */
static int check_certificate(ne_session *sess, gnutls_session sock,
ne_ssl_certificate *chain)
{
time_t before, after, now = time(NULL);
int ret, failures = 0;
before = gnutls_x509_crt_get_activation_time(chain->subject);
after = gnutls_x509_crt_get_expiration_time(chain->subject);
if (now < before)
failures |= NE_SSL_NOTYETVALID;
else if (now > after)
failures |= NE_SSL_EXPIRED;
ret = check_identity(sess->server.hostname, chain->subject, NULL);
if (ret < 0) {
ne_set_error(sess, _("Server certificate was missing commonName "
"attribute in subject name"));
return NE_ERROR;
} else if (ret > 0) {
failures |= NE_SSL_IDMISMATCH;
}
if (gnutls_certificate_verify_peers(sock)) {
failures |= NE_SSL_UNTRUSTED;
}
NE_DEBUG(NE_DBG_SSL, "Failures = %d\n", failures);
if (failures == 0) {
ret = NE_OK;
} else {
#warning TODO: set up error string
ret = NE_ERROR;
if (sess->ssl_verify_fn
&& sess->ssl_verify_fn(sess->ssl_verify_ud, failures, chain) == 0)
ret = NE_OK;
}
return ret;
}
/* Negotiate an SSL connection. */
int ne__negotiate_ssl(ne_request *req)
{
ne_session *const sess = ne_get_session(req);
ne_ssl_context *const ctx = sess->ssl_context;
ne_ssl_certificate *chain;
gnutls_session sock;
NE_DEBUG(NE_DBG_SSL, "Negotiating SSL connection.\n");
if (ne_sock_connect_ssl(sess->socket, ctx)) {
ne_set_error(sess, _("SSL negotiation failed: %s"),
ne_sock_error(sess->socket));
return NE_ERROR;
}
sock = ne__sock_sslsock(sess->socket);
chain = make_peers_chain(sock);
if (chain == NULL) {
ne_set_error(sess, _("Server did not send certificate chain"));
return NE_ERROR;
}
if (check_certificate(sess, sock, chain)) {
ne_ssl_cert_free(chain);
return NE_ERROR;
}
return NE_OK;
}
const ne_ssl_dname *ne_ssl_cert_issuer(const ne_ssl_certificate *cert)
{
return &cert->issuer_dn;
}
const ne_ssl_dname *ne_ssl_cert_subject(const ne_ssl_certificate *cert)
{
return &cert->subj_dn;
}
const ne_ssl_certificate *ne_ssl_cert_signedby(const ne_ssl_certificate *cert)
{
return cert->issuer;
}
const char *ne_ssl_cert_identity(const ne_ssl_certificate *cert)
{
return cert->identity;
}
void ne_ssl_context_trustcert(ne_ssl_context *ctx, const ne_ssl_certificate *cert)
{
gnutls_x509_crt certs = cert->subject;
gnutls_certificate_set_x509_trust(ctx->cred, &certs, 1);
}
void ne_ssl_trust_default_ca(ne_session *sess)
{
#warning incomplete
}
/* Read the contents of file FILENAME into *DATUM. */
static int read_to_datum(const char *filename, gnutls_datum *datum)
{
FILE *f = fopen(filename, "r");
ne_buffer *buf;
char tmp[4192];
size_t len;
if (!f) {
return -1;
}
buf = ne_buffer_ncreate(8192);
while ((len = fread(tmp, 1, sizeof tmp, f)) > 0) {
ne_buffer_append(buf, tmp, len);
}
if (!feof(f)) {
ne_buffer_destroy(buf);
return -1;
}
datum->size = ne_buffer_size(buf);
datum->data = ne_buffer_finish(buf);
return 0;
}
/* Parses a PKCS#12 structure and loads the certificate, private key
* and friendly name if possible. Returns zero on success, non-zero
* on error. */
static int pkcs12_parse(gnutls_pkcs12 p12, gnutls_x509_privkey *pkey,
gnutls_x509_crt *x5, char **friendly_name,
const char *password)
{
gnutls_pkcs12_bag bag = NULL;
int i, j, ret = 0;
for (i = 0; ret == 0; ++i) {
if (bag) gnutls_pkcs12_bag_deinit(bag);
ret = gnutls_pkcs12_bag_init(&bag);
if (ret < 0) continue;
ret = gnutls_pkcs12_get_bag(p12, i, bag);
if (ret < 0) continue;
gnutls_pkcs12_bag_decrypt(bag, password == NULL ? "" : password);
for (j = 0; ret == 0 && j < gnutls_pkcs12_bag_get_count(bag); ++j) {
gnutls_pkcs12_bag_type type;
gnutls_datum data;
if (friendly_name && *friendly_name == NULL) {
char *name;
gnutls_pkcs12_bag_get_friendly_name(bag, j, &name);
if (name) {
if (name[0] == '.') name++; /* weird GnuTLS bug? */
*friendly_name = ne_strdup(name);
}
}
type = gnutls_pkcs12_bag_get_type(bag, j);
switch (type) {
case GNUTLS_BAG_PKCS8_KEY:
case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY:
gnutls_x509_privkey_init(pkey);
ret = gnutls_pkcs12_bag_get_data(bag, j, &data);
if (ret < 0) continue;
ret = gnutls_x509_privkey_import_pkcs8(*pkey, &data,
GNUTLS_X509_FMT_DER,
password,
0);
if (ret < 0) continue;
break;
case GNUTLS_BAG_CERTIFICATE:
gnutls_x509_crt_init(x5);
ret = gnutls_pkcs12_bag_get_data(bag, j, &data);
if (ret < 0) continue;
ret = gnutls_x509_crt_import(*x5, &data, GNUTLS_X509_FMT_DER);
if (ret < 0) continue;
break;
default:
break;
}
}
}
/* Make sure last bag is freed */
if (bag) gnutls_pkcs12_bag_deinit(bag);
/* Free in case of error */
if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
if (*x5) gnutls_x509_crt_deinit(*x5);
if (*pkey) gnutls_x509_privkey_deinit(*pkey);
if (friendly_name && *friendly_name) ne_free(*friendly_name);
}
if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) ret = 0;
return ret;
}
ne_ssl_client_cert *ne_ssl_clicert_read(const char *filename)
{
int ret;
gnutls_datum data;
gnutls_pkcs12 p12;
ne_ssl_client_cert *cc;
char *friendly_name = NULL;
gnutls_x509_crt cert = NULL;
gnutls_x509_privkey pkey = NULL;
if (read_to_datum(filename, &data))
return NULL;
if (gnutls_pkcs12_init(&p12) != 0) {
return NULL;
}
ret = gnutls_pkcs12_import(p12, &data, GNUTLS_X509_FMT_DER, 0);
ne_free(data.data);
if (ret < 0) {
gnutls_pkcs12_deinit(p12);
return NULL;
}
ret = pkcs12_parse(p12, &pkey, &cert, &friendly_name, NULL);
if (gnutls_pkcs12_verify_mac(p12, "") == 0) {
cc = ne_calloc(sizeof *cc);
cc->pkey = pkey;
cc->decrypted = 1;
cc->friendly_name = friendly_name;
populate_cert(&cc->cert, cert);
gnutls_pkcs12_deinit(p12);
cc->p12 = NULL;
return cc;
} else {
if (ret == 0) {
cc = ne_calloc(sizeof *cc);
cc->friendly_name = friendly_name;
cc->p12 = p12;
return cc;
} else {
gnutls_pkcs12_deinit(p12);
return NULL;
}
}
}
int ne_ssl_clicert_encrypted(const ne_ssl_client_cert *cc)
{
return !cc->decrypted;
}
int ne_ssl_clicert_decrypt(ne_ssl_client_cert *cc, const char *password)
{
int ret;
gnutls_x509_crt cert = NULL;
gnutls_x509_privkey pkey = NULL;
if (gnutls_pkcs12_verify_mac(cc->p12, password) != 0) {
return -1;
}
ret = pkcs12_parse(cc->p12, &pkey, &cert, NULL, password);
if (ret < 0)
return ret;
gnutls_pkcs12_deinit(cc->p12);
populate_cert(&cc->cert, cert);
cc->pkey = pkey;
cc->decrypted = 1;
cc->p12 = NULL;
return 0;
}
const ne_ssl_certificate *ne_ssl_clicert_owner(const ne_ssl_client_cert *cc)
{
return &cc->cert;
}
const char *ne_ssl_clicert_name(ne_ssl_client_cert *ccert)
{
return ccert->friendly_name;
}
ne_ssl_certificate *ne_ssl_cert_read(const char *filename)
{
int ret;
gnutls_datum data;
gnutls_x509_crt x5;
if (read_to_datum(filename, &data))
return NULL;
if (gnutls_x509_crt_init(&x5) != 0)
return NULL;
ret = gnutls_x509_crt_import(x5, &data, GNUTLS_X509_FMT_PEM);
ne_free(data.data);
if (ret < 0) {
gnutls_x509_crt_deinit(x5);
return NULL;
}
return populate_cert(ne_calloc(sizeof(struct ne_ssl_certificate_s)), x5);
}
int ne_ssl_cert_write(const ne_ssl_certificate *cert, const char *filename)
{
unsigned char buffer[10*1024];
int len = sizeof buffer;
FILE *fp = fopen(filename, "w");
if (fp == NULL) return -1;
if (gnutls_x509_crt_export(cert->subject, GNUTLS_X509_FMT_PEM, buffer,
&len) < 0) {
fclose(fp);
return -1;
}
if (fwrite(buffer, len, 1, fp) != 1) {
fclose(fp);
return -1;
}
if (fclose(fp) != 0)
return -1;
return 0;
}
void ne_ssl_cert_free(ne_ssl_certificate *cert)
{
gnutls_x509_crt_deinit(cert->subject);
if (cert->identity) ne_free(cert->identity);
if (cert->issuer) ne_ssl_cert_free(cert->issuer);
ne_free(cert);
}
int ne_ssl_cert_cmp(const ne_ssl_certificate *c1, const ne_ssl_certificate *c2)
{
char digest1[NE_SSL_DIGESTLEN], digest2[NE_SSL_DIGESTLEN];
if (ne_ssl_cert_digest(c1, digest1) || ne_ssl_cert_digest(c2, digest2)) {
return -1;
}
return strcmp(digest1, digest2);
}
/* The certificate import/export format is the base64 encoding of the
* raw DER; PEM without the newlines and wrapping. */
ne_ssl_certificate *ne_ssl_cert_import(const char *data)
{
int ret;
size_t len;
unsigned char *der;
gnutls_datum buffer = { NULL, 0 };
gnutls_x509_crt x5;
if (gnutls_x509_crt_init(&x5) != 0)
return NULL;
/* decode the base64 to get the raw DER representation */
len = ne_unbase64(data, &der);
if (len == 0) return NULL;
buffer.data = der;
buffer.size = len;
ret = gnutls_x509_crt_import(x5, &buffer, GNUTLS_X509_FMT_DER);
ne_free(der);
if (ret < 0) {
gnutls_x509_crt_deinit(x5);
return NULL;
}
return populate_cert(ne_calloc(sizeof(struct ne_ssl_certificate_s)), x5);
}
char *ne_ssl_cert_export(const ne_ssl_certificate *cert)
{
unsigned char *der;
size_t len = 0;
char *ret;
/* find the length of the DER encoding. */
if (gnutls_x509_crt_export(cert->subject, GNUTLS_X509_FMT_DER, NULL, &len) !=
GNUTLS_E_SHORT_MEMORY_BUFFER) {
return NULL;
}
der = ne_malloc(len);
if (gnutls_x509_crt_export(cert->subject, GNUTLS_X509_FMT_DER, der, &len)) {
ne_free(der);
return NULL;
}
ret = ne_base64(der, len);
ne_free(der);
return ret;
}
int ne_ssl_cert_digest(const ne_ssl_certificate *cert, char *digest)
{
int j, len = 20;
char sha1[20], *p;
if (gnutls_x509_crt_get_fingerprint(cert->subject, GNUTLS_DIG_SHA,
sha1, &len) < 0)
return -1;
for (j = 0, p = digest; j < 20; j++) {
*p++ = NE_HEX2ASC((sha1[j] >> 4) & 0x0f);
*p++ = NE_HEX2ASC(sha1[j] & 0x0f);
*p++ = ':';
}
*--p = '\0';
return 0;
}

View File

@ -725,7 +725,7 @@ int ne_lock(ne_session *sess, struct ne_lock *lock)
ne_buffer_destroy(body);
ne_buffer_destroy(ctx.cdata);
parse_failed = !ne_xml_valid(parser);
parse_failed = ne_xml_failed(parser);
if (ret == NE_OK && ne_get_status(req)->klass == 2) {
if (ctx.token == NULL) {
@ -780,9 +780,13 @@ int ne_lock_refresh(ne_session *sess, struct ne_lock *lock)
ne_request *req = ne_request_create(sess, "LOCK", lock->uri.path);
ne_xml_parser *parser = ne_xml_create();
int ret, parse_failed;
struct lock_ctx ctx;
memset(&ctx, 0, sizeof ctx);
ctx.cdata = ne_buffer_create();
/* Handle the response and update *lock appropriately. */
ne_xml_push_handler(parser, lk_startelm, NULL, lk_endelm, lock);
ne_xml_push_handler(parser, lk_startelm, lk_cdata, lk_endelm, &ctx);
ne_add_response_body_reader(req, ne_accept_2xx,
ne_xml_parse_v, parser);
@ -797,7 +801,7 @@ int ne_lock_refresh(ne_session *sess, struct ne_lock *lock)
ret = ne_request_dispatch(req);
parse_failed = !ne_xml_valid(parser);
parse_failed = ne_xml_failed(parser);
if (ret == NE_OK && ne_get_status(req)->klass == 2) {
if (parse_failed) {
@ -812,6 +816,7 @@ int ne_lock_refresh(ne_session *sess, struct ne_lock *lock)
ret = NE_ERROR;
}
ne_buffer_destroy(ctx.cdata);
ne_request_destroy(req);
ne_xml_destroy(parser);

View File

@ -218,10 +218,8 @@ static int match_hostname(char *cn, const char *hostname)
/* Check certificate identity. Returns zero if identity matches; 1 if
* identity does not match, or <0 if the certificate had no identity.
* If 'identity' is non-NULL, store the malloc-allocated identity in
* *identity. If 'server' is non-NULL, it must be the network address
* of the server in use, and identity must be NULL. */
static int check_identity(const char *hostname, X509 *cert, char **identity,
const ne_inet_addr *server)
* *identity. */
static int check_identity(const char *hostname, X509 *cert, char **identity)
{
STACK_OF(GENERAL_NAME) *names;
int match = 0, found = 0;
@ -241,7 +239,7 @@ static int check_identity(const char *hostname, X509 *cert, char **identity,
match = match_hostname(name, hostname);
ne_free(name);
found = 1;
} else if (nm->type == GEN_IPADD && server) {
} else if (nm->type == GEN_IPADD) {
/* compare IP address with server IP address. */
ne_inet_addr *ia;
if (nm->d.ip->length == 4)
@ -252,7 +250,10 @@ static int check_identity(const char *hostname, X509 *cert, char **identity,
ia = NULL;
/* ne_iaddr_make returns NULL if address type is unsupported */
if (ia != NULL) { /* address type was supported. */
match = ne_iaddr_cmp(server, ia) == 0;
char buf[128];
match = strcmp(hostname,
ne_iaddr_print(ia, buf, sizeof buf)) == 0;
found = 1;
ne_iaddr_free(ia);
} else {
@ -295,7 +296,8 @@ static int check_identity(const char *hostname, X509 *cert, char **identity,
ne_free(name);
}
NE_DEBUG(NE_DBG_SSL, "Identity match: %s\n", match ? "good" : "bad");
NE_DEBUG(NE_DBG_SSL, "Identity match for '%s': %s\n", hostname,
match ? "good" : "bad");
return match ? 0 : 1;
}
@ -308,7 +310,7 @@ static ne_ssl_certificate *populate_cert(ne_ssl_certificate *cert, X509 *x5)
cert->subject = x5;
/* Retrieve the cert identity; pass a dummy hostname to match. */
cert->identity = NULL;
check_identity("", x5, &cert->identity, NULL);
check_identity("", x5, &cert->identity);
return cert;
}
@ -323,7 +325,7 @@ static ne_ssl_certificate *make_chain(STACK_OF(X509) *chain)
for (n = 0; n < count; n++) {
ne_ssl_certificate *cert = ne_malloc(sizeof *cert);
populate_cert(cert, X509_dup(sk_X509_value(chain, n)));
#if NE_DEBUGGING
#ifdef NE_DEBUGGING
if (ne_debug_mask & NE_DBG_SSL) {
fprintf(ne_debug_stream, "Cert #%d:\n", n);
X509_print_fp(ne_debug_stream, cert->subject);
@ -357,8 +359,7 @@ static int check_certificate(ne_session *sess, SSL *ssl, ne_ssl_certificate *cha
/* Check certificate was issued to this server; pass network
* address of server if a proxy is not in use. */
ret = check_identity(sess->server.hostname, cert, NULL,
sess->use_proxy ? NULL : sess->server.current);
ret = check_identity(sess->server.hostname, cert, NULL);
if (ret < 0) {
ne_set_error(sess, _("Server certificate was missing commonName "
"attribute in subject name"));
@ -481,18 +482,56 @@ void ne_ssl_set_clicert(ne_session *sess, const ne_ssl_client_cert *cc)
sess->client_cert = dup_client_cert(cc);
}
ne_ssl_context *ne_ssl_context_create(void)
ne_ssl_context *ne_ssl_context_create(int mode)
{
ne_ssl_context *ctx = ne_malloc(sizeof *ctx);
ctx->ctx = SSL_CTX_new(SSLv23_client_method());
ctx->sess = NULL;
/* set client cert callback. */
SSL_CTX_set_client_cert_cb(ctx->ctx, provide_client_cert);
/* enable workarounds for buggy SSL server implementations */
SSL_CTX_set_options(ctx->ctx, SSL_OP_ALL);
ne_ssl_context *ctx = ne_calloc(sizeof *ctx);
if (mode == NE_SSL_CTX_CLIENT) {
ctx->ctx = SSL_CTX_new(SSLv23_client_method());
ctx->sess = NULL;
/* set client cert callback. */
SSL_CTX_set_client_cert_cb(ctx->ctx, provide_client_cert);
/* enable workarounds for buggy SSL server implementations */
SSL_CTX_set_options(ctx->ctx, SSL_OP_ALL);
} else if (mode == NE_SSL_CTX_SERVER) {
ctx->ctx = SSL_CTX_new(SSLv23_server_method());
} else {
ctx->ctx = SSL_CTX_new(SSLv2_server_method());
}
return ctx;
}
int ne_ssl_context_keypair(ne_ssl_context *ctx, const char *cert,
const char *key)
{
int ret;
ret = SSL_CTX_use_PrivateKey_file(ctx->ctx, key, SSL_FILETYPE_PEM);
if (ret == 1) {
ret = SSL_CTX_use_certificate_file(ctx->ctx, cert, SSL_FILETYPE_PEM);
}
return ret == 1 ? 0 : -1;
}
int ne_ssl_context_set_verify(ne_ssl_context *ctx,
int required,
const char *ca_names,
const char *verify_cas)
{
if (required) {
SSL_CTX_set_verify(ctx->ctx, SSL_VERIFY_PEER |
SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
}
if (ca_names) {
SSL_CTX_set_client_CA_list(ctx->ctx,
SSL_load_client_CA_file(ca_names));
}
if (verify_cas) {
SSL_CTX_load_verify_locations(ctx->ctx, verify_cas, NULL);
}
return 0;
}
void ne_ssl_context_destroy(ne_ssl_context *ctx)
{
SSL_CTX_free(ctx->ctx);
@ -502,11 +541,11 @@ void ne_ssl_context_destroy(ne_ssl_context *ctx)
}
/* For internal use only. */
int ne_negotiate_ssl(ne_request *req)
int ne__negotiate_ssl(ne_request *req)
{
ne_session *sess = ne_get_session(req);
ne_ssl_context *ctx = sess->ssl_context;
ne_ssl_socket *sock;
SSL *ssl;
STACK_OF(X509) *chain;
int freechain = 0; /* non-zero if chain should be free'd. */
@ -527,12 +566,12 @@ int ne_negotiate_ssl(ne_request *req)
return NE_ERROR;
}
sock = ne_sock_sslsock(sess->socket);
ssl = ne__sock_sslsock(sess->socket);
chain = SSL_get_peer_cert_chain(sock->ssl);
chain = SSL_get_peer_cert_chain(ssl);
/* For an SSLv2 connection, the cert chain will always be NULL. */
if (chain == NULL) {
X509 *cert = SSL_get_peer_certificate(sock->ssl);
X509 *cert = SSL_get_peer_certificate(ssl);
if (cert) {
chain = sk_X509_new_null();
sk_X509_push(chain, cert);
@ -561,7 +600,7 @@ int ne_negotiate_ssl(ne_request *req)
if (freechain) sk_X509_free(chain); /* no longer need the chain */
if (check_certificate(sess, sock->ssl, cert)) {
if (check_certificate(sess, ssl, cert)) {
NE_DEBUG(NE_DBG_SSL, "SSL certificate checks failed: %s\n",
sess->error);
ne_ssl_cert_free(cert);
@ -573,12 +612,12 @@ int ne_negotiate_ssl(ne_request *req)
if (!ctx->sess) {
/* store the session. */
ctx->sess = SSL_get1_session(sock->ssl);
ctx->sess = SSL_get1_session(ssl);
}
if (sess->notify_cb) {
sess->notify_cb(sess->notify_ud, ne_conn_secure,
SSL_get_version(sock->ssl));
SSL_get_version(ssl));
}
return NE_OK;
@ -604,7 +643,7 @@ const char *ne_ssl_cert_identity(const ne_ssl_certificate *cert)
return cert->identity;
}
void ne_ssl_ctx_trustcert(ne_ssl_context *ctx, const ne_ssl_certificate *cert)
void ne_ssl_context_trustcert(ne_ssl_context *ctx, const ne_ssl_certificate *cert)
{
X509_STORE *store = SSL_CTX_get_cert_store(ctx->ctx);

View File

@ -67,14 +67,16 @@ struct ne_session_s {
char *scheme;
struct host_info server, proxy;
/* application-provided address list */
const ne_inet_addr **addrlist;
size_t numaddrs, curaddr;
/* Settings */
unsigned int use_proxy:1; /* do we have a proxy server? */
unsigned int no_persist:1; /* set to disable persistent connections */
unsigned int use_ssl:1; /* whether a secure connection is required */
unsigned int in_connect:1; /* doing a proxy CONNECT */
int expect100_works; /* known state of 100-continue support */
ne_progress progress_cb;
void *progress_ud;
@ -88,7 +90,7 @@ struct ne_session_s {
char *user_agent; /* full User-Agent: header field */
#ifdef NEON_SSL
#ifdef NE_HAVE_SSL
ne_ssl_client_cert *client_cert;
ne_ssl_certificate *server_cert;
ne_ssl_context *ssl_context;
@ -105,17 +107,15 @@ struct ne_session_s {
char error[BUFSIZ];
};
/* Pushes block of 'count' bytes at 'buf'. Returns non-zero on
* error. */
typedef int (*ne_push_fn)(void *userdata, const char *buf, size_t count);
/* Pulls the request body for the given request, passing blocks to the
* given callback.
*/
int ne_pull_request_body(ne_request *req, ne_push_fn fn, void *ud);
* given callback. */
int ne__pull_request_body(ne_request *req, ne_push_fn fn, void *ud);
/* Do the SSL negotiation. */
int ne_negotiate_ssl(ne_request *req);
/* 0.24.x hack to fix ne_compress layer problems */
void ne_kill_pre_send(ne_session *sess, ne_pre_send_fn fn, void *userdata);
int ne__negotiate_ssl(ne_request *req);
#endif /* HTTP_PRIVATE_H */

View File

@ -1,6 +1,7 @@
/*
SSL interface definitions internal to neon.
Copyright (C) 2003, Joe Orton <joe@manyfish.co.uk>
Copyright (C) 2003, 2004, Joe Orton <joe@manyfish.co.uk>
Copyright (C) 2004, Aleix Conchillo Flaque <aleix@member.fsf.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@ -25,24 +26,38 @@
#ifndef NE_PRIVSSL_H
#define NE_PRIVSSL_H
/* This is the private interface between ne_socket and ne_openssl. */
/* This is the private interface between ne_socket, ne_gnutls and
* ne_openssl. */
#ifdef NEON_SSL
#include "ne_ssl.h"
#include "ne_socket.h"
#ifdef HAVE_OPENSSL
#include <openssl/ssl.h>
#include "ne_ssl.h"
/* SSL context */
struct ne_ssl_context_s {
SSL_CTX *ctx;
SSL_SESSION *sess;
};
struct ne_ssl_socket_s {
SSL *ssl;
typedef SSL *ne_ssl_socket;
#endif /* HAVE_OPENSSL */
#ifdef HAVE_GNUTLS
#include <gnutls/gnutls.h>
struct ne_ssl_context_s {
gnutls_certificate_credentials cred;
/* TODO: store session here too */
};
#endif /* NEON_SSL */
typedef gnutls_session ne_ssl_socket;
#endif
#endif /* HAVE_GNUTLS */
ne_ssl_socket ne__sock_sslsock(ne_socket *sock);
#endif /* NE_PRIVSSL_H */

View File

@ -33,6 +33,7 @@
#include "ne_props.h"
#include "ne_basic.h"
#include "ne_locks.h"
#include "ne_i18n.h"
/* don't store flat props with a value > 10K */
#define MAX_FLATPROP_LEN (102400)
@ -83,11 +84,12 @@ struct propstat {
/* Results set. */
struct ne_prop_result_set_s {
struct propstat *pstats;
int numpstats;
int numpstats, counter;
void *private;
char *href;
};
#define MAX_PROP_COUNTER (1024)
static int
startelm(void *userdata, int state, const char *name, const char *nspace,
@ -141,7 +143,7 @@ static int propfind(ne_propfind_handler *handler,
if (ret == NE_OK && ne_get_status(req)->klass != 2) {
ret = NE_ERROR;
} else if (!ne_xml_valid(handler->parser)) {
} else if (ne_xml_failed(handler->parser)) {
ne_set_error(handler->sess, "%s", ne_xml_get_error(handler->parser));
ret = NE_ERROR;
}
@ -220,7 +222,7 @@ int ne_proppatch(ne_session *sess, const char *uri,
ne_set_request_body_buffer(req, body->data, ne_buffer_size(body));
ne_add_request_header(req, "Content-Type", NE_XML_MEDIA_TYPE);
#ifdef USE_DAV_LOCKS
#ifdef NE_HAVE_DAV
ne_lock_using_resource(req, uri, NE_DEPTH_ZERO);
#endif
@ -360,9 +362,15 @@ static void *start_response(void *userdata, const char *href)
static void *start_propstat(void *userdata, void *response)
{
ne_prop_result_set *set = response;
int n;
ne_propfind_handler *hdl = userdata;
struct propstat *pstat;
int n;
if (++hdl->current->counter == MAX_PROP_COUNTER) {
ne_xml_set_error(hdl->parser, _("Response exceeds maximum property count"));
return NULL;
}
n = set->numpstats;
set->pstats = ne_realloc(set->pstats, sizeof(struct propstat) * (n+1));
set->numpstats = n+1;
@ -396,6 +404,13 @@ static int startelm(void *userdata, int parent,
return ELM_flatprop;
}
/* Enforce maximum number of properties per resource to prevent a
* memory exhaustion attack by a hostile server. */
if (++hdl->current->counter == MAX_PROP_COUNTER) {
ne_xml_set_error(hdl->parser, _("Response exceeds maximum property count"));
return NE_XML_ABORT;
}
/* Add a property to this propstat */
n = pstat->numprops;

View File

@ -26,10 +26,6 @@
#include "config.h"
#include <sys/types.h>
#include <sys/stat.h>
#ifdef __EMX__
#include <sys/select.h>
#endif
#ifdef HAVE_LIMITS_H
#include <limits.h> /* for UINT_MAX etc */
@ -90,6 +86,33 @@ struct body_reader {
struct body_reader *next;
};
#ifdef NE_LFS
#define ne_lseek lseek64
typedef off64_t ne_off_t;
#define FMT_NE_OFF_T NE_FMT_OFF64_T
#if defined(LONG_LONG_MAX) && !defined(LLONG_MAX)
#define LLONG_MAX LONG_LONG_MAX
#endif
#define NE_OFFT_MAX LLONG_MAX
#ifdef HAVE_STRTOLL
#define ne_strtoff strtoll
#else
#define ne_strtoff strtoq
#endif
#else /* !NE_LFS */
typedef off_t ne_off_t;
#define ne_lseek lseek
#define FMT_NE_OFF_T NE_FMT_OFF_T
#define NE_OFFT_MAX LONG_MAX
#if SIZEOF_OFF_T > SIZEOF_LONG && defined(HAVE_STRTOLL)
#define ne_strtoff strtoll
#elif SIZEOF_OFF_T > SIZEOF_LONG && defined(HAVE_STRTOQ)
#define ne_strtoff strtoq
#else
#define ne_strtoff strtol
#endif
#endif /* NE_LFS */
struct ne_request_s {
char *method, *uri; /* method and Request-URI */
@ -99,16 +122,23 @@ struct ne_request_s {
ne_provide_body body_cb;
void *body_ud;
/* Comes from either an fd or a buffer. */
/* Request body source: file or buffer (if not callback). */
union {
int fd;
struct {
int fd;
ne_off_t offset, length;
ne_off_t remain; /* remaining bytes to send. */
} file;
struct {
/* length bytes @ buffer = whole body.
* remain bytes @ pnt = remaining bytes to send */
const char *buffer, *pnt;
size_t left;
size_t length, remain;
} buf;
} body;
size_t body_size, body_progress;
ne_off_t body_length; /* length of request body */
ne_off_t body_progress; /* number of bytes of body sent so far */
/* temporary store for response lines. */
char respbuf[BUFSIZ];
@ -117,17 +147,25 @@ struct ne_request_s {
/* The transfer encoding types */
struct ne_response {
int length; /* Response entity-body content-length */
size_t left; /* Bytes left to read */
size_t chunk_left; /* Bytes of chunk left to read */
size_t total; /* total bytes read so far. */
/* how the message length is detemined: */
enum {
R_TILLEOF = 0, /* read till eof */
R_NO_BODY, /* implicitly no body (HEAD, 204, 205, 304) */
R_NO_BODY, /* implicitly no body (HEAD, 204, 304) */
R_CHUNKED, /* using chunked transfer-encoding */
R_CLENGTH /* using given content-length */
} mode;
union {
/* clen: used if mode == R_CLENGTH; total and bytes
* remaining to be read of response body. */
struct {
ne_off_t total, remain;
} clen;
/* chunk: used if mode == R_CHUNKED; total and bytes
* remaining to be read of current chunk */
struct {
size_t total, remain;
} chunk;
} body;
ne_off_t progress; /* number of bytes read of response */
} resp;
/* List of callbacks which are passed response headers */
@ -316,25 +354,6 @@ void ne_hook_destroy_session(ne_session *sess,
ADD_HOOK(sess->destroy_sess_hooks, fn, userdata);
}
/* 0.24.x hack to fix ne_compress layer problems */
void ne_kill_pre_send(ne_session *sess, ne_pre_send_fn fn, void *userdata)
{
struct hook **last, *hk;
last = &sess->pre_send_hooks;
hk = *last;
while (hk) {
if (hk->fn == (void_fn)fn && hk->userdata == userdata) {
*last = hk->next;
ne_free(hk);
return;
}
last = &hk->next;
hk = *last;
}
}
void ne_set_session_private(ne_session *sess, const char *id, void *userdata)
{
add_hook(&sess->private, id, NULL, userdata);
@ -350,16 +369,16 @@ static ssize_t body_string_send(void *userdata, char *buffer, size_t count)
ne_request *req = userdata;
if (count == 0) {
req->body.buf.left = req->body_size;
req->body.buf.remain = req->body.buf.length;
req->body.buf.pnt = req->body.buf.buffer;
} else {
/* if body_left == 0 we fall through and return 0. */
if (req->body.buf.left < count)
count = req->body.buf.left;
if (req->body.buf.remain < count)
count = req->body.buf.remain;
memcpy(buffer, req->body.buf.pnt, count);
req->body.buf.pnt += count;
req->body.buf.left -= count;
req->body.buf.remain -= count;
}
return count;
@ -370,16 +389,26 @@ static ssize_t body_fd_send(void *userdata, char *buffer, size_t count)
ne_request *req = userdata;
if (count) {
return read(req->body.fd, buffer, count);
if (req->body.file.remain == 0)
return 0;
if ((off_t)count > req->body.file.remain)
count = req->body.file.remain;
return read(req->body.file.fd, buffer, count);
} else {
/* rewind since we may have to send it again */
return lseek(req->body.fd, SEEK_SET, 0);
/* rewind for next send. */
if (ne_lseek(req->body.file.fd, req->body.file.offset, SEEK_SET)
== req->body.file.offset) {
req->body.file.remain = req->body.file.length;
return 0;
} else {
return -1;
}
}
}
/* Pulls the request body from the source and pushes it to the given
* callback. Returns 0 on success, or NE_* code */
int ne_pull_request_body(ne_request *req, ne_push_fn fn, void *ud)
int ne__pull_request_body(ne_request *req, ne_push_fn fn, void *ud)
{
int ret = 0;
char buffer[BUFSIZ];
@ -419,7 +448,7 @@ static int send_with_progress(void *userdata, const char *data, size_t n)
if (ret == 0) {
req->body_progress += n;
req->session->progress_cb(req->session->progress_ud,
req->body_progress, req->body_size);
req->body_progress, req->body_length);
}
return ret;
@ -434,10 +463,10 @@ static int send_request_body(ne_request *req)
if (req->session->progress_cb) {
/* with progress callbacks. */
req->body_progress = 0;
ret = ne_pull_request_body(req, send_with_progress, req);
ret = ne__pull_request_body(req, send_with_progress, req);
} else {
/* without progress callbacks. */
ret = ne_pull_request_body(req, (ne_push_fn)ne_sock_fullwrite,
ret = ne__pull_request_body(req, (ne_push_fn)ne_sock_fullwrite,
req->session->socket);
}
@ -457,7 +486,8 @@ static void add_fixed_headers(ne_request *req)
* harder to get a persistent connection, except if using a proxy
* as per 2068 sec 19.7.1. Always add TE: trailers since those
* are understood. */
if (!req->session->is_http11 && !req->session->use_proxy) {
if (!req->session->no_persist && !req->session->is_http11
&& !req->session->use_proxy) {
ne_buffer_zappend(req->headers,
"Keep-Alive: " EOL
"Connection: TE, Keep-Alive" EOL
@ -487,7 +517,8 @@ static void te_hdr_handler(void *userdata, const char *value)
{
struct ne_response *resp = userdata;
resp->mode = R_CHUNKED;
resp->mode = R_CHUNKED;
resp->body.chunk.remain = 0;
}
/* Handler for the "Connection" response header */
@ -504,10 +535,10 @@ static void connection_hdr_handler(void *userdata, const char *value)
static void clength_hdr_handler(void *userdata, const char *value)
{
struct ne_response *resp = userdata;
size_t len = strtoul(value, NULL, 10);
if (len != ULONG_MAX && resp->mode == R_TILLEOF) {
ne_off_t len = ne_strtoff(value, NULL, 10);
if (len != NE_OFFT_MAX && len >= 0 && resp->mode == R_TILLEOF) {
resp->mode = R_CLENGTH;
resp->length = len;
resp->body.clen.total = resp->body.clen.remain = len;
}
}
@ -560,47 +591,66 @@ ne_request *ne_request_create(ne_session *sess,
return req;
}
static void set_body_size(ne_request *req, size_t size)
/* Set the request body length to 'length' */
static void set_body_length(ne_request *req, ne_off_t length)
{
req->body_size = size;
ne_print_request_header(req, "Content-Length", "%" NE_FMT_SIZE_T, size);
req->body_length = length;
ne_print_request_header(req, "Content-Length", "%" FMT_NE_OFF_T, length);
}
void ne_set_request_body_buffer(ne_request *req, const char *buffer,
size_t size)
{
req->body.buf.buffer = buffer;
req->body.buf.length = size;
req->body_cb = body_string_send;
req->body_ud = req;
set_body_size(req, size);
set_body_length(req, size);
}
void ne_set_request_body_provider(ne_request *req, size_t bodysize,
void ne_set_request_body_provider(ne_request *req, off_t bodysize,
ne_provide_body provider, void *ud)
{
req->body_cb = provider;
req->body_ud = ud;
set_body_size(req, bodysize);
set_body_length(req, bodysize);
}
int ne_set_request_body_fd(ne_request *req, int fd)
void ne_set_request_body_fd(ne_request *req, int fd,
off_t offset, off_t length)
{
struct stat bodyst;
/* Get file length */
if (fstat(fd, &bodyst) < 0) {
char err[200];
ne_strerror(errno, err, sizeof err);
ne_set_error(req->session, _("Could not determine file length: %s"),
err);
NE_DEBUG(NE_DBG_HTTP, "Stat failed: %s\n", err);
return -1;
}
req->body.fd = fd;
req->body.file.fd = fd;
req->body.file.offset = offset;
req->body.file.length = length;
req->body_cb = body_fd_send;
req->body_ud = req;
set_body_size(req, bodyst.st_size);
return 0;
set_body_length(req, length);
}
#ifdef NE_LFS
void ne_set_request_body_fd64(ne_request *req, int fd,
off64_t offset, off64_t length)
{
req->body.file.fd = fd;
req->body.file.offset = offset;
req->body.file.length = length;
req->body_cb = body_fd_send;
req->body_ud = req;
set_body_length(req, length);
}
void ne_set_request_body_provider64(ne_request *req, off64_t bodysize,
ne_provide_body provider, void *ud)
{
req->body_cb = provider;
req->body_ud = ud;
set_body_length(req, bodysize);
}
#endif
void ne_set_request_expect100(ne_request *req, int flag)
{
req->use_expect100 = flag;
}
void ne_add_request_header(ne_request *req, const char *name,
@ -707,34 +757,33 @@ void ne_request_destroy(ne_request *req)
}
/* Reads a block of the response into buffer, which is of size buflen.
* Returns number of bytes read, 0 on end-of-response, or NE_* on error.
* TODO?: only make one actual read() call in here...
*/
/* Reads a block of the response into BUFFER, which is of size
* *BUFLEN. Returns zero on success or non-zero on error. On
* success, *BUFLEN is updated to be the number of bytes read into
* BUFFER (which will be 0 to indicate the end of the repsonse). On
* error, the connection is closed and the session error string is
* set. */
static int read_response_block(ne_request *req, struct ne_response *resp,
char *buffer, size_t *buflen)
{
ne_socket *const sock = req->session->socket;
size_t willread;
ssize_t readlen;
ne_socket *sock = req->session->socket;
switch (resp->mode) {
case R_CHUNKED:
/* We are doing a chunked transfer-encoding.
* It goes: `SIZE CRLF CHUNK CRLF SIZE CRLF CHUNK CRLF ...'
* ended by a `CHUNK CRLF 0 CRLF', a 0-sized chunk.
* The slight complication is that we have to cope with
* partial reads of chunks.
* For this reason, resp.chunk_left contains the number of
* bytes left to read in the current chunk.
*/
if (resp->chunk_left == 0) {
unsigned long int chunk_len;
/* Chunked transfer-encoding: chunk syntax is "SIZE CRLF CHUNK
* CRLF SIZE CRLF CHUNK CRLF ..." followed by zero-length
* chunk: "CHUNK CRLF 0 CRLF". resp.chunk.remain contains the
* number of bytes left to read in the current chunk. */
if (resp->body.chunk.remain == 0) {
unsigned long chunk_len;
char *ptr;
/* We are at the start of a new chunk. */
NE_DEBUG(NE_DBG_HTTP, "New chunk.\n");
/* The start of a new chunk. */
SOCK_ERR(req, ne_sock_readline(sock, buffer, *buflen),
_("Could not read chunk size"));
NE_DEBUG(NE_DBG_HTTP, "[Chunk Size] < %s", buffer);
NE_DEBUG(NE_DBG_HTTP, "[chunk] < %s", buffer);
chunk_len = strtoul(buffer, &ptr, 16);
/* limit chunk size to <= UINT_MAX, so it will probably
* fit in a size_t. */
@ -743,18 +792,14 @@ static int read_response_block(ne_request *req, struct ne_response *resp,
return aborted(req, _("Could not parse chunk size"), 0);
}
NE_DEBUG(NE_DBG_HTTP, "Got chunk size: %lu\n", chunk_len);
if (chunk_len == 0) {
/* Zero-size chunk == end of response. */
NE_DEBUG(NE_DBG_HTTP, "Zero-size chunk.\n");
*buflen = 0;
return NE_OK;
}
resp->chunk_left = chunk_len;
resp->body.chunk.remain = chunk_len;
}
willread = resp->chunk_left;
willread = resp->body.chunk.remain > *buflen
? *buflen : resp->body.chunk.remain;
break;
case R_CLENGTH:
willread = resp->left;
willread = resp->body.clen.remain > (off_t)*buflen
? *buflen : (size_t)resp->body.clen.remain;
break;
case R_TILLEOF:
willread = *buflen;
@ -764,8 +809,7 @@ static int read_response_block(ne_request *req, struct ne_response *resp,
willread = 0;
break;
}
if (willread > *buflen) willread = *buflen;
else if (willread == 0) {
if (willread == 0) {
*buflen = 0;
return 0;
}
@ -792,8 +836,8 @@ static int read_response_block(ne_request *req, struct ne_response *resp,
"Read block (%" NE_FMT_SSIZE_T " bytes):\n[%.*s]\n",
readlen, (int)readlen, buffer);
if (resp->mode == R_CHUNKED) {
resp->chunk_left -= readlen;
if (resp->chunk_left == 0) {
resp->body.chunk.remain -= readlen;
if (resp->body.chunk.remain == 0) {
char crlfbuf[2];
/* If we've read a whole chunk, read a CRLF */
readlen = ne_sock_fullread(sock, crlfbuf, 2);
@ -804,8 +848,9 @@ static int read_response_block(ne_request *req, struct ne_response *resp,
return aborted(req, _("Chunk delimiter was invalid"), 0);
}
} else if (resp->mode == R_CLENGTH) {
resp->left -= readlen;
resp->body.clen.remain -= readlen;
}
resp->progress += readlen;
return NE_OK;
}
@ -813,20 +858,21 @@ ssize_t ne_read_response_block(ne_request *req, char *buffer, size_t buflen)
{
struct body_reader *rdr;
size_t readlen = buflen;
struct ne_response *const resp = &req->resp;
if (read_response_block(req, &req->resp, buffer, &readlen))
if (read_response_block(req, resp, buffer, &readlen))
return -1;
req->resp.total += readlen;
if (req->session->progress_cb) {
req->session->progress_cb(req->session->progress_ud, req->resp.total,
(req->resp.mode==R_CLENGTH)?req->resp.length:-1);
req->session->progress_cb(req->session->progress_ud, resp->progress,
resp->mode==R_CLENGTH ? resp->body.clen.total:-1);
}
/* TODO: call the readers when this fails too. */
for (rdr = req->body_readers; rdr!=NULL; rdr=rdr->next) {
if (rdr->use) rdr->handler(rdr->userdata, buffer, readlen);
if (rdr->use && rdr->handler(rdr->userdata, buffer, readlen) != 0) {
ne_close_connection(req->session);
return -1;
}
}
return readlen;
@ -864,10 +910,10 @@ static ne_buffer *build_request(ne_request *req)
static void dump_request(const char *request)
{
if ((NE_DBG_HTTPPLAIN&ne_debug_mask) == NE_DBG_HTTPPLAIN) {
if (ne_debug_mask & NE_DBG_HTTPPLAIN) {
/* Display everything mode */
NE_DEBUG(NE_DBG_HTTP, "Sending request headers:\n%s", request);
} else {
} else if (ne_debug_mask & NE_DBG_HTTP) {
/* Blank out the Authorization paramaters */
char *reqdebug = ne_strdup(request), *pnt = reqdebug;
while ((pnt = strstr(pnt, "Authorization: ")) != NULL) {
@ -979,7 +1025,7 @@ static int send_request(ne_request *req, const ne_buffer *request)
return RETRY_RET(retry, ret, aret);
}
if (!req->use_expect100 && req->body_size > 0) {
if (!req->use_expect100 && req->body_length > 0) {
/* Send request body, if not using 100-continue. */
ret = send_request_body(req);
if (ret < 0) {
@ -999,7 +1045,8 @@ static int send_request(ne_request *req, const ne_buffer *request)
/* Discard headers with the interim response. */
if ((ret = discard_headers(req)) != NE_OK) break;
if (req->use_expect100 && (status->code == 100) && !sentbody) {
if (req->use_expect100 && (status->code == 100)
&& req->body_length > 0 && !sentbody) {
/* Send the body after receiving the first 100 Continue */
if ((ret = send_request_body(req)) != NE_OK) break;
sentbody = 1;
@ -1135,8 +1182,12 @@ static int read_response_headers(ne_request *req)
return ret;
}
/* Perform any necessary DNS lookup for the host given by *info;
* return NE_ code. */
static int lookup_host(ne_session *sess, struct host_info *info)
{
if (sess->addrlist) return NE_OK;
NE_DEBUG(NE_DBG_HTTP, "Doing DNS lookup on %s...\n", info->hostname);
if (sess->notify_cb)
sess->notify_cb(sess->notify_ud, ne_conn_namelookup, info->hostname);
@ -1169,10 +1220,6 @@ int ne_begin_request(ne_request *req)
req->resp.mode = R_TILLEOF;
/* FIXME: Determine whether to use the Expect: 100-continue header. */
req->use_expect100 = (req->session->expect100_works > -1) &&
(req->body_size > HTTP_EXPECT_MINSIZE) && req->session->is_http11;
/* Build the request string, and send it */
data = build_request(req);
DEBUG_DUMP_REQUEST(data->data);
@ -1197,7 +1244,7 @@ int ne_begin_request(ne_request *req)
/* Read the headers */
HTTP_ERR(read_response_headers(req));
#ifdef NEON_SSL
#ifdef NE_HAVE_SSL
/* Special case for CONNECT handling: the response has no body,
* and the connection can persist. */
if (req->session->in_connect && st->klass == 2) {
@ -1206,9 +1253,9 @@ int ne_begin_request(ne_request *req)
}
#endif
/* HEAD requests and 204, 205, 304 responses have no response body,
/* HEAD requests and 204, 304 responses have no response body,
* regardless of what headers are present. */
if (req->method_is_head || st->code==204 || st->code==205 || st->code==304)
if (req->method_is_head || st->code == 204 || st->code == 304)
req->resp.mode = R_NO_BODY;
/* Prepare for reading the response entity-body. Call each of the
@ -1218,9 +1265,6 @@ int ne_begin_request(ne_request *req)
rdr->use = rdr->accept_response(rdr->userdata, req, st);
}
req->resp.left = req->resp.length;
req->resp.chunk_left = 0;
return NE_OK;
}
@ -1292,7 +1336,7 @@ ne_session *ne_get_session(const ne_request *req)
return req->session;
}
#ifdef NEON_SSL
#ifdef NE_HAVE_SSL
/* Create a CONNECT tunnel through the proxy server.
* Returns HTTP_* */
static int proxy_tunnel(ne_session *sess)
@ -1324,13 +1368,37 @@ static int proxy_tunnel(ne_session *sess)
}
#endif
/* Return the first resolved address for the given host. */
static const ne_inet_addr *resolve_first(ne_session *sess,
struct host_info *host)
{
if (sess->addrlist) {
sess->curaddr = 0;
return sess->addrlist[0];
} else {
return ne_addr_first(host->address);
}
}
/* Return the next resolved address for the given host or NULL if
* there are no more addresses. */
static const ne_inet_addr *resolve_next(ne_session *sess,
struct host_info *host)
{
if (sess->addrlist) {
if (sess->curaddr++ < sess->numaddrs)
return sess->addrlist[sess->curaddr];
else
return NULL;
} else {
return ne_addr_next(host->address);
}
}
/* Make new TCP connection to server at 'host' of type 'name'. Note
* that once a connection to a particular network address has
* succeeded, that address will be used first for the next attempt to
* connect. */
/* TODO: an alternate implementation could always cycle through the
* addresses: this could ease server load, but could hurt SSL session
* caching for SSL sessions, which would increase server load. */
static int do_connect(ne_request *req, struct host_info *host, const char *err)
{
ne_session *const sess = req->session;
@ -1342,7 +1410,7 @@ static int do_connect(ne_request *req, struct host_info *host, const char *err)
}
if (host->current == NULL)
host->current = ne_addr_first(host->address);
host->current = resolve_first(sess, host);
do {
notify_status(sess, ne_conn_connecting, host->hostport);
@ -1355,7 +1423,7 @@ static int do_connect(ne_request *req, struct host_info *host, const char *err)
#endif
ret = ne_sock_connect(sess->socket, host->current, host->port);
} while (ret && /* try the next address... */
(host->current = ne_addr_next(host->address)) != NULL);
(host->current = resolve_next(sess, host)) != NULL);
if (ret) {
ne_set_error(sess, "%s: %s", err, ne_sock_error(sess->socket));
@ -1363,7 +1431,7 @@ static int do_connect(ne_request *req, struct host_info *host, const char *err)
return NE_CONNECT;
}
notify_status(sess, ne_conn_connected, sess->proxy.hostport);
notify_status(sess, ne_conn_connected, host->hostport);
if (sess->rdtimeout)
ne_sock_read_timeout(sess->socket, sess->rdtimeout);
@ -1389,7 +1457,7 @@ static int open_connection(ne_request *req)
if (ret != NE_OK) return ret;
#ifdef NEON_SSL
#ifdef NE_HAVE_SSL
/* Negotiate SSL layer if required. */
if (sess->use_ssl && !sess->in_connect) {
/* CONNECT tunnel */
@ -1397,7 +1465,7 @@ static int open_connection(ne_request *req)
ret = proxy_tunnel(sess);
if (ret == NE_OK)
ret = ne_negotiate_ssl(req);
ret = ne__negotiate_ssl(req);
/* This is probably only really needed for ne_negotiate_ssl
* failures as proxy_tunnel will fail via aborted(). */

View File

@ -1,6 +1,6 @@
/*
HTTP Request Handling
Copyright (C) 1999-2002, Joe Orton <joe@manyfish.co.uk>
Copyright (C) 1999-2004, Joe Orton <joe@manyfish.co.uk>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@ -53,17 +53,21 @@ typedef struct ne_request_s ne_request;
ne_request *ne_request_create(ne_session *sess,
const char *method, const char *path);
/* 'buffer' will be sent as the request body with given request. */
/* The request body will be taken from 'size' bytes of 'buffer'. */
void ne_set_request_body_buffer(ne_request *req, const char *buffer,
size_t size);
/* Send the contents of a file as the request body; 'fd' must be a
* file descriptor of an open, seekable file. Current file offset of
* fd is not retained (and ignored: the file is read from the the
* first byte). Returns:
* 0 on okay.
* non-zero if could not determine length of file. */
int ne_set_request_body_fd(ne_request *req, int fd);
/* The request body will be taken from 'length' bytes read from the
* file descriptor 'fd', starting from file offset 'offset'. */
void ne_set_request_body_fd(ne_request *req, int fd,
off_t offset, off_t length);
#ifdef NE_LFS
/* Alternate version of ne_set_request_body_fd taking off64_t
* offset type for systems supporting _LARGEFILE64_SOURCE. */
void ne_set_request_body_fd64(ne_request *req, int fd,
off64_t offset, off64_t length);
#endif
/* "Pull"-based request body provider: a callback which is invoked to
* provide blocks of request body on demand.
@ -79,13 +83,20 @@ int ne_set_request_body_fd(ne_request *req, int fd);
typedef ssize_t (*ne_provide_body)(void *userdata,
char *buffer, size_t buflen);
/* Install a callback which is invoked as needed to provide request
* body blocks. Total request body is 'size' bytes: the callback MUST
* ensure it returns in total exactly 'size' bytes each time the
* request body is provided. */
void ne_set_request_body_provider(ne_request *req, size_t size,
/* Install a callback which is invoked as needed to provide the
* request body, a block at a time. The total size of the request
* body is 'length'; the callback must ensure that it returns no more
* than 'length' bytes in total. */
void ne_set_request_body_provider(ne_request *req, off_t length,
ne_provide_body provider, void *userdata);
#ifdef NE_LFS
/* Duplicate version of ne_set_request_body_provider, taking an off64_t
* offset. */
void ne_set_request_body_provider64(ne_request *req, off64_t length,
ne_provide_body provider, void *userdata);
#endif
/* Handling response bodies... you provide TWO callbacks:
*
* 1) 'acceptance' callback: determines whether you want to handle the
@ -108,8 +119,12 @@ int ne_accept_2xx(void *userdata, ne_request *req, const ne_status *st);
* userdata. */
int ne_accept_always(void *userdata, ne_request *req, const ne_status *st);
/* Callback for reading a block of data. */
typedef void (*ne_block_reader)(void *userdata, const char *buf, size_t len);
/* Callback for reading a block of data. Returns zero on success, or
* -1 on error. If returning an error, the response will be aborted
* and the callback will not be invoked again. The request dispatch
* (or ne_read_response_block call) will fail with NE_ERROR; the
* session error string should have been set by the callback. */
typedef int (*ne_block_reader)(void *userdata, const char *buf, size_t len);
/* Add a response reader for the given request, with the given
* acceptance function. userdata is passed as the first argument to
@ -213,6 +228,12 @@ int ne_end_request(ne_request *req);
*/
ssize_t ne_read_response_block(ne_request *req, char *buffer, size_t buflen);
/* Include the HTTP/1.1 header "Expect: 100-continue" in request 'req'
* if 'flag' is non-zero. Warning: 100-continue support is not
* implemented correctly in some HTTP/1.1 servers, enabling this
* feature may cause requests to hang or time out. */
void ne_set_request_expect100(ne_request *req, int flag);
/**** Request hooks handling *****/
typedef void (*ne_free_hooks)(void *cookie);
@ -261,4 +282,3 @@ void *ne_get_request_private(ne_request *req, const char *id);
END_NEON_DECLS
#endif /* NE_REQUEST_H */

View File

@ -1,6 +1,6 @@
/*
HTTP session handling
Copyright (C) 1999-2003, Joe Orton <joe@manyfish.co.uk>
Copyright (C) 1999-2004, Joe Orton <joe@manyfish.co.uk>
Portions are:
Copyright (C) 1999-2000 Tommi Komulainen <Tommi.Komulainen@iki.fi>
@ -33,6 +33,10 @@
#include <errno.h>
#endif
#ifdef NE_HAVE_IDNA
#include <idna.h>
#endif
#include "ne_session.h"
#include "ne_alloc.h"
#include "ne_utils.h"
@ -84,7 +88,7 @@ void ne_session_destroy(ne_session *sess)
ne_close_connection(sess);
}
#ifdef NEON_SSL
#ifdef NE_HAVE_SSL
if (sess->ssl_context)
ne_ssl_context_destroy(sess->ssl_context);
@ -118,6 +122,14 @@ static void set_hostport(struct host_info *host, unsigned int defaultport)
static void
set_hostinfo(struct host_info *info, const char *hostname, unsigned int port)
{
#ifdef NE_HAVE_IDNA
char *ihost;
#define FLAGS IDNA_USE_STD3_ASCII_RULES
if (idna_to_ascii_8z(hostname, &ihost, FLAGS) == IDNA_SUCCESS)
info->hostname = ihost;
else /* fall back to use provided hostname string */
#endif
info->hostname = ne_strdup(hostname);
info->port = port;
}
@ -139,16 +151,14 @@ ne_session *ne_session_create(const char *scheme,
set_hostinfo(&sess->server, hostname, port);
set_hostport(&sess->server, sess->use_ssl?443:80);
#ifdef NEON_SSL
#ifdef NE_HAVE_SSL
if (sess->use_ssl) {
sess->ssl_context = ne_ssl_context_create();
sess->ssl_context = ne_ssl_context_create(0);
}
#endif
sess->scheme = ne_strdup(scheme);
/* Default expect-100 to OFF. */
sess->expect100_works = -1;
return sess;
}
@ -160,6 +170,12 @@ void ne_session_proxy(ne_session *sess, const char *hostname,
set_hostinfo(&sess->proxy, hostname, port);
}
void ne_set_addrlist(ne_session *sess, const ne_inet_addr **addrs, size_t n)
{
sess->addrlist = addrs;
sess->numaddrs = n;
}
void ne_set_error(ne_session *sess, const char *format, ...)
{
va_list params;
@ -184,15 +200,6 @@ void ne_set_status(ne_session *sess,
sess->notify_ud = userdata;
}
void ne_set_expect100(ne_session *sess, int use_expect100)
{
if (use_expect100) {
sess->expect100_works = 1;
} else {
sess->expect100_works = -1;
}
}
void ne_set_persist(ne_session *sess, int persist)
{
sess->no_persist = !persist;
@ -268,10 +275,7 @@ void ne_ssl_provide_clicert(ne_session *sess,
void ne_ssl_trust_cert(ne_session *sess, const ne_ssl_certificate *cert)
{
#ifdef NEON_SSL
ne_ssl_ctx_trustcert(sess->ssl_context, cert);
#ifdef NE_HAVE_SSL
ne_ssl_context_trustcert(sess->ssl_context, cert);
#endif
}

View File

@ -1,6 +1,6 @@
/*
HTTP session handling
Copyright (C) 1999-2003, Joe Orton <joe@manyfish.co.uk>
Copyright (C) 1999-2004, Joe Orton <joe@manyfish.co.uk>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@ -27,6 +27,7 @@
#include "ne_ssl.h"
#include "ne_uri.h" /* for ne_uri */
#include "ne_defs.h"
#include "ne_socket.h"
BEGIN_NEON_DECLS
@ -34,7 +35,9 @@ typedef struct ne_session_s ne_session;
/* Create a session to the given server, using the given scheme. If
* "https" is passed as the scheme, SSL will be used to connect to the
* server. */
* server. If neon is built with support for IDNA, 'hostname' can be
* a UTF-8-encoded Unicode string; otherwise, it must be an ASCII
* string. */
ne_session *ne_session_create(const char *scheme,
const char *hostname, unsigned int port);
@ -49,18 +52,13 @@ void ne_close_connection(ne_session *sess);
void ne_session_proxy(ne_session *sess,
const char *hostname, unsigned int port);
/* Set protocol options for session:
* expect100: Defaults to OFF
* persist: Defaults to ON
*
* expect100: When set, send the "Expect: 100-continue" request header
* with requests with bodies.
*
* persist: When set, use a persistent connection. (Generally,
* you don't want to turn this off.)
* */
void ne_set_expect100(ne_session *sess, int use_expect100);
void ne_set_persist(ne_session *sess, int persist);
/* Disable use of persistent connection if 'flag' is non-zero, else
* enable (the default). */
void ne_set_persist(ne_session *sess, int flag);
/* Bypass the normal name resolution; force the use of specific set of
* addresses for this session, addrs[0]...addrs[n-1]. */
void ne_set_addrlist(ne_session *sess, const ne_inet_addr **addrs, size_t n);
/* Progress callback. */
typedef void (*ne_progress)(void *userdata, off_t progress, off_t total);

View File

@ -1,7 +1,8 @@
/*
socket handling routines
Socket handling routines
Copyright (C) 1998-2004, Joe Orton <joe@manyfish.co.uk>,
Copyright (C) 1999-2000 Tommi Komulainen <Tommi.Komulainen@iki.fi>
Copyright (C) 2004 Aleix Conchillo Flaque <aleix@member.fsf.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@ -29,10 +30,6 @@
#ifdef __hpux
/* pick up hstrerror */
#define _XOPEN_SOURCE_EXTENDED 1
/* don't use the broken getaddrinfo shipped in HP-UX 11.11 */
#ifdef USE_GETADDRINFO
#undef USE_GETADDRINFO
#endif
#endif
#include <sys/types.h>
@ -40,13 +37,16 @@
#include <sys/time.h>
#endif
#include <sys/stat.h>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef NE_USE_POLL
#include <sys/poll.h>
#elif defined(HAVE_SYS_SELECT_H)
#include <sys/select.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
@ -63,9 +63,12 @@
#ifdef WIN32
#include <winsock2.h>
#include <stddef.h>
#ifdef USE_GETADDRINFO
#include <ws2tcpip.h>
#endif
#endif
#if defined(NEON_SSL) && defined(HAVE_LIMITS_H)
#if defined(HAVE_OPENSSL) && defined(HAVE_LIMITS_H)
#include <limits.h> /* for INT_MAX */
#endif
#ifdef HAVE_STRING_H
@ -91,18 +94,17 @@
#include <socks.h>
#endif
#ifdef NEON_SSL
#ifdef HAVE_OPENSSL
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/pkcs12.h> /* for PKCS12_PBE_add */
#include <openssl/rand.h>
#include "ne_privssl.h"
#include <openssl/opensslv.h> /* for OPENSSL_VERSION_NUMBER */
#endif
#include "ne_i18n.h"
#include "ne_utils.h"
#include "ne_string.h"
#ifdef HAVE_GNUTLS
#include <gnutls/gnutls.h>
#endif
#define NE_INET_ADDR_DEFINED
/* A slightly ugly hack: change the ne_inet_addr definition to be the
@ -112,35 +114,35 @@
* structure, or losing type-safety by using void *. */
#ifdef USE_GETADDRINFO
typedef struct addrinfo ne_inet_addr;
/* To avoid doing AAAA queries unless absolutely necessary, either use
* AI_ADDRCONFIG where available, or a run-time check for working IPv6
* support; the latter is only known to work on Linux. */
#if !defined(USE_GAI_ADDRCONFIG) && defined(__linux__)
#define USE_CHECK_IPV6
#endif
#else
typedef struct in_addr ne_inet_addr;
#endif
#ifdef NE_HAVE_SSL
#include "ne_privssl.h" /* MUST come after ne_inet_addr is defined */
#endif
/* To avoid doing AAAA queries unless absolutely necessary, either use
* AI_ADDRCONFIG where available, or a run-time check for working IPv6
* support; the latter is only known to work on Linux. */
#if defined(USE_GETADDRINFO) && !defined(USE_GAI_ADDRCONFIG) && defined(__linux__)
#define USE_CHECK_IPV6
#endif
#include "ne_i18n.h"
#include "ne_utils.h"
#include "ne_string.h"
#include "ne_socket.h"
#include "ne_alloc.h"
#if defined(__BEOS__) && !defined(BONE_VERSION)
/* pre-BONE */
#define ne_write(a,b,c) send(a,b,c,0)
#define ne_read(a,b,c) recv(a,b,c,0)
#define ne_close(s) closesocket(s)
#define ne_errno errno
#elif defined(WIN32)
#define ne_write(a,b,c) send(a,b,c,0)
#define ne_read(a,b,c) recv(a,b,c,0)
#define ne_close(s) closesocket(s)
#define ne_errno WSAGetLastError()
#else /* really Unix! */
#define ne_write(a,b,c) write(a,b,c)
#define ne_read(a,b,c) read(a,b,c)
#define ne_close(s) close(s)
#define ne_errno errno
#endif
@ -151,7 +153,13 @@ typedef struct in_addr ne_inet_addr;
#define NE_ISCLOSED(e) ((e) == WSAESHUTDOWN || (e) == WSAENOTCONN)
#define NE_ISINTR(e) (0)
#else /* Unix */
/* ECONNABORTED shouldn't really be returned by anything but accept()
* but apparently nobody told CygWin that... */
#ifdef ECONNABORTED
#define NE_ISRESET(e) ((e) == ECONNRESET || (e) == ECONNABORTED)
#else
#define NE_ISRESET(e) ((e) == ECONNRESET)
#endif
#define NE_ISCLOSED(e) ((e) == EPIPE)
#define NE_ISINTR(e) ((e) == EINTR)
#endif
@ -165,8 +173,8 @@ struct iofns {
/* Read up to 'len' bytes into 'buf' from socket. Return <0 on
* error or EOF, or >0; number of bytes read. */
ssize_t (*read)(ne_socket *s, char *buf, size_t len);
/* Write exactly 'len' bytes from 'buf' to socket. Return zero on
* success, <0 on error. */
/* Write up to 'len' bytes from 'buf' to socket. Return number of
* bytes written on success, or <0 on error. */
ssize_t (*write)(ne_socket *s, const char *buf, size_t len);
/* Wait up to 'n' seconds for socket to become readable. Returns
* 0 when readable, otherwise NE_SOCK_TIMEOUT or NE_SOCK_ERROR. */
@ -179,7 +187,7 @@ struct ne_socket_s {
void *progress_ud;
int rdtimeout; /* read timeout. */
const struct iofns *ops;
#ifdef NEON_SSL
#ifdef NE_HAVE_SSL
ne_ssl_socket ssl;
#endif
/* The read buffer: ->buffer stores byte which have been read; as
@ -223,16 +231,21 @@ static void print_error(int errnum, char *buffer, size_t buflen)
#define set_strerror(s, e) ne_strerror((e), (s)->error, sizeof (s)->error)
#endif
#ifdef NEON_SSL
/* Initialize SSL library. */
#if defined(HAVE_OPENSSL)
static void init_ssl(void)
{
SSL_load_error_strings();
SSL_library_init();
PKCS12_PBE_add(); /* ### not sure why this is needed. */
}
#elif defined(HAVE_GNUTLS)
static void init_ssl(void)
{
gnutls_global_init();
}
#endif /* HAVE_OPENSSL */
#ifdef HAVE_OPENSSL
/* Seed the SSL PRNG, if necessary; returns non-zero on failure. */
static int seed_ssl_prng(void)
{
@ -240,7 +253,7 @@ static int seed_ssl_prng(void)
if (RAND_status() == 1)
return 0;
#ifdef EGD_PATH
#if defined(EGD_PATH)
NE_DEBUG(NE_DBG_SOCKET, "Seeding PRNG from " EGD_PATH "...\n");
if (RAND_egd(EGD_PATH) != -1)
return 0;
@ -260,7 +273,7 @@ static int seed_ssl_prng(void)
NE_DEBUG(NE_DBG_SOCKET, "No entropy source found; could not seed PRNG.\n");
return -1;
}
#endif /* NEON_SSL */
#endif /* HAVE_OPENSSL */
#ifdef USE_CHECK_IPV6
static int ipv6_disabled = 0;
@ -307,7 +320,7 @@ int ne_sock_init(void)
#endif
#ifdef NEON_SOCKS
#ifdef NE_HAVE_SOCKS
SOCKSinit("neon");
#endif
@ -319,7 +332,7 @@ int ne_sock_init(void)
init_ipv6();
#endif
#ifdef NEON_SSL
#ifdef NE_HAVE_SSL
init_ssl();
#endif
@ -331,6 +344,9 @@ void ne_sock_exit(void)
{
#ifdef WIN32
WSACleanup();
#endif
#ifdef HAVE_GNUTLS
gnutls_global_deinit();
#endif
init_result = 0;
}
@ -345,9 +361,6 @@ int ne_sock_block(ne_socket *sock, int n)
/* Cast address object AD to type 'sockaddr_TY' */
#define SACAST(ty, ad) ((struct sockaddr_##ty *)(ad))
#define SOCK_ERR(x) do { ssize_t _sock_err = (x); \
if (_sock_err < 0) return _sock_err; } while(0)
ssize_t ne_sock_read(ne_socket *sock, char *buffer, size_t buflen)
{
ssize_t bytes;
@ -411,7 +424,20 @@ ssize_t ne_sock_peek(ne_socket *sock, char *buffer, size_t buflen)
/* Await data on raw fd in socket. */
static int readable_raw(ne_socket *sock, int secs)
{
int fdno = sock->fd, ret;
int ret;
#ifdef NE_USE_POLL
struct pollfd fds;
int timeout = secs > 0 ? secs * 1000 : -1;
fds.fd = sock->fd;
fds.events = POLLIN;
fds.revents = 0;
do {
ret = poll(&fds, 1, timeout);
} while (ret < 0 && NE_ISINTR(ne_errno));
#else
int fdno = sock->fd;
fd_set rdfds;
struct timeval timeout, *tvp = (secs >= 0 ? &timeout : NULL);
@ -425,6 +451,8 @@ static int readable_raw(ne_socket *sock, int secs)
}
ret = select(fdno + 1, &rdfds, NULL, NULL, tvp);
} while (ret < 0 && NE_ISINTR(ne_errno));
#endif
if (ret < 0) {
set_strerror(sock, ne_errno);
return NE_SOCK_ERROR;
@ -440,7 +468,7 @@ static ssize_t read_raw(ne_socket *sock, char *buffer, size_t len)
if (ret) return ret;
do {
ret = ne_read(sock->fd, buffer, len);
ret = recv(sock->fd, buffer, len, 0);
} while (ret == -1 && NE_ISINTR(ne_errno));
if (ret == 0) {
@ -460,46 +488,36 @@ static ssize_t read_raw(ne_socket *sock, char *buffer, size_t len)
static ssize_t write_raw(ne_socket *sock, const char *data, size_t length)
{
ssize_t wrote;
ssize_t ret;
do {
wrote = ne_write(sock->fd, data, length);
if (wrote > 0) {
data += wrote;
length -= wrote;
}
} while ((wrote > 0 || NE_ISINTR(ne_errno)) && length > 0);
ret = send(sock->fd, data, length, 0);
} while (ret == -1 && NE_ISINTR(ne_errno));
if (wrote < 0) {
if (ret < 0) {
int errnum = ne_errno;
set_strerror(sock, errnum);
return MAP_ERR(errnum);
}
return 0;
return ret;
}
static const struct iofns iofns_raw = { read_raw, write_raw, readable_raw };
#ifdef NEON_SSL
#ifdef HAVE_OPENSSL
/* OpenSSL I/O function implementations. */
static int readable_ossl(ne_socket *sock, int secs)
{
/* If there is buffered SSL data, then don't block on the socket.
* FIXME: make sure that SSL_read *really* won't block if
* SSL_pending returns non-zero. Possibly need to do
* SSL_read(ssl, buf, SSL_pending(ssl)) */
if (SSL_pending(sock->ssl.ssl))
if (SSL_pending(sock->ssl))
return 0;
return readable_raw(sock, secs);
}
/* SSL error handling, according to SSL_get_error(3). */
static int error_ossl(ne_socket *sock, int sret)
{
int err = SSL_get_error(sock->ssl.ssl, sret), ret = NE_SOCK_ERROR;
int err = SSL_get_error(sock->ssl, sret), ret = NE_SOCK_ERROR;
const char *str;
switch (err) {
case SSL_ERROR_ZERO_RETURN:
@ -520,13 +538,15 @@ static int error_ossl(ne_socket *sock, int sret)
ret = MAP_ERR(err);
}
} else {
ne_snprintf(sock->error, sizeof sock->error,
_("SSL error: %s"), ERR_reason_error_string(err));
str = ERR_reason_error_string(err);
ne_snprintf(sock->error, sizeof sock->error, _("SSL error: %s"),
str ? str : _("unknown error code"));
}
break;
default:
str = ERR_reason_error_string(ERR_get_error());
ne_snprintf(sock->error, sizeof sock->error, _("SSL error: %s"),
ERR_reason_error_string(ERR_get_error()));
str ? str : _("unknown error code"));
break;
}
return ret;
@ -543,7 +563,7 @@ static ssize_t read_ossl(ne_socket *sock, char *buffer, size_t len)
ret = readable_ossl(sock, sock->rdtimeout);
if (ret) return ret;
ret = SSL_read(sock->ssl.ssl, buffer, CAST2INT(len));
ret = SSL_read(sock->ssl, buffer, CAST2INT(len));
if (ret <= 0)
ret = error_ossl(sock, ret);
@ -553,26 +573,126 @@ static ssize_t read_ossl(ne_socket *sock, char *buffer, size_t len)
static ssize_t write_ossl(ne_socket *sock, const char *data, size_t len)
{
int ret, ilen = CAST2INT(len);
ret = SSL_write(sock->ssl.ssl, data, ilen);
ret = SSL_write(sock->ssl, data, ilen);
/* ssl.h says SSL_MODE_ENABLE_PARTIAL_WRITE must be enabled to
* have SSL_write return < length... so, SSL_write should never
* return < length. */
if (ret != ilen)
return error_ossl(sock, ret);
return 0;
return ret;
}
static const struct iofns iofns_ossl = {
static const struct iofns iofns_ssl = {
read_ossl,
write_ossl,
readable_ossl
};
#endif /* NEON_SSL */
#elif defined(HAVE_GNUTLS)
/* Return zero if an alert value can be ignored. */
static int check_alert(ne_socket *sock, ssize_t ret)
{
const char *alert;
if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED) {
alert = gnutls_alert_get_name(gnutls_alert_get(sock->ssl));
NE_DEBUG(NE_DBG_SOCKET, "TLS warning alert: %s\n", alert);
return 0;
} else if (ret == GNUTLS_E_FATAL_ALERT_RECEIVED) {
alert = gnutls_alert_get_name(gnutls_alert_get(sock->ssl));
NE_DEBUG(NE_DBG_SOCKET, "TLS fatal alert: %s\n", alert);
return -1;
}
return ret;
}
static int readable_gnutls(ne_socket *sock, int secs)
{
if (gnutls_record_check_pending(sock->ssl)) {
return 0;
}
return readable_raw(sock, secs);
}
static ssize_t error_gnutls(ne_socket *sock, ssize_t sret)
{
ssize_t ret;
switch (sret) {
case 0:
ret = NE_SOCK_CLOSED;
set_error(sock, _("Connection closed"));
break;
case GNUTLS_E_FATAL_ALERT_RECEIVED:
ret = NE_SOCK_RESET;
ne_snprintf(sock->error, sizeof sock->error, _("SSL error: %s"),
gnutls_alert_get_name(gnutls_alert_get(sock->ssl)));
break;
default:
ret = NE_SOCK_ERROR;
ne_snprintf(sock->error, sizeof sock->error, _("SSL error: %s"),
gnutls_strerror(sret));
}
return ret;
}
#define RETRY_GNUTLS(sock, ret) ((ret < 0) \
&& (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN \
|| check_alert(sock, ret) == 0))
static ssize_t read_gnutls(ne_socket *sock, char *buffer, size_t len)
{
ssize_t ret;
ret = readable_gnutls(sock, sock->rdtimeout);
if (ret) return ret;
do {
ret = gnutls_record_recv(sock->ssl, buffer, len);
} while (RETRY_GNUTLS(sock, ret));
if (ret <= 0)
ret = error_gnutls(sock, ret);
return ret;
}
static ssize_t write_gnutls(ne_socket *sock, const char *data, size_t len)
{
ssize_t ret;
do {
ret = gnutls_record_send(sock->ssl, data, len);
} while (RETRY_GNUTLS(sock, ret));
if (ret < 0)
return error_gnutls(sock, ret);
return ret;
}
static const struct iofns iofns_ssl = {
read_gnutls,
write_gnutls,
readable_gnutls
};
#endif
int ne_sock_fullwrite(ne_socket *sock, const char *data, size_t len)
{
return sock->ops->write(sock, data, len);
ssize_t ret;
do {
ret = sock->ops->write(sock, data, len);
if (ret > 0) {
data += ret;
len -= ret;
}
} while (ret > 0 && len > 0);
return ret < 0 ? ret : 0;
}
ssize_t ne_sock_readline(ne_socket *sock, char *buf, size_t buflen)
@ -761,7 +881,7 @@ char *ne_addr_error(const ne_sock_addr *addr, char *buf, size_t bufsiz)
char *ne_iaddr_print(const ne_inet_addr *ia, char *buf, size_t bufsiz)
{
#ifdef USE_GETADDRINFO /* implies inet_ntop */
#if defined(USE_GETADDRINFO) && defined(HAVE_INET_NTOP)
const char *ret;
#ifdef AF_INET6
if (ia->ai_family == AF_INET6) {
@ -776,7 +896,12 @@ char *ne_iaddr_print(const ne_inet_addr *ia, char *buf, size_t bufsiz)
ret = NULL;
if (ret == NULL)
ne_strnzcpy(buf, "[IP address]", bufsiz);
#else
#elif defined(USE_GETADDRINFO) && defined(NI_NUMERICHOST)
/* use getnameinfo instead for Win32, which lacks inet_ntop: */
if (getnameinfo(ia->ai_addr, ia->ai_addrlen, buf, bufsiz, NULL, 0,
NI_NUMERICHOST))
ne_strnzcpy(buf, "[IP address]", bufsiz);
#else /* USE_GETADDRINFO */
ne_strnzcpy(buf, inet_ntoa(*ia), bufsiz);
#endif
return buf;
@ -854,6 +979,14 @@ int ne_sock_connect(ne_socket *sock,
return -1;
}
#if !defined(NE_USE_POLL) && !defined(WIN32)
if (fd > FD_SETSIZE) {
ne_close(fd);
set_error(sock, _("Socket descriptor number exceeds FD_SETSIZE"));
return NE_SOCK_ERROR;
}
#endif
#if defined(TCP_NODELAY) && defined(HAVE_SETSOCKOPT) && defined(IPPROTO_TCP)
{ /* Disable the Nagle algorithm; better to add write buffering
* instead of doing this. */
@ -862,7 +995,7 @@ int ne_sock_connect(ne_socket *sock,
}
#endif
if (raw_connect(fd, addr, ntohs(port))) {
if (raw_connect(fd, addr, htons(port))) {
set_strerror(sock, ne_errno);
ne_close(fd);
return -1;
@ -908,6 +1041,15 @@ ne_inet_addr *ne_iaddr_make(ne_iaddr_type type, const unsigned char *raw)
return ia;
}
ne_iaddr_type ne_iaddr_typeof(const ne_inet_addr *ia)
{
#ifdef USE_GETADDRINFO
return ia->ai_family == AF_INET6 ? ne_iaddr_ipv6 : ne_iaddr_ipv4;
#else
return ne_iaddr_ipv4;
#endif
}
int ne_iaddr_cmp(const ne_inet_addr *i1, const ne_inet_addr *i2)
{
#ifdef USE_GETADDRINFO
@ -959,25 +1101,59 @@ void ne_sock_read_timeout(ne_socket *sock, int timeout)
sock->rdtimeout = timeout;
}
#ifdef NEON_SSL
#ifdef NE_HAVE_SSL
void ne_sock_switch_ssl(ne_socket *sock, void *ssl)
int ne_sock_accept_ssl(ne_socket *sock, ne_ssl_context *ctx)
{
sock->ssl.ssl = ssl;
sock->ops = &iofns_ossl;
int ret;
ne_ssl_socket ssl;
#if defined(HAVE_OPENSSL)
ssl = SSL_new(ctx->ctx);
SSL_set_fd(ssl, sock->fd);
sock->ssl = ssl;
ret = SSL_accept(ssl);
if (ret != 1) {
return error_ossl(sock, ret);
}
#elif defined(HAVE_GNUTLS)
gnutls_init(&ssl, GNUTLS_SERVER);
gnutls_credentials_set(ssl, GNUTLS_CRD_CERTIFICATE, ctx->cred);
gnutls_set_default_priority(ssl);
sock->ssl = ssl;
gnutls_transport_set_ptr(sock->ssl, (gnutls_transport_ptr) sock->fd);
ret = gnutls_handshake(ssl);
if (ret < 0) {
return error_gnutls(sock, ret);
}
#endif
sock->ops = &iofns_ssl;
return 0;
}
int ne_sock_connect_ssl(ne_socket *sock, ne_ssl_context *ctx)
{
SSL *ssl;
int ret;
#if defined(HAVE_OPENSSL)
SSL *ssl;
if (seed_ssl_prng()) {
set_error(sock, _("SSL disabled due to lack of entropy"));
return NE_SOCK_ERROR;
}
sock->ssl.ssl = ssl = SSL_new(ctx->ctx);
/* If runtime library version differs from compile-time version
* number in major/minor/fix level, abort soon. */
if ((SSLeay() ^ OPENSSL_VERSION_NUMBER) & 0xFFFFF000) {
set_error(sock, _("SSL disabled due to library version mismatch"));
return NE_SOCK_ERROR;
}
sock->ssl = ssl = SSL_new(ctx->ctx);
if (!ssl) {
set_error(sock, _("Could not create SSL structure"));
return NE_SOCK_ERROR;
@ -986,7 +1162,7 @@ int ne_sock_connect_ssl(ne_socket *sock, ne_ssl_context *ctx)
SSL_set_app_data(ssl, ctx);
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
SSL_set_fd(ssl, sock->fd);
sock->ops = &iofns_ossl;
sock->ops = &iofns_ssl;
if (ctx->sess)
SSL_set_session(ssl, ctx->sess);
@ -995,16 +1171,30 @@ int ne_sock_connect_ssl(ne_socket *sock, ne_ssl_context *ctx)
if (ret != 1) {
error_ossl(sock, ret);
SSL_free(ssl);
sock->ssl.ssl = NULL;
sock->ssl = NULL;
return NE_SOCK_ERROR;
}
#elif defined(HAVE_GNUTLS)
/* DH and RSA params are set in ne_ssl_context_create */
gnutls_init(&sock->ssl, GNUTLS_CLIENT);
gnutls_set_default_priority(sock->ssl);
gnutls_credentials_set(sock->ssl, GNUTLS_CRD_CERTIFICATE, ctx->cred);
gnutls_transport_set_ptr(sock->ssl, (gnutls_transport_ptr) sock->fd);
sock->ops = &iofns_ssl;
ret = gnutls_handshake(sock->ssl);
if (ret < 0) {
error_gnutls(sock, ret);
return NE_SOCK_ERROR;
}
#endif
return 0;
}
ne_ssl_socket *ne_sock_sslsock(ne_socket *sock)
ne_ssl_socket ne__sock_sslsock(ne_socket *sock)
{
return &sock->ssl;
return sock->ssl;
}
#endif
@ -1018,12 +1208,21 @@ const char *ne_sock_error(const ne_socket *sock)
int ne_sock_close(ne_socket *sock)
{
int ret;
#ifdef NEON_SSL
if (sock->ssl.ssl) {
SSL_shutdown(sock->ssl.ssl);
SSL_free(sock->ssl.ssl);
#if defined(HAVE_OPENSSL)
if (sock->ssl) {
SSL_shutdown(sock->ssl);
SSL_free(sock->ssl);
}
#elif defined(HAVE_GNUTLS)
if (sock->ssl) {
do {
ret = gnutls_bye(sock->ssl, GNUTLS_SHUT_RDWR);
} while (ret < 0
&& (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN));
}
#endif
if (sock->fd < 0)
ret = 0;
else

View File

@ -1,6 +1,6 @@
/*
socket handling interface
Copyright (C) 1999-2003, Joe Orton <joe@manyfish.co.uk>
Copyright (C) 1999-2004, Joe Orton <joe@manyfish.co.uk>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@ -36,7 +36,7 @@ BEGIN_NEON_DECLS
#define NE_SOCK_CLOSED (-3)
/* Connection was reset (e.g. server crashed) */
#define NE_SOCK_RESET (-4)
/* Secure connection was subject to possible truncation attack. */
/* Secure connection was closed without proper SSL shutdown. */
#define NE_SOCK_TRUNC (-5)
/* ne_socket represents a TCP socket. */
@ -57,7 +57,7 @@ int ne_sock_init(void);
/* Shutdown any underlying libraries. */
void ne_sock_exit(void);
/* Resolve the given hostname. 'flags' are currently ignored. Hex
/* Resolve the given hostname. 'flags' must be zero. Hex
* string IPv6 addresses (e.g. `::1') may be enclosed in brackets
* (e.g. `[::1]'). */
ne_sock_addr *ne_addr_resolve(const char *hostname, int flags);
@ -102,6 +102,9 @@ ne_inet_addr *ne_iaddr_make(ne_iaddr_type type, const unsigned char *raw);
* are not equal. */
int ne_iaddr_cmp(const ne_inet_addr *i1, const ne_inet_addr *i2);
/* Returns the type of the given network address. */
ne_iaddr_type ne_iaddr_typeof(const ne_inet_addr *ia);
/* Prints the string representation of network address 'ia' into the
* 'buffer', which is of size 'bufsiz'. Returns 'buffer'. */
char *ne_iaddr_print(const ne_inet_addr *ia, char *buffer, size_t bufsiz);
@ -177,16 +180,14 @@ void ne_sock_read_timeout(ne_socket *sock, int timeout);
* none is known. */
int ne_service_lookup(const char *name);
/* Enable SSL with an already-negotiated SSL socket. */
void ne_sock_switch_ssl(ne_socket *sock, void *ssl);
/* Negotiate an SSL connection on socket as an SSL server, using given
* SSL context. */
int ne_sock_accept_ssl(ne_socket *sock, ne_ssl_context *ctx);
/* Perform an SSL negotiation on 'sock', using given context. */
/* Negotiate an SSL connection on socket as an SSL client, using given
* SSL context. */
int ne_sock_connect_ssl(ne_socket *sock, ne_ssl_context *ctx);
/* Return SSL socket object in use for 'sock'. */
typedef struct ne_ssl_socket_s ne_ssl_socket;
ne_ssl_socket *ne_sock_sslsock(ne_socket *sock);
END_NEON_DECLS
#endif /* NE_SOCKET_H */

View File

@ -133,14 +133,31 @@ const ne_ssl_certificate *ne_ssl_clicert_owner(const ne_ssl_client_cert *ccert);
/* Deallocate memory associated with a client certificate. */
void ne_ssl_clicert_free(ne_ssl_client_cert *ccert);
/* An SSL context; only necessary when interfacing with ne_socket.h. */
/* SSL context object. The interfaces to manipulate an SSL context
* are only needed when interfacing directly with ne_socket.h. */
typedef struct ne_ssl_context_s ne_ssl_context;
/* Create an SSL context. */
ne_ssl_context *ne_ssl_context_create(void);
/* Context creation modes: */
#define NE_SSL_CTX_CLIENT (0) /* client context */
#define NE_SSL_CTX_SERVER (1) /* default server context */
#define NE_SSL_CTX_SERVERv2 (2) /* SSLv2-specific server context */
/* Trust the given certificate 'cert' in context 'ctx'. */
void ne_ssl_ctx_trustcert(ne_ssl_context *ctx, const ne_ssl_certificate *cert);
/* Create an SSL context. */
ne_ssl_context *ne_ssl_context_create(int mode);
/* Client mode: trust the given certificate 'cert' in context 'ctx'. */
void ne_ssl_context_trustcert(ne_ssl_context *ctx, const ne_ssl_certificate *cert);
/* Server mode: use given cert and key (filenames to PEM certificates). */
int ne_ssl_context_keypair(ne_ssl_context *ctx,
const char *cert, const char *key);
/* Server mode: set client cert verification options: required is non-zero if
* a client cert is required, if ca_names is non-NULL it is a filename containing
* a set of PEM certs from which CA names are sent in the ccert request. */
int ne_ssl_context_set_verify(ne_ssl_context *ctx, int required,
const char *ca_names, const char *verify_cas);
/* Destroy an SSL context. */
void ne_ssl_context_destroy(ne_ssl_context *ctx);

View File

@ -1,6 +1,6 @@
/*
String utility functions
Copyright (C) 1999-2003, Joe Orton <joe@manyfish.co.uk>
Copyright (C) 1999-2004, Joe Orton <joe@manyfish.co.uk>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@ -31,6 +31,8 @@
#include <unistd.h>
#endif
#include <stdio.h>
#include <ctype.h> /* for isprint() etc in ne_strclean() */
#include "ne_alloc.h"
@ -101,172 +103,6 @@ char *ne_shave(char *str, const char *whitespace)
return ret;
}
/* TODO: deprecate all these and use ne_token() instead. */
char **split_string(const char *str, const char separator,
const char *quotes, const char *whitespace)
{
return split_string_c(str, separator, quotes, whitespace, NULL);
}
char **split_string_c(const char *str, const char separator,
const char *quotes, const char *whitespace,
int *give_count)
{
char **comps;
const char *pnt, *quot = NULL,
*start, *end; /* The start of the current component */
int count, /* The number of components */
iswhite, /* is it whitespace */
issep, /* is it the separator */
curr, /* current component index */
length, /* length of component */
leading_wspace; /* in leading whitespace still? */
/* Inefficient, but easier - first off, count the number of
* components we have. */
count = 1;
for (pnt = str; *pnt!='\0'; pnt++) {
if (quotes != NULL) {
quot = strchr(quotes, *pnt);
}
if (quot != NULL) {
/* We found a quote, so skip till the next quote */
for (pnt++; (*pnt!=*quot) && (*pnt!='\0'); pnt++)
/* nullop */;
} else if (*pnt == separator) {
count++;
}
}
if (give_count) {
/* Write the count */
*give_count = count;
}
/* Now, have got the number of components.
* Allocate the comps array. +1 for the NULL */
comps = ne_malloc(sizeof(char *) * (count + 1));
comps[count] = NULL;
quot = end = start = NULL;
curr = 0;
leading_wspace = 1;
/* Now fill in the array */
for (pnt = str; *pnt != '\0'; pnt++) {
/* What is the current character - quote, whitespace, separator? */
if (quotes != NULL) {
quot = strchr(quotes, *pnt);
}
iswhite = (whitespace!=NULL) &&
(strchr(whitespace, *pnt) != NULL);
issep = (*pnt == separator);
/* What to do? */
if (leading_wspace) {
if (quot!=NULL) {
/* Quoted bit */
start = pnt;
length = 1;
leading_wspace = 0;
} else if (issep) {
/* Zero-length component */
comps[curr++] = ne_strdup("");
} else if (!iswhite) {
start = end = pnt;
length = 1;
leading_wspace = 0;
}
} else {
if (quot!=NULL) {
/* Quoted bit */
length++;
} else if (issep) {
/* End of component - enter it into the array */
length = (end - start) + 1;
comps[curr] = ne_malloc(length+1);
memcpy(comps[curr], start, length);
comps[curr][length] = '\0';
curr++;
leading_wspace = 1;
} else if (!iswhite) {
/* Not whitespace - update end marker */
end = pnt;
}
}
if (quot != NULL) {
/* Skip to closing quote */
for (pnt++; *pnt!=*quot && *pnt != '\0'; ++pnt)
/* nullop */;
/* Last non-wspace char is closing quote */
end = pnt;
}
}
/* Handle final component */
if (leading_wspace) {
comps[curr] = ne_strdup("");
} else {
/* End of component - enter it into the array */
length = (end - start) + 1;
comps[curr] = ne_malloc(length+1);
memcpy(comps[curr], start, length);
comps[curr][length] = '\0';
}
return comps;
}
char **pair_string(const char *str, const char compsep, const char kvsep,
const char *quotes, const char *whitespace)
{
char **comps, **pairs, *split;
int count = 0, n, length;
comps = split_string_c(str, compsep, quotes, whitespace, &count);
/* Allocate space for 2* as many components as split_string returned,
* +2 for the NULLS. */
pairs = ne_malloc((2*count+2) * sizeof(char *));
if (pairs == NULL) {
return NULL;
}
for (n = 0; n < count; n++) {
/* Find the split */
split = strchr(comps[n], kvsep);
if (split == NULL) {
/* No seperator found */
length = strlen(comps[n]);
} else {
length = split-comps[n];
}
/* Enter the key into the array */
pairs[2*n] = comps[n];
/* Null-terminate the key */
pairs[2*n][length] = '\0';
pairs[2*n+1] = split?(split + 1):NULL;
}
ne_free(comps);
pairs[2*count] = pairs[2*count+1] = NULL;
return pairs;
}
void split_string_free(char **components)
{
char **pnt = components;
while (*pnt != NULL) {
ne_free(*pnt);
pnt++;
}
ne_free(components);
}
void pair_string_free(char **pairs)
{
int n;
for (n = 0; pairs[n] != NULL; n+=2) {
ne_free(pairs[n]);
}
ne_free(pairs);
}
void ne_buffer_clear(ne_buffer *buf)
{
memset(buf->data, 0, buf->length);
@ -517,3 +353,31 @@ char *ne_strerror(int errnum, char *buf, size_t buflen)
#endif
return buf;
}
/* Wrapper for ne_snprintf. */
size_t ne_snprintf(char *str, size_t size, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
#ifdef HAVE_TRIO
trio_vsnprintf(str, size, fmt, ap);
#else
vsnprintf(str, size, fmt, ap);
#endif
va_end(ap);
str[size-1] = '\0';
return strlen(str);
}
/* Wrapper for ne_vsnprintf. */
size_t ne_vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
{
#ifdef HAVE_TRIO
trio_vsnprintf(str, size, fmt, ap);
#else
vsnprintf(str, size, fmt, ap);
#endif
str[size-1] = '\0';
return strlen(str);
}

View File

@ -1,6 +1,6 @@
/*
String utility functions
Copyright (C) 1999-2002, Joe Orton <joe@manyfish.co.uk>
Copyright (C) 1999-2002, 2004, Joe Orton <joe@manyfish.co.uk>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@ -57,17 +57,6 @@ char *ne_base64(const unsigned char *text, size_t len);
* or zero on decode error (in which case *out is undefined). */
size_t ne_unbase64(const char *data, unsigned char **out);
/*** OBSOLETE INTERFACES ***/
char **split_string(const char *str, const char seperator,
const char *quotes, const char *whitespace);
char **split_string_c(const char *str, const char seperator,
const char *quotes, const char *whitespace, int *count);
char **pair_string(const char *str, const char compsep, const char kvsep,
const char *quotes, const char *whitespace);
void split_string_free(char **components);
void pair_string_free(char **pairs);
/*** END OF OBSOLETE INTERFACES */
/* String buffer handling. (Strings are zero-terminated still). A
* string buffer ne_buffer * which grows dynamically with the
* string. */
@ -132,6 +121,15 @@ char *ne_concat(const char *str, ...);
#define NE_ASC2HEX(x) (((x) <= '9') ? ((x) - '0') : (tolower((x)) + 10 - 'a'))
#define NE_HEX2ASC(x) ((char) ((x) > 9 ? ((x) - 10 + 'a') : ((x) + '0')))
/* Wrapper for snprintf: always NUL-terminates returned buffer, and
* returns strlen(str). */
size_t ne_snprintf(char *str, size_t size, const char *fmt, ...)
ne_attribute((format(printf, 3, 4)));
/* Wrapper for vsnprintf. */
size_t ne_vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
ne_attribute((format(printf, 3, 0)));
END_NEON_DECLS
#endif /* NE_STRING_H */

View File

@ -1,6 +1,6 @@
/*
Stubs for SSL support when no SSL library has been configured
Copyright (C) 2002-2003, Joe Orton <joe@manyfish.co.uk>
Copyright (C) 2002-2004, Joe Orton <joe@manyfish.co.uk>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@ -82,14 +82,22 @@ void ne_ssl_clicert_free(ne_ssl_client_cert *ccert) {}
void ne_ssl_trust_default_ca(ne_session *sess) {}
ne_ssl_context *ne_ssl_context_create(void)
ne_ssl_context *ne_ssl_context_create(int mode)
{
return NULL;
}
void ne_ssl_ctx_trustcert(ne_ssl_context *ctx, const ne_ssl_certificate *cert)
void ne_ssl_context_trustcert(ne_ssl_context *ctx, const ne_ssl_certificate *cert)
{}
int ne_ssl_context_set_verify(ne_ssl_context *ctx,
int required,
const char *ca_names,
const char *verify_cas)
{
return -1;
}
void ne_ssl_context_destroy(ne_ssl_context *ctx) {}
int ne_ssl_cert_digest(const ne_ssl_certificate *cert, char digest[60])

View File

@ -34,9 +34,10 @@
#include <stdlib.h>
#endif
#include <stdio.h>
#include <ctype.h>
#include "ne_utils.h" /* for 'min' */
#include "ne_string.h" /* for ne_buffer */
#include "ne_alloc.h"
#include "ne_uri.h"
@ -277,6 +278,11 @@ int ne_uri_cmp(const ne_uri *u1, const ne_uri *u2)
#undef CMP
#undef CASECMP
#ifndef WIN32
#undef min
#define min(a,b) ((a)<(b)?(a):(b))
#endif
/* TODO: implement properly */
int ne_path_compare(const char *a, const char *b)
{

View File

@ -30,10 +30,18 @@
#include <stdio.h>
#include <ctype.h> /* isdigit() for ne_parse_statusline */
#ifdef NEON_SSL
#ifdef NE_HAVE_ZLIB
#include <zlib.h>
#endif
#ifdef HAVE_OPENSSL
#include <openssl/opensslv.h>
#endif
#ifdef HAVE_GNUTLS
#include <gnutls/gnutls.h>
#endif
/* libxml2: pick up the version string. */
#if defined(HAVE_LIBXML)
#include <libxml/xmlversion.h>
@ -41,10 +49,6 @@
#include <expat.h>
#endif
#ifdef NEON_ZLIB
#include <zlib.h>
#endif
#include "ne_utils.h"
#include "ne_string.h" /* for ne_strdup */
#include "ne_dates.h"
@ -78,12 +82,15 @@ void ne_debug(int ch, const char *template, ...)
#define NE_STRINGIFY(x) # x
#define NE_EXPAT_VER(x,y,z) NE_STRINGIFY(x) "." NE_STRINGIFY(y) "." NE_STRINGIFY(z)
static const char *version_string = "neon " NEON_VERSION ": "
static const char version_string[] = "neon " NEON_VERSION ": "
#ifdef NEON_IS_LIBRARY
"Library build"
#else
"Bundled build"
#endif
#ifdef NE_HAVE_IPV6
", IPv6"
#endif
#ifdef HAVE_EXPAT
", Expat"
/* expat >=1.95.2 exported the version */
@ -95,19 +102,25 @@ static const char *version_string = "neon " NEON_VERSION ": "
", libxml " LIBXML_DOTTED_VERSION
#endif /* HAVE_LIBXML */
#endif /* !HAVE_EXPAT */
#if defined(NEON_ZLIB) && defined(ZLIB_VERSION)
#if defined(NE_HAVE_ZLIB) && defined(ZLIB_VERSION)
", zlib " ZLIB_VERSION
#endif /* NEON_ZLIB && ... */
#ifdef NEON_SOCKS
#endif /* NE_HAVE_ZLIB && ... */
#ifdef NE_HAVE_SOCKS
", SOCKSv5"
#endif
#ifdef NEON_SSL
#ifdef NE_HAVE_IDNA
", IDNA"
#endif
#ifdef HAVE_OPENSSL
#ifdef OPENSSL_VERSION_TEXT
", " OPENSSL_VERSION_TEXT
#else
"OpenSSL (unknown version)"
#endif /* OPENSSL_VERSION_TEXT */
#endif
#endif /* HAVE_OPENSSL */
#ifdef HAVE_GNUTLS
", GNU TLS " LIBGNUTLS_VERSION
#endif /* HAVE_GNUTLS */
"."
;
@ -121,13 +134,31 @@ int ne_version_match(int major, int minor)
return (NEON_VERSION_MAJOR != major) || (NEON_VERSION_MINOR < minor);
}
int ne_supports_ssl(void)
int ne_has_support(int feature)
{
#ifdef NEON_SSL
return 1;
#else
return 0;
switch (feature) {
#ifdef NE_HAVE_SSL
case NE_FEATURE_SSL:
#endif
#ifdef NE_HAVE_ZLIB
case NE_FEATURE_ZLIB:
#endif
#ifdef NE_HAVE_IPV6
case NE_FEATURE_IPV6:
#endif
#ifdef NE_HAVE_IDNA
case NE_FEATURE_IDNA:
#endif
#ifdef NE_HAVE_SOCKS
case NE_FEATURE_SOCKS:
#endif
#ifdef NE_HAVE_LFS
case NE_FEATURE_LFS:
#endif
return 1;
default:
return 0;
}
}
int ne_parse_statusline(const char *status_line, ne_status *st)

View File

@ -1,6 +1,6 @@
/*
HTTP utility functions
Copyright (C) 1999-2002, Joe Orton <joe@manyfish.co.uk>
Copyright (C) 1999-2004, Joe Orton <joe@manyfish.co.uk>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@ -46,22 +46,16 @@ const char *ne_version_string(void);
* 'minor'. */
int ne_version_match(int major, int minor);
/* Returns non-zero if neon has support for SSL. */
int ne_supports_ssl(void);
#define NE_FEATURE_SSL (1) /* SSL/TLS support */
#define NE_FEATURE_ZLIB (2) /* zlib compression in compress interface */
#define NE_FEATURE_IPV6 (3) /* IPv6 is supported in resolver */
#define NE_FEATURE_IDNA (4) /* internationalized domain name support */
#define NE_FEATURE_LFS (5) /* large file support */
#define NE_FEATURE_SOCKS (6) /* SOCKSv5 support */
/* Use replacement snprintf's if trio is being used. */
#ifdef NEON_TRIO
#define ne_snprintf trio_snprintf
#define ne_vsnprintf trio_vsnprintf
#else
#define ne_snprintf snprintf
#define ne_vsnprintf vsnprintf
#endif
#ifndef WIN32
#undef min
#define min(a,b) ((a)<(b)?(a):(b))
#endif
/* Returns non-zero if neon has support for given feature code
* NE_FEATURE_*. */
int ne_has_support(int feature);
/* CONSIDER: mutt has a nicer way of way of doing debugging output... maybe
* switch to like that. */

View File

@ -1,5 +1,5 @@
/*
Higher Level Interface to XML Parsers.
Wrapper interface to XML parser
Copyright (C) 1999-2004, Joe Orton <joe@manyfish.co.uk>
This library is free software; you can redistribute it and/or
@ -96,9 +96,11 @@ struct ne_xml_parser_s {
struct element *current; /* current element in the branch */
struct handler *top_handlers; /* always points at the
* handler on top of the stack. */
int valid; /* non-zero whilst parse should continue */
int failure; /* zero whilst parse should continue */
int prune; /* if non-zero, depth within a dead branch */
int bom_pos;
#ifdef HAVE_EXPAT
XML_Parser parser;
char *encoding;
@ -193,6 +195,21 @@ const char *ne_xml_doc_encoding(const ne_xml_parser *p)
#endif
}
/* The first character of the REC-xml-names "NCName" rule excludes
* "Digit | '.' | '-' | '_' | CombiningChar | Extender"; the XML
* parser will not enforce this rule in a namespace declaration since
* it treats the entire attribute name as a REC-xml "Name" rule. It's
* too hard to check for all of CombiningChar | Digit | Extender here,
* but the valid_ncname_ch1 macro catches some of the rest. */
/* Return non-zero if 'ch' is an invalid start character for an NCName: */
#define invalid_ncname_ch1(ch) ((ch) == '\0' || strchr("-.0123456789", (ch)) != NULL)
/* Subversion repositories have been deployed which use property names
* marshalled as NCNames including a colon character; these should
* also be rejected but will be allowed for the time being. */
#define invalid_ncname(xn) (invalid_ncname_ch1((xn)[0]))
/* Extract the namespace prefix declarations from 'atts'. */
static int declare_nspaces(ne_xml_parser *p, struct element *elm,
const ne_xml_char **atts)
@ -200,13 +217,15 @@ static int declare_nspaces(ne_xml_parser *p, struct element *elm,
int n;
for (n = 0; atts && atts[n]; n += 2) {
if (strcasecmp(atts[n], "xmlns") == 0) {
if (strcmp(atts[n], "xmlns") == 0) {
/* New default namespace */
elm->default_ns = ne_strdup(atts[n+1]);
} else if (strncasecmp(atts[n], "xmlns:", 6) == 0) {
} else if (strncmp(atts[n], "xmlns:", 6) == 0) {
struct namespace *ns;
if (atts[n][6] == '\0' || atts[n+1][0] == '\0') {
/* Reject some invalid NCNames as namespace prefix, and an
* empty URI as the namespace URI */
if (invalid_ncname(atts[n] + 6) || atts[n+1][0] == '\0') {
ne_snprintf(p->error, ERR_SIZE,
("XML parse error at line %d: invalid namespace "
"declaration"), ne_xml_currentline(p));
@ -243,22 +262,20 @@ static int expand_qname(ne_xml_parser *p, struct element *elm,
elm->name = ne_strdup(qname);
elm->nspace = e->default_ns;
} else if (invalid_ncname(pfx + 1) || qname == pfx) {
ne_snprintf(p->error, ERR_SIZE,
_("XML parse error at line %d: invalid element name"),
ne_xml_currentline(p));
return -1;
} else {
const char *uri = resolve_nspace(elm, qname, pfx-qname);
if (uri) {
/* The name is everything after the ':' */
if (pfx[1] == '\0') {
ne_snprintf(p->error, ERR_SIZE,
("XML parse error at line %d: element name missing"
"after namespace prefix"), ne_xml_currentline(p));
return -1;
}
elm->name = ne_strdup(pfx+1);
elm->nspace = uri;
} else {
ne_snprintf(p->error, ERR_SIZE,
("XML parse error at line %d: undeclared namespace"),
("XML parse error at line %d: undeclared namespace prefix"),
ne_xml_currentline(p));
return -1;
}
@ -275,7 +292,7 @@ static void start_element(void *userdata, const ne_xml_char *name,
struct handler *hand;
int state = NE_XML_DECLINE;
if (!p->valid) return;
if (p->failure) return;
if (p->prune) {
p->prune++;
@ -288,7 +305,7 @@ static void start_element(void *userdata, const ne_xml_char *name,
p->current = elm;
if (declare_nspaces(p, elm, atts) || expand_qname(p, elm, name)) {
p->valid = 0;
p->failure = 1;
return;
}
@ -308,8 +325,8 @@ static void start_element(void *userdata, const ne_xml_char *name,
else if (state == NE_XML_DECLINE)
/* prune this branch. */
p->prune++;
else /* state == NE_XML_ABORT */
p->valid = 0;
else /* state < 0 => abort parse */
p->failure = state;
}
/* Destroys an element structure. */
@ -337,12 +354,11 @@ static void char_data(void *userdata, const ne_xml_char *data, int len)
ne_xml_parser *p = userdata;
struct element *elm = p->current;
if (!p->valid || p->prune) return;
if (p->failure || p->prune) return;
if (elm->handler->cdata_cb &&
elm->handler->cdata_cb(elm->handler->userdata, elm->state, data, len)) {
NE_DEBUG(NE_DBG_XML, "Cdata callback failed.\n");
p->valid = 0;
if (elm->handler->cdata_cb) {
p->failure = elm->handler->cdata_cb(elm->handler->userdata, elm->state, data, len);
NE_DEBUG(NE_DBG_XML, "Cdata callback returned %d.\n", p->failure);
}
}
@ -352,15 +368,17 @@ static void end_element(void *userdata, const ne_xml_char *name)
ne_xml_parser *p = userdata;
struct element *elm = p->current;
if (!p->valid) return;
if (p->failure) return;
if (p->prune) {
if (p->prune-- > 1) return;
} else if (elm->handler->endelm_cb &&
elm->handler->endelm_cb(elm->handler->userdata, elm->state,
elm->nspace, elm->name)) {
NE_DEBUG(NE_DBG_XML, "XML: end-element for %d failed.\n", elm->state);
p->valid = 0;
} else if (elm->handler->endelm_cb) {
p->failure = elm->handler->endelm_cb(elm->handler->userdata, elm->state,
elm->nspace, elm->name);
if (p->failure) {
NE_DEBUG(NE_DBG_XML, "XML: end-element for %d failed with %d.\n",
elm->state, p->failure);
}
}
NE_DEBUG(NE_DBG_XMLPARSE, "XML: end-element (%d, {%s, %s})\n",
@ -397,8 +415,6 @@ static const char *resolve_nspace(const struct element *elm,
ne_xml_parser *ne_xml_create(void)
{
ne_xml_parser *p = ne_calloc(sizeof *p);
/* Initialize other stuff */
p->valid = 1;
/* Placeholder for the root element */
p->current = p->root = ne_calloc(sizeof *p->root);
p->root->default_ns = "";
@ -448,24 +464,22 @@ void ne_xml_push_handler(ne_xml_parser *p,
}
}
void ne_xml_parse_v(void *userdata, const char *block, size_t len)
int ne_xml_parse_v(void *userdata, const char *block, size_t len)
{
ne_xml_parser *p = userdata;
/* FIXME: The two XML parsers break all our nice abstraction by
* choosing different char *'s. The swine. This cast will come
* back and bite us someday, no doubt. */
ne_xml_parse(p, block, len);
return ne_xml_parse(p, (const ne_xml_char *)block, len);
}
/* Parse the given block of input of length len */
void ne_xml_parse(ne_xml_parser *p, const char *block, size_t len)
#define BOM_UTF8 "\xEF\xBB\xBF" /* UTF-8 BOM */
int ne_xml_parse(ne_xml_parser *p, const char *block, size_t len)
{
int ret, flag;
/* duck out if it's broken */
if (!p->valid) {
if (p->failure) {
NE_DEBUG(NE_DBG_XML, "Not parsing %" NE_FMT_SIZE_T " bytes.\n",
len);
return;
return p->failure;
}
if (len == 0) {
flag = -1;
@ -476,34 +490,54 @@ void ne_xml_parse(ne_xml_parser *p, const char *block, size_t len)
len);
flag = 0;
}
/* Note, don't write a parser error if !p->valid, since an error
if (p->bom_pos < 3) {
while (len > 0 && p->bom_pos < 3 &&
block[0] == BOM_UTF8[p->bom_pos]) {
block++;
len--;
p->bom_pos++;
}
if (len == 0)
return 0;
if (p->bom_pos == 0) {
p->bom_pos = 3; /* no BOM */
} else if (p->bom_pos > 0 && p->bom_pos < 3) {
strcpy(p->error, _("Invalid Byte Order Mark"));
return p->failure = 1;
}
}
/* Note, don't write a parser error if p->failure, since an error
* will already have been written in that case. */
#ifdef HAVE_EXPAT
ret = XML_Parse(p->parser, block, len, flag);
NE_DEBUG(NE_DBG_XMLPARSE, "XML_Parse returned %d\n", ret);
if (ret == 0 && p->valid) {
if (ret == 0 && p->failure == 0) {
ne_snprintf(p->error, ERR_SIZE,
"XML parse error at line %d: %s",
XML_GetCurrentLineNumber(p->parser),
XML_ErrorString(XML_GetErrorCode(p->parser)));
p->valid = 0;
p->failure = 1;
}
#else
ret = xmlParseChunk(p->parser, block, len, flag);
NE_DEBUG(NE_DBG_XMLPARSE, "xmlParseChunk returned %d\n", ret);
/* Parse errors are normally caught by the sax_error() callback,
* which clears p->valid. */
if (p->parser->errNo && p->valid) {
if (p->parser->errNo && p->failure == 0) {
ne_snprintf(p->error, ERR_SIZE, "XML parse error at line %d.",
ne_xml_currentline(p));
p->valid = 0;
p->failure = 1;
NE_DEBUG(NE_DBG_XMLPARSE, "XML parse error: %s\n", p->error);
}
#endif
return p->failure;
}
int ne_xml_valid(ne_xml_parser *p)
int ne_xml_failed(ne_xml_parser *p)
{
return p->valid;
return p->failure;
}
void ne_xml_destroy(ne_xml_parser *p)
@ -553,11 +587,12 @@ static void sax_error(void *ctx, const char *msg, ...)
ne_vsnprintf(buf, 1024, msg, ap);
va_end(ap);
ne_snprintf(p->error, ERR_SIZE,
_("XML parse error at line %d: %s."),
p->parser->input->line, buf);
p->valid = 0;
if (p->failure == 0) {
ne_snprintf(p->error, ERR_SIZE,
_("XML parse error at line %d: %s."),
p->parser->input->line, buf);
p->failure = 1;
}
}
#endif

View File

@ -1,6 +1,6 @@
/*
neon XML parser interface
Copyright (C) 1999-2003, Joe Orton <joe@manyfish.co.uk>
Copyright (C) 1999-2004, Joe Orton <joe@manyfish.co.uk>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@ -86,31 +86,38 @@ void ne_xml_push_handler(ne_xml_parser *p,
ne_xml_endelm_cb *endelm,
void *userdata);
/* Returns non-zero if the parse was valid, zero if it failed (e.g.,
* any of the callbacks failed, the XML was not well-formed, etc).
* Use ne_xml_get_error to retrieve the error message if it failed. */
int ne_xml_valid(ne_xml_parser *p);
/* ne_xml_failed returns non-zero if there was an error during
* parsing, or zero if the parse completed successfully. The return
* value is equal to that of the last ne_xml_parse call for this
* parser. */
int ne_xml_failed(ne_xml_parser *p);
/* Set error string for parser: the string may be truncated. */
void ne_xml_set_error(ne_xml_parser *p, const char *msg);
/* Return the error string (never NULL). After ne_xml_failed returns
* >0, this will describe the parse error. Otherwise it will be a
* default error string. */
const char *ne_xml_get_error(ne_xml_parser *p);
/* Destroy the parser object. */
void ne_xml_destroy(ne_xml_parser *p);
/* Parse the given block of input of length len. Block does not need
* to be NUL-terminated. */
void ne_xml_parse(ne_xml_parser *p, const char *block, size_t len);
/* Parse the given block of input of length len. Parser must be
* called with len=0 to signify the end of the document (for that
* case, the block argument is ignored). Returns zero on success, or
* non-zero on error: for an XML syntax error, a positive number is
* returned; if parsing is aborted by a caller-supplied callback, that
* callback's return value is returned. */
int ne_xml_parse(ne_xml_parser *p, const char *block, size_t len);
/* As above, casting (ne_xml_parser *)userdata internally.
* (This function can be passed to ne_add_response_body_reader) */
void ne_xml_parse_v(void *userdata, const char *block, size_t len);
int ne_xml_parse_v(void *userdata, const char *block, size_t len);
/* Return current parse line for errors */
int ne_xml_currentline(ne_xml_parser *p);
/* Set error string for parser. */
void ne_xml_set_error(ne_xml_parser *p, const char *msg);
/* Return the error string for the parser and never NULL. */
const char *ne_xml_get_error(ne_xml_parser *p);
/* From a start_element callback which was passed 'attrs' using given
* parser, return attribute of given name and namespace. If nspace is
* NULL, no namespace resolution is performed. */

View File

@ -1,6 +1,25 @@
Wed Aug 25 21:05:28 2004 Joe Orton <joe@manyfish.co.uk>
* cookies.c: Removed.
* Makefile.in: Updated.
Wed Aug 25 19:47:28 2004 Joe Orton <joe@manyfish.co.uk>
* socket.c (do_connect, begin): Simplify do_connect use.
Wed Aug 25 18:28:19 2004 Joe Orton <joe@manyfish.co.uk>
* xml.c (matches, fail_parse): Test for UTF-8 BOM handling.
Mon Jul 5 18:41:07 2004 Joe Orton <joe@manyfish.co.uk>
* basic.c (content_type): Test for correct default charset for
text/xml content-type by RFC3280.
Mon Jul 5 10:59:17 2004 Joe Orton <joe@manyfish.co.uk>
Add regression tests for trio of ne_compress.c bugs:
Add XFAIL regression tests for trio of ne_compress.c bugs:
* compress.c (reader): Validate that a size=0 call comes only
after the expected response data, and use struct string.
@ -16,12 +35,6 @@ Sun Jul 4 21:55:00 2004 Joe Orton <joe@manyfish.co.uk>
* sockets.c: All callers updated.
Tue May 18 21:00:07 2004 Joe Orton <joe@manyfish.co.uk>
* ssl.c (fail_ssl_request):
* basic.c (do_range): Fix false negatives from gcc
-Wformat-security.
Sun May 2 21:16:45 2004 Joe Orton <joe@manyfish.co.uk>
* util-tests.c (regress_dates): Add regression tests.
@ -31,6 +44,39 @@ Wed Apr 14 10:45:43 2004 Joe Orton <joe@manyfish.co.uk>
* props.c (regress, patch_regress): Add regression tests for
CAN-2004-0179 issues.
Thu Apr 8 13:57:04 2004 Joe Orton <joe@manyfish.co.uk>
* largefile.c (read_large_response): Go faster: turn off debugging
during request dispatch.
Wed Apr 7 13:39:37 2004 Joe Orton <joe@manyfish.co.uk>
* auth.c (basic): Add some multi-scheme challenges.
Wed Apr 7 13:14:16 2004 Joe Orton <joe@manyfish.co.uk>
* request.c (s_progress): Use NE_FMT_OFF_T for printing off_t's
throughout.
Sun Feb 22 23:38:05 2004 Joe Orton <joe@manyfish.co.uk>
* request.c (expect_100_once, serve_100_once): Adjust for new
100-continue interface.
(expect_100_nobody): New test.
Sun Feb 22 20:39:15 2004 Joe Orton <joe@manyfish.co.uk>
* cookies.c (parsing): Use ne_cookie_empty_cache.
Sun Feb 22 17:28:41 2004 Joe Orton <joe@manyfish.co.uk>
* props.c (pfind_simple): Test for whitespace handling.
Sun Feb 22 16:31:52 2004 Joe Orton <joe@manyfish.co.uk>
* auth.c (basic): Test handling of Basic challenge in presence of
multiple challenges.
Sun Feb 15 12:34:13 2004 Joe Orton <joe@manyfish.co.uk>
* makekeys.sh, openssl.conf: Create new utf8subj.cert,
@ -39,10 +85,67 @@ Sun Feb 15 12:34:13 2004 Joe Orton <joe@manyfish.co.uk>
* ssl.c (dname_readable): Test that ne_ssl_readable_dname always
gives back UTF-8.
Sat Feb 14 21:59:17 2004 Joe Orton <joe@manyfish.co.uk>
* xml.c (fail_parse): Add tests for invalid NCNames in namespace
prefix declaration and as element names.
Sun Jan 25 15:21:56 2004 Joe Orton <joe@manyfish.co.uk>
* largefile.c (serve_large_response, read_large_response): New
test.
Sat Jan 24 18:10:14 2004 Joe Orton <joe@manyfish.co.uk>
* Makefile.in: Fix test suite for 'make' implementatinos which
don't handle single-suffix inference rules.
Sat Jan 3 14:10:14 2004 Joe Orton <joe@manyfish.co.uk>
* largefile.c (send_high_offset): Renamed from send_large_file.
Sat Jan 3 13:57:16 2004 Joe Orton <joe@manyfish.co.uk>
* Makefile.in (BASIC_TESTS): Add cookies.
Thu Jan 1 17:42:30 2004 Joe Orton <joe@manyfish.co.uk>
* util-tests.c (support): Check for NE_FEATURE_LFS.
* largefile.c: New file.
* Makefile.in: Add lfs-check, largefile, largefile.lo targets.
Sat Nov 15 08:04:22 2003 Joe Orton <joe@manyfish.co.uk>
* request.c (idna_hostname, dup_header, serve_check_host): New
test.
Fri Nov 14 14:06:57 2003 Joe Orton <joe@manyfish.co.uk>
* util-tests.c (support): Test for NE_FEATURE_IDNA.
Fri Nov 14 11:26:29 2003 Joe Orton <joe@manyfish.co.uk>
* acl.c: Remove NEON_NODAV condition.
* stubs.c: Use new NE_HAVE_* conditions.
* util-tests.c (supports): Test new ne_has_support interface.
Thu Nov 13 20:33:44 2003 Joe Orton <joe@manyfish.co.uk>
* request.c (no_body_205): New test.
Tue Nov 11 20:36:43 2003 Joe Orton <joe@manyfish.co.uk>
Adjust for ne_xml_valid->ne_xml_failure API change.
* xml.c (chardata, startelm_abort, endelm_abort, parse_match):
Check for propagation of negative failure codes.
(fail_parse): Check for positive failure code.
(attributes): Use ne_xml_failure.
Sat Oct 25 00:11:29 2003 Joe Orton <joe@manyfish.co.uk>
* ssl.c (fail_truncated_eof): Remove test.

View File

@ -19,10 +19,11 @@ CC = @CC@
OPENSSL = @OPENSSL@
HELPERS = @HELPERS@
BASIC_TESTS = uri-tests util-tests string-tests session socket \
request auth basic stubs redirect
BASIC_TESTS = uri-tests util-tests string-tests socket \
session request auth basic stubs redirect
ZLIB_TESTS = compress
ZLIB_HELPERS = file1.gz file2.gz trailing.gz badcsum.gz truncated.gz corrupt1.gz corrupt2.gz
ZLIB_HELPERS = file1.gz file2.gz trailing.gz badcsum.gz truncated.gz \
corrupt1.gz corrupt2.gz empty.gz
DAV_TESTS = xml acl props lock
SSL_TESTS = socket-ssl ssl
SSL_HELPERS = ca-stamp
@ -52,7 +53,7 @@ clean:
rm -f $(TESTS) $(HELPERS) *.*o common/*.*o libtest.a *.log
rm -rf ca .libs
rm -f ca-stamp client.key *.csr ssigned.pem wrongcn.pem \
server.cert client.cert client.p12 *.cert
server.cert client.cert client.p12 *.cert sparse.bin
check: $(TESTS) $(HELPERS)
@SRCDIR=$(srcdir) $(SHELL) $(srcdir)/run.sh $(TESTS)
@ -60,6 +61,9 @@ check: $(TESTS) $(HELPERS)
grind: $(TESTS) $(HELPERS)
@SRCDIR=$(srcdir) HARNESS="$(VALGRIND)" $(SHELL) $(srcdir)/run.sh $(TESTS)
lfs-check: largefile $(LFS_HELPERS)
@SRCDIR=$(srcdir) $(SHELL) $(srcdir)/run.sh largefile
NEWS = $(top_srcdir)/NEWS
file1.gz: $(NEWS)
@ -87,6 +91,9 @@ corrupt1.gz: file1.gz
corrupt2.gz:
cat $(NEWS) > $@
empty.gz:
touch $@
# Dummy target to create the CA keys etc. makekeys stderr is redirected
# since it changes for every invocation; not helpful for regression
# testing.
@ -107,9 +114,6 @@ $(LIBTEST): $(LIBOBJS)
.c.lo:
$(COMPILE) -c $< -o $@
.lo:
$(LINK) -o $@ $< $(LIBS)
# Recompile socket.c with SOCKET_SSL defined
socket-ssl.lo: $(srcdir)/socket.c $(HDRS)
$(COMPILE) -DSOCKET_SSL -c $(srcdir)/socket.c -o $@
@ -120,6 +124,9 @@ socket-ssl: socket-ssl.lo $(LIBTEST)
resolve: resolve.lo $(LIBNEON)
$(LINK) -o $@ resolve.lo $(LIBNEON)
common/tests.lo: $(srcdir)/common/tests.c $(OBJDEPS)
common/child.lo: $(srcdir)/common/child.c $(OBJDEPS)
utils.lo: $(srcdir)/utils.c $(OBJDEPS)
auth.lo: $(srcdir)/auth.c $(OBJDEPS)
uri-tests.lo: $(srcdir)/uri-tests.c $(OBJDEPS)
util-tests.lo: $(srcdir)/util-tests.c $(OBJDEPS)
@ -137,26 +144,46 @@ session.lo: $(srcdir)/session.c $(OBJDEPS)
redirect.lo: $(srcdir)/redirect.c $(OBJDEPS)
basic.lo: $(srcdir)/basic.c $(OBJDEPS)
ssl.lo: $(srcdir)/ssl.c $(OBJDEPS)
cookies.lo: $(srcdir)/cookies.c $(OBJDEPS)
lock.lo: $(srcdir)/lock.c $(OBJDEPS)
largefile.lo: $(srcdir)/largefile.c $(OBJDEPS)
auth: auth.lo $(DEPS)
$(LINK) -o $@ auth.lo $(DEPS)
basic: basic.lo $(DEPS)
$(LINK) -o $@ basic.lo $(DEPS)
uri-tests: uri-tests.lo $(DEPS)
$(LINK) -o $@ uri-tests.lo $(DEPS)
util-tests: util-tests.lo $(DEPS)
$(LINK) -o $@ util-tests.lo $(DEPS)
string-tests: string-tests.lo $(DEPS)
$(LINK) -o $@ string-tests.lo $(DEPS)
socket: socket.lo $(DEPS)
$(LINK) -o $@ socket.lo $(DEPS)
server: server.lo $(DEPS)
$(LINK) -o $@ server.lo $(DEPS)
request: request.lo $(DEPS)
$(LINK) -o $@ request.lo $(DEPS)
regress: regress.lo $(DEPS)
$(LINK) -o $@ regress.lo $(DEPS)
compress: compress.lo $(DEPS)
$(LINK) -o $@ compress.lo $(DEPS)
acl: acl.lo $(DEPS)
$(LINK) -o $@ acl.lo $(DEPS)
utils: utils.lo $(DEPS)
$(LINK) -o $@ utils.lo $(DEPS)
stubs: stubs.lo $(DEPS)
$(LINK) -o $@ stubs.lo $(DEPS)
props: props.lo $(DEPS)
$(LINK) -o $@ props.lo $(DEPS)
session: session.lo $(DEPS)
$(LINK) -o $@ session.lo $(DEPS)
redirect: redirect.lo $(DEPS)
basic: basic.lo $(DEPS)
$(LINK) -o $@ redirect.lo $(DEPS)
ssl: ssl.lo $(DEPS)
$(LINK) -o $@ ssl.lo $(DEPS)
xml: xml.lo $(DEPS)
$(LINK) -o $@ xml.lo $(DEPS)
lock: lock.lo $(DEPS)
cookies: cookies.lo $(DEPS)
$(LINK) -o $@ lock.lo $(DEPS)
largefile: largefile.lo $(DEPS)
$(LINK) -o $@ largefile.lo $(DEPS)

View File

@ -24,18 +24,6 @@
#include "child.h"
#include "utils.h"
#ifdef NEON_NODAV
static int skip(void)
{
t_context("built without WebDAV support");
return SKIP;
}
ne_test tests[] = { T(skip), T(NULL) };
#else
/**** DUMMY TESTS: just makes sure the stuff doesn't dump core. */
static int test_acl(const char *uri, ne_acl_entry *es, int nume)
@ -111,5 +99,3 @@ ne_test tests[] = {
T(deny_byprop),
T(NULL)
};
#endif /* NEON_NODAV */

View File

@ -1,6 +1,6 @@
/*
Authentication tests
Copyright (C) 2001-2003, Joe Orton <joe@manyfish.co.uk>
Copyright (C) 2001-2004, Joe Orton <joe@manyfish.co.uk>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -40,11 +40,16 @@
static const char username[] = "Aladdin", password[] = "open sesame";
static int auth_failed;
static const char www_wally[] = "WWW-Authenticate: Basic realm=WallyWorld";
#define BASIC_WALLY "Basic realm=WallyWorld"
#define CHAL_WALLY "WWW-Authenticate: " BASIC_WALLY
static int auth_cb(void *userdata, const char *realm, int tries,
char *un, char *pw)
{
if (strcmp(realm, "WallyWorld")) {
NE_DEBUG(NE_DBG_HTTP, "Got wrong realm '%s'!\n", realm);
return -1;
}
strcpy(un, username);
strcpy(pw, password);
return tries;
@ -87,6 +92,8 @@ static int send_response(ne_socket *sock, const char *hdr, int code, int eoc)
* second doesn't. */
static int auth_serve(ne_socket *sock, void *userdata)
{
char *hdr = userdata;
auth_failed = 1;
/* Register globals for discard_request. */
@ -94,7 +101,7 @@ static int auth_serve(ne_socket *sock, void *userdata)
want_header = "Authorization";
discard_request(sock);
send_response(sock, www_wally, 401, 0);
send_response(sock, hdr, 401, 0);
discard_request(sock);
send_response(sock, NULL, auth_failed?500:200, 1);
@ -102,33 +109,71 @@ static int auth_serve(ne_socket *sock, void *userdata)
return 0;
}
/* Test that various Basic auth challenges are correctly handled. */
static int basic(void)
{
ne_session *sess;
const char *hdrs[] = {
/* simplest case */
CHAL_WALLY,
CALL(make_session(&sess, auth_serve, NULL));
ne_set_server_auth(sess, auth_cb, NULL);
/* several challenges, one header */
"WWW-Authenticate: BarFooScheme, " BASIC_WALLY,
CALL(any_2xx_request(sess, "/norman"));
/* several challenges, one header */
CHAL_WALLY ", BarFooScheme realm=\"PenguinWorld\"",
/* whitespace tests. */
"WWW-Authenticate: Basic realm=WallyWorld ",
/* nego test. */
"WWW-Authenticate: Negotiate fish, Basic realm=WallyWorld",
/* nego test. */
"WWW-Authenticate: Negotiate fish, bar=boo, Basic realm=WallyWorld",
/* multi-header case 1 */
"WWW-Authenticate: BarFooScheme\r\n"
CHAL_WALLY,
/* multi-header cases 1 */
CHAL_WALLY "\r\n"
"WWW-Authenticate: BarFooScheme bar=\"foo\"",
/* multi-header case 3 */
"WWW-Authenticate: FooBarChall foo=\"bar\"\r\n"
CHAL_WALLY "\r\n"
"WWW-Authenticate: BarFooScheme bar=\"foo\""
};
size_t n;
for (n = 0; n < sizeof(hdrs)/sizeof(hdrs[0]); n++) {
ne_session *sess;
CALL(make_session(&sess, auth_serve, (void *)hdrs[n]));
ne_set_server_auth(sess, auth_cb, NULL);
CALL(any_2xx_request(sess, "/norman"));
ne_session_destroy(sess);
CALL(await_server());
}
ne_session_destroy(sess);
CALL(await_server());
return OK;
}
static int retry_serve(ne_socket *sock, void *ud)
{
discard_request(sock);
send_response(sock, www_wally, 401, 0);
send_response(sock, CHAL_WALLY, 401, 0);
discard_request(sock);
send_response(sock, www_wally, 401, 0);
send_response(sock, CHAL_WALLY, 401, 0);
discard_request(sock);
send_response(sock, NULL, 200, 0);
discard_request(sock);
send_response(sock, www_wally, 401, 0);
send_response(sock, CHAL_WALLY, 401, 0);
discard_request(sock);
send_response(sock, NULL, 200, 0);
@ -140,19 +185,19 @@ static int retry_serve(ne_socket *sock, void *ud)
send_response(sock, NULL, 200, 0);
discard_request(sock);
send_response(sock, www_wally, 401, 0);
send_response(sock, CHAL_WALLY, 401, 0);
discard_request(sock);
send_response(sock, NULL, 200, 0);
discard_request(sock);
send_response(sock, www_wally, 401, 0);
send_response(sock, CHAL_WALLY, 401, 0);
discard_request(sock);
send_response(sock, www_wally, 401, 0);
send_response(sock, CHAL_WALLY, 401, 0);
discard_request(sock);
send_response(sock, www_wally, 401, 0);
send_response(sock, CHAL_WALLY, 401, 0);
discard_request(sock);
send_response(sock, NULL, 200, 0);
@ -296,8 +341,8 @@ static int tunnel_regress(void)
/* test digest auth 2617-style. */
/* negotiation: within a single header, multiple headers.
* check digest has precedence */
/* test that digest has precedence over Basic for multi-scheme
* challenges */
/* test auth-int, auth-int FAILURE. chunk trailers/non-trailer */

View File

@ -46,8 +46,10 @@ static int content_type(void)
{ "foo/bar", "foo", "bar", NULL },
{ "foo/bar ", "foo", "bar", NULL },
{ "application/xml", "application", "xml", NULL },
/* text/ subtypes default to charset ISO-8859-1. */
/* text/ subtypes default to charset ISO-8859-1, per 2616. */
{ "text/lemon", "text", "lemon", "ISO-8859-1" },
/* text/xml defaults to charset us-ascii, per 3280 */
{ "text/xml", "text", "xml", "us-ascii" },
#undef TXU
#define TXU "text", "xml", "utf-8"
/* 2616 doesn't *say* that charset can be quoted, but bets are

15
neon/test/ca1.pem Normal file
View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICQTCCAeugAwIBAgIBADANBgkqhkiG9w0BAQQFADCBnzELMAkGA1UEBhMCR0Ix
FTATBgNVBAgTDExpbmNvbG5zaGlyZTEQMA4GA1UEBxMHTGluY29sbjERMA8GA1UE
ChMIQ0FzIEx0ZC4xGDAWBgNVBAsTD0ZpcnN0IFJhbmRvbSBDQTEaMBgGA1UEAxMR
Zmlyc3QuZXhhbXBsZS5jb20xHjAcBgkqhkiG9w0BCQEWD25lb25Ad2ViZGF2Lm9y
ZzAeFw0wNDEwMjkxMzEzNDdaFw0wNzA0MTcxMzEzNDdaMIGfMQswCQYDVQQGEwJH
QjEVMBMGA1UECBMMTGluY29sbnNoaXJlMRAwDgYDVQQHEwdMaW5jb2xuMREwDwYD
VQQKEwhDQXMgTHRkLjEYMBYGA1UECxMPRmlyc3QgUmFuZG9tIENBMRowGAYDVQQD
ExFmaXJzdC5leGFtcGxlLmNvbTEeMBwGCSqGSIb3DQEJARYPbmVvbkB3ZWJkYXYu
b3JnMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPNFTmxnz4JZA+8+SonD0qWgSBPY
WrNlH1FP+psm5EGZGmGJGvSDsk6HkyvstdopKF50UuEaJ263IorAhkmdGG0CAwEA
AaMQMA4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAANBAOvtDu4Cs6nj5DG1
NG5gqCkrVWqvjSd1jzsxOJBoN9gk/d87rAzNCvK4dTkFf9btdRZwv5OZFJzKLcU8
f7qzMnM=
-----END CERTIFICATE-----

15
neon/test/ca2.pem Normal file
View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICPzCCAemgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBnjELMAkGA1UEBhMCR0Ix
ETAPBgNVBAgTCENvcm53YWxsMREwDwYDVQQHEwhGYWxtb3V0aDERMA8GA1UEChMI
Q0FzIEx0ZC4xGTAXBgNVBAsTEFNlY29uZCBSYW5kb20gQ0ExGzAZBgNVBAMTEnNl
Y29uZC5leGFtcGxlLmNvbTEeMBwGCSqGSIb3DQEJARYPbmVvbkB3ZWJkYXYub3Jn
MB4XDTA0MTAyOTEzMTM0N1oXDTA3MDQxNzEzMTM0N1owgZ4xCzAJBgNVBAYTAkdC
MREwDwYDVQQIEwhDb3Jud2FsbDERMA8GA1UEBxMIRmFsbW91dGgxETAPBgNVBAoT
CENBcyBMdGQuMRkwFwYDVQQLExBTZWNvbmQgUmFuZG9tIENBMRswGQYDVQQDExJz
ZWNvbmQuZXhhbXBsZS5jb20xHjAcBgkqhkiG9w0BCQEWD25lb25Ad2ViZGF2Lm9y
ZzBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDzRU5sZ8+CWQPvPkqJw9KloEgT2Fqz
ZR9RT/qbJuRBmRphiRr0g7JOh5Mr7LXaKShedFLhGidutyKKwIZJnRhtAgMBAAGj
EDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADQQANIBQyploOs1JrmzZu
TATbjH6wsoEWdAUKs+UMuigRHskqK4j6PutoPWYFB+Ebxfh1miiaWS/KwFzWmPte
iNeK
-----END CERTIFICATE-----

14
neon/test/ca3.pem Normal file
View File

@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICNzCCAeGgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBmjELMAkGA1UEBhMCR0Ix
EDAOBgNVBAgTB1N1ZmZvbGsxEDAOBgNVBAcTB0lwc3dpY2gxETAPBgNVBAoTCENB
cyBMdGQuMRgwFgYDVQQLEw9UaGlyZCBSYW5kb20gQ0ExGjAYBgNVBAMTEXRoaXJk
LmV4YW1wbGUuY29tMR4wHAYJKoZIhvcNAQkBFg9uZW9uQHdlYmRhdi5vcmcwHhcN
MDQxMDI5MTMxMzQ3WhcNMDcwNDE3MTMxMzQ3WjCBmjELMAkGA1UEBhMCR0IxEDAO
BgNVBAgTB1N1ZmZvbGsxEDAOBgNVBAcTB0lwc3dpY2gxETAPBgNVBAoTCENBcyBM
dGQuMRgwFgYDVQQLEw9UaGlyZCBSYW5kb20gQ0ExGjAYBgNVBAMTEXRoaXJkLmV4
YW1wbGUuY29tMR4wHAYJKoZIhvcNAQkBFg9uZW9uQHdlYmRhdi5vcmcwXDANBgkq
hkiG9w0BAQEFAANLADBIAkEA80VObGfPglkD7z5KicPSpaBIE9has2UfUU/6mybk
QZkaYYka9IOyToeTK+y12ikoXnRS4RonbrciisCGSZ0YbQIDAQABoxAwDjAMBgNV
HRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA0EAwL7CNh2/1USUCHz55X/5BmySC1UJ
mImoh0DD0LocIQJUjGsScm3M8HXarGxl6Vfkklt/k2TMAy6YCTv+1/dazw==
-----END CERTIFICATE-----

14
neon/test/ca4.pem Normal file
View File

@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICOzCCAeWgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBnDELMAkGA1UEBhMCR0Ix
EDAOBgNVBAgTB05vcmZvbGsxEDAOBgNVBAcTB05vcndpY2gxETAPBgNVBAoTCENB
cyBMdGQuMRkwFwYDVQQLExBGb3VydGggUmFuZG9tIENBMRswGQYDVQQDExJmb3Vy
dGguZXhhbXBsZS5jb20xHjAcBgkqhkiG9w0BCQEWD25lb25Ad2ViZGF2Lm9yZzAe
Fw0wNDEwMjkxMzEzNDdaFw0wNzA0MTcxMzEzNDdaMIGcMQswCQYDVQQGEwJHQjEQ
MA4GA1UECBMHTm9yZm9sazEQMA4GA1UEBxMHTm9yd2ljaDERMA8GA1UEChMIQ0Fz
IEx0ZC4xGTAXBgNVBAsTEEZvdXJ0aCBSYW5kb20gQ0ExGzAZBgNVBAMTEmZvdXJ0
aC5leGFtcGxlLmNvbTEeMBwGCSqGSIb3DQEJARYPbmVvbkB3ZWJkYXYub3JnMFww
DQYJKoZIhvcNAQEBBQADSwAwSAJBAPNFTmxnz4JZA+8+SonD0qWgSBPYWrNlH1FP
+psm5EGZGmGJGvSDsk6HkyvstdopKF50UuEaJ263IorAhkmdGG0CAwEAAaMQMA4w
DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAANBAMxApCvWUMkO47bO/Cpy6ow2
BTb8BQW+NeSXV3EIlu1IPVJ9e1pcfTtVP5z5bseeUQSMcRWwEbV3Aie+a5xsT9Y=
-----END CERTIFICATE-----

58
neon/test/calist.pem Normal file
View File

@ -0,0 +1,58 @@
-----BEGIN CERTIFICATE-----
MIICQTCCAeugAwIBAgIBADANBgkqhkiG9w0BAQQFADCBnzELMAkGA1UEBhMCR0Ix
FTATBgNVBAgTDExpbmNvbG5zaGlyZTEQMA4GA1UEBxMHTGluY29sbjERMA8GA1UE
ChMIQ0FzIEx0ZC4xGDAWBgNVBAsTD0ZpcnN0IFJhbmRvbSBDQTEaMBgGA1UEAxMR
Zmlyc3QuZXhhbXBsZS5jb20xHjAcBgkqhkiG9w0BCQEWD25lb25Ad2ViZGF2Lm9y
ZzAeFw0wNDEwMjkxMzEzNDdaFw0wNzA0MTcxMzEzNDdaMIGfMQswCQYDVQQGEwJH
QjEVMBMGA1UECBMMTGluY29sbnNoaXJlMRAwDgYDVQQHEwdMaW5jb2xuMREwDwYD
VQQKEwhDQXMgTHRkLjEYMBYGA1UECxMPRmlyc3QgUmFuZG9tIENBMRowGAYDVQQD
ExFmaXJzdC5leGFtcGxlLmNvbTEeMBwGCSqGSIb3DQEJARYPbmVvbkB3ZWJkYXYu
b3JnMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPNFTmxnz4JZA+8+SonD0qWgSBPY
WrNlH1FP+psm5EGZGmGJGvSDsk6HkyvstdopKF50UuEaJ263IorAhkmdGG0CAwEA
AaMQMA4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAANBAOvtDu4Cs6nj5DG1
NG5gqCkrVWqvjSd1jzsxOJBoN9gk/d87rAzNCvK4dTkFf9btdRZwv5OZFJzKLcU8
f7qzMnM=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIICPzCCAemgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBnjELMAkGA1UEBhMCR0Ix
ETAPBgNVBAgTCENvcm53YWxsMREwDwYDVQQHEwhGYWxtb3V0aDERMA8GA1UEChMI
Q0FzIEx0ZC4xGTAXBgNVBAsTEFNlY29uZCBSYW5kb20gQ0ExGzAZBgNVBAMTEnNl
Y29uZC5leGFtcGxlLmNvbTEeMBwGCSqGSIb3DQEJARYPbmVvbkB3ZWJkYXYub3Jn
MB4XDTA0MTAyOTEzMTM0N1oXDTA3MDQxNzEzMTM0N1owgZ4xCzAJBgNVBAYTAkdC
MREwDwYDVQQIEwhDb3Jud2FsbDERMA8GA1UEBxMIRmFsbW91dGgxETAPBgNVBAoT
CENBcyBMdGQuMRkwFwYDVQQLExBTZWNvbmQgUmFuZG9tIENBMRswGQYDVQQDExJz
ZWNvbmQuZXhhbXBsZS5jb20xHjAcBgkqhkiG9w0BCQEWD25lb25Ad2ViZGF2Lm9y
ZzBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDzRU5sZ8+CWQPvPkqJw9KloEgT2Fqz
ZR9RT/qbJuRBmRphiRr0g7JOh5Mr7LXaKShedFLhGidutyKKwIZJnRhtAgMBAAGj
EDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADQQANIBQyploOs1JrmzZu
TATbjH6wsoEWdAUKs+UMuigRHskqK4j6PutoPWYFB+Ebxfh1miiaWS/KwFzWmPte
iNeK
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIICNzCCAeGgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBmjELMAkGA1UEBhMCR0Ix
EDAOBgNVBAgTB1N1ZmZvbGsxEDAOBgNVBAcTB0lwc3dpY2gxETAPBgNVBAoTCENB
cyBMdGQuMRgwFgYDVQQLEw9UaGlyZCBSYW5kb20gQ0ExGjAYBgNVBAMTEXRoaXJk
LmV4YW1wbGUuY29tMR4wHAYJKoZIhvcNAQkBFg9uZW9uQHdlYmRhdi5vcmcwHhcN
MDQxMDI5MTMxMzQ3WhcNMDcwNDE3MTMxMzQ3WjCBmjELMAkGA1UEBhMCR0IxEDAO
BgNVBAgTB1N1ZmZvbGsxEDAOBgNVBAcTB0lwc3dpY2gxETAPBgNVBAoTCENBcyBM
dGQuMRgwFgYDVQQLEw9UaGlyZCBSYW5kb20gQ0ExGjAYBgNVBAMTEXRoaXJkLmV4
YW1wbGUuY29tMR4wHAYJKoZIhvcNAQkBFg9uZW9uQHdlYmRhdi5vcmcwXDANBgkq
hkiG9w0BAQEFAANLADBIAkEA80VObGfPglkD7z5KicPSpaBIE9has2UfUU/6mybk
QZkaYYka9IOyToeTK+y12ikoXnRS4RonbrciisCGSZ0YbQIDAQABoxAwDjAMBgNV
HRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA0EAwL7CNh2/1USUCHz55X/5BmySC1UJ
mImoh0DD0LocIQJUjGsScm3M8HXarGxl6Vfkklt/k2TMAy6YCTv+1/dazw==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIICOzCCAeWgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBnDELMAkGA1UEBhMCR0Ix
EDAOBgNVBAgTB05vcmZvbGsxEDAOBgNVBAcTB05vcndpY2gxETAPBgNVBAoTCENB
cyBMdGQuMRkwFwYDVQQLExBGb3VydGggUmFuZG9tIENBMRswGQYDVQQDExJmb3Vy
dGguZXhhbXBsZS5jb20xHjAcBgkqhkiG9w0BCQEWD25lb25Ad2ViZGF2Lm9yZzAe
Fw0wNDEwMjkxMzEzNDdaFw0wNzA0MTcxMzEzNDdaMIGcMQswCQYDVQQGEwJHQjEQ
MA4GA1UECBMHTm9yZm9sazEQMA4GA1UEBxMHTm9yd2ljaDERMA8GA1UEChMIQ0Fz
IEx0ZC4xGTAXBgNVBAsTEEZvdXJ0aCBSYW5kb20gQ0ExGzAZBgNVBAMTEmZvdXJ0
aC5leGFtcGxlLmNvbTEeMBwGCSqGSIb3DQEJARYPbmVvbkB3ZWJkYXYub3JnMFww
DQYJKoZIhvcNAQEBBQADSwAwSAJBAPNFTmxnz4JZA+8+SonD0qWgSBPYWrNlH1FP
+psm5EGZGmGJGvSDsk6HkyvstdopKF50UuEaJ263IorAhkmdGG0CAwEAAaMQMA4w
DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAANBAMxApCvWUMkO47bO/Cpy6ow2
BTb8BQW+NeSXV3EIlu1IPVJ9e1pcfTtVP5z5bseeUQSMcRWwEbV3Aie+a5xsT9Y=
-----END CERTIFICATE-----

56
neon/test/chain.pem Normal file
View File

@ -0,0 +1,56 @@
-----BEGIN CERTIFICATE-----
MIICNzCCAeGgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBmjELMAkGA1UEBhMCVVMx
EzARBgNVBAgTCkNhbGlmb3JuaWExEDAOBgNVBAcTB09ha2xhbmQxEDAOBgNVBAoT
B05lb3NpZ24xFDASBgNVBAsTC1JhbmRvbSBEZXB0MRwwGgYDVQQDExNub3doZXJl
LmV4YW1wbGUuY29tMR4wHAYJKoZIhvcNAQkBFg9uZW9uQHdlYmRhdi5vcmcwHhcN
MDQxMDI5MTMxMzQ3WhcNMDcwNDE3MTMxMzQ3WjCBmjELMAkGA1UEBhMCVVMxEzAR
BgNVBAgTCkNhbGlmb3JuaWExEDAOBgNVBAcTB09ha2xhbmQxEDAOBgNVBAoTB05l
b3NpZ24xFDASBgNVBAsTC1JhbmRvbSBEZXB0MRwwGgYDVQQDExNub3doZXJlLmV4
YW1wbGUuY29tMR4wHAYJKoZIhvcNAQkBFg9uZW9uQHdlYmRhdi5vcmcwXDANBgkq
hkiG9w0BAQEFAANLADBIAkEAxZZK/iqR8mWCs0u3A4Vz58fik0B2RpVLF8LFmXuu
XCDNR4bjCwcOJpd+zpHrxb7LKaUYIA9Y3g1i90qylbgJBwIDAQABoxAwDjAMBgNV
HRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA0EAEGXxwEqcoz3uXP6/7QqmMhxDhrce
xAGgVRXo546dK9XW3/E6HL7vM+euPnsF/Anhjv5PSRG5pLTy2hDE+r/QuQ==
-----END CERTIFICATE-----
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 2 (0x2)
Signature Algorithm: md5WithRSAEncryption
Issuer: C=US, ST=California, L=Oakland, O=Neosign, OU=Random Dept, CN=nowhere.example.com/emailAddress=neon@webdav.org
Validity
Not Before: Oct 29 13:13:48 2004 GMT
Not After : Apr 17 13:13:48 2007 GMT
Subject: C=GB, ST=Cambridgeshire, L=Cambridge, O=Neon Hackers Ltd, OU=Neon QA Dept, CN=localhost/emailAddress=neon@webdav.org
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (512 bit)
Modulus (512 bit):
00:f3:45:4e:6c:67:cf:82:59:03:ef:3e:4a:89:c3:
d2:a5:a0:48:13:d8:5a:b3:65:1f:51:4f:fa:9b:26:
e4:41:99:1a:61:89:1a:f4:83:b2:4e:87:93:2b:ec:
b5:da:29:28:5e:74:52:e1:1a:27:6e:b7:22:8a:c0:
86:49:9d:18:6d
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Signature Algorithm: md5WithRSAEncryption
7e:43:47:e7:a6:40:a3:c0:08:ac:79:15:8b:f3:6f:50:5b:27:
a4:10:8d:61:b8:17:00:95:1e:bf:93:30:d6:19:99:b1:d6:a2:
ef:25:b4:c8:c0:06:0b:84:05:af:ae:75:f1:01:6a:83:b9:01:
35:01:11:8f:8b:35:5b:dc:3b:09
-----BEGIN CERTIFICATE-----
MIICOjCCAeSgAwIBAgIBAjANBgkqhkiG9w0BAQQFADCBmjELMAkGA1UEBhMCVVMx
EzARBgNVBAgTCkNhbGlmb3JuaWExEDAOBgNVBAcTB09ha2xhbmQxEDAOBgNVBAoT
B05lb3NpZ24xFDASBgNVBAsTC1JhbmRvbSBEZXB0MRwwGgYDVQQDExNub3doZXJl
LmV4YW1wbGUuY29tMR4wHAYJKoZIhvcNAQkBFg9uZW9uQHdlYmRhdi5vcmcwHhcN
MDQxMDI5MTMxMzQ4WhcNMDcwNDE3MTMxMzQ4WjCBoDELMAkGA1UEBhMCR0IxFzAV
BgNVBAgTDkNhbWJyaWRnZXNoaXJlMRIwEAYDVQQHEwlDYW1icmlkZ2UxGTAXBgNV
BAoTEE5lb24gSGFja2VycyBMdGQxFTATBgNVBAsTDE5lb24gUUEgRGVwdDESMBAG
A1UEAxMJbG9jYWxob3N0MR4wHAYJKoZIhvcNAQkBFg9uZW9uQHdlYmRhdi5vcmcw
XDANBgkqhkiG9w0BAQEFAANLADBIAkEA80VObGfPglkD7z5KicPSpaBIE9has2Uf
UU/6mybkQZkaYYka9IOyToeTK+y12ikoXnRS4RonbrciisCGSZ0YbQIDAQABow0w
CzAJBgNVHRMEAjAAMA0GCSqGSIb3DQEBBAUAA0EAfkNH56ZAo8AIrHkVi/NvUFsn
pBCNYbgXAJUev5Mw1hmZsdai7yW0yMAGC4QFr6518QFqg7kBNQERj4s1W9w7CQ==
-----END CERTIFICATE-----

View File

@ -1,3 +1,11 @@
Wed Aug 25 19:27:26 2004 Joe Orton <joe@manyfish.co.uk>
* child.c (reset_socket): New function.
Mon Jul 5 18:38:08 2004 Joe Orton <joe@manyfish.co.uk>
* tests.c (main): Print 'xfail' for expected failures.
Tue Oct 7 21:19:56 2003 Joe Orton <joe@manyfish.co.uk>
* child.c (close_socket): New function.

View File

@ -1,6 +1,6 @@
/*
Framework for testing with a server process
Copyright (C) 2001-2002, Joe Orton <joe@manyfish.co.uk>
Copyright (C) 2001-2004, Joe Orton <joe@manyfish.co.uk>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -131,6 +131,17 @@ void minisleep(void)
#endif
}
int reset_socket(ne_socket *sock)
{
#ifdef SO_LINGER
/* Stevens' magic trick to send an RST on close(). */
struct linger l = {1, 0};
return setsockopt(ne_sock_fd(sock), SOL_SOCKET, SO_LINGER, &l, sizeof l);
#else
return 1;
#endif
}
/* close 'sock', performing lingering close to avoid premature RST. */
static int close_socket(ne_socket *sock)
{

View File

@ -1,6 +1,6 @@
/*
Framework for testing with a server process
Copyright (C) 2001, Joe Orton <joe@manyfish.co.uk>
Copyright (C) 2001-2004, Joe Orton <joe@manyfish.co.uk>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -21,12 +21,26 @@
#ifndef CHILD_H
#define CHILD_H 1
#include "config.h"
#ifdef HAVE_STRING_H
#include <string.h> /* for strlen() */
#endif
#include "ne_socket.h"
/* Test which does DNS lookup on "localhost": this must be the first
* named test. */
int lookup_localhost(void);
/* Test which looks up real local hostname. */
int lookup_hostname(void);
/* set to local hostname if lookup_hostname succeeds. */
extern char *local_hostname;
/* Callback for spawn_server. */
typedef int (*server_fn)(nsocket *sock, void *userdata);
typedef int (*server_fn)(ne_socket *sock, void *userdata);
/* Spawns server child process:
* - forks child process.
@ -38,10 +52,66 @@ typedef int (*server_fn)(nsocket *sock, void *userdata);
*/
int spawn_server(int port, server_fn fn, void *userdata);
/* Like spawn_server; if bind_local is non-zero, binds server to
* localhost, otherwise, binds server to real local hostname. (must
* have called lookup_localhost or lookup_hostname as approprate
* beforehand). */
int spawn_server_addr(int bind_local, int port, server_fn fn, void *userdata);
/* Like spawn server except will continue accepting connections and
* processing requests, up to 'n' times. If 'n' is reached, then the
* child process exits with a failure status. */
int spawn_server_repeat(int port, server_fn fn, void *userdata, int n);
/* Blocks until child process exits, and gives return code of 'fn'. */
int await_server(void);
/* Kills child process. */
int reap_server(void);
/* Returns non-zero if server process has already died. */
int dead_server(void);
/* If discard_request comes across a header called 'want_header', it
* will call got_header passing the header field value. */
extern const char *want_header;
typedef void (*got_header_fn)(char *value);
extern got_header_fn got_header;
/* Send string to child; ne_sock_fullwrite with debugging. */
ssize_t server_send(ne_socket *sock, const char *data, size_t len);
/* Utility macro: send given string down socket. */
#define SEND_STRING(sock, str) server_send((sock), (str), strlen((str)))
/* Tries to ensure that the socket will be closed using RST rather
* than FIN. */
int reset_socket(ne_socket *sock);
/* Utility function: discard request. Sets context on error. */
int discard_request(ne_socket *sock);
/* Utility function: discard request body. Sets context on error. */
int discard_body(ne_socket *sock);
struct serve_file_args {
const char *fname;
const char *headers;
int chunks;
};
/* Utility function: callback for spawn_server: pass pointer to
* serve_file_args as userdata, and args->fname is served as a 200
* request. If args->headers is non-NULL, it must be a set of
* CRLF-terminated lines which is added in to the response headers.
* If args->chunks is non-zero, the file is delivered using chunks of
* that size. */
int serve_file(ne_socket *sock, void *ud);
/* set to value of C-L header by discard_request. */
extern int clength;
/* Sleep for a short time. */
void minisleep(void);
#endif /* CHILD_H */

View File

@ -1,6 +1,6 @@
/*
Stupidly simple test framework
Copyright (C) 2001-2002, Joe Orton <joe@manyfish.co.uk>
Copyright (C) 2001-2002, 2004, Joe Orton <joe@manyfish.co.uk>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -41,6 +41,7 @@
#include <errno.h>
#endif
#include "ne_string.h"
#include "ne_utils.h"
#include "ne_socket.h"
@ -195,7 +196,7 @@ int main(int argc, char *argv[])
printf("-> running `%s':\n", test_suite);
for (n = 0; !aborted && tests[n].fn != NULL; n++) {
int result;
int result, is_xfail = 0;
#ifdef NEON_MEMLEAK
size_t allocated = ne_alloc_used;
#endif
@ -233,8 +234,10 @@ int main(int argc, char *argv[])
if (result == OK) {
t_context("test passed but expected failure");
result = FAIL;
} else if (result == FAIL)
} else if (result == FAIL) {
result = OK;
is_xfail = 1;
}
}
/* align the result column if we've had warnings. */
@ -244,7 +247,14 @@ int main(int argc, char *argv[])
switch (result) {
case OK:
COL("32"); printf("pass"); NOCOL;
if (is_xfail) {
COL("32;07");
printf("xfail");
} else {
COL("32");
printf("pass");
}
NOCOL;
if (warned) {
printf(" (with %d warning%s)", warned, (warned > 1)?"s":"");
}
@ -266,7 +276,7 @@ int main(int argc, char *argv[])
aborted = 1;
/* fall-through */
case SKIP:
COL("44"); printf("SKIPPED"); NOCOL;
COL("44;37;01"); printf("SKIPPED"); NOCOL;
if (have_context) {
printf(" (%s)", test_context);
}

View File

@ -47,7 +47,7 @@ static int init(void)
#define EXTRA_DEBUG 0 /* disabled by default */
static void reader(void *ud, const char *block, size_t len)
static int reader(void *ud, const char *block, size_t len)
{
struct string *b = ud;
@ -56,7 +56,7 @@ static void reader(void *ud, const char *block, size_t len)
(int)len, block);
#endif
if (failed == f_mismatch) return;
if (failed == f_mismatch) return -1;
if (failed == f_partial && len == 0) {
if (b->len != 0) {
@ -66,13 +66,14 @@ static void reader(void *ud, const char *block, size_t len)
} else {
failed = f_complete;
}
return;
return 0;
}
if (len > b->len || memcmp(b->data, block, len) != 0) {
NE_DEBUG(NE_DBG_HTTP, "reader: failed, got [[%.*s]] not [[%.*s]]\n",
(int)len, block, (int)b->len, b->data);
failed = f_mismatch;
return -1;
} else {
b->data += len;
b->len -= len;
@ -81,6 +82,8 @@ static void reader(void *ud, const char *block, size_t len)
(int)b->len);
#endif
}
return 0;
}
static int file2buf(int fd, ne_buffer *buf)
@ -100,7 +103,7 @@ static int do_fetch(const char *realfn, const char *gzipfn,
{
ne_session *sess;
ne_request *req;
int fd;
int fd, ret;
ne_buffer *buf = ne_buffer_create();
struct serve_file_args sfargs;
ne_decompress *dc;
@ -130,19 +133,34 @@ static int do_fetch(const char *realfn, const char *gzipfn,
req = ne_request_create(sess, "GET", "/");
dc = ne_decompress_reader(req, ne_accept_2xx, reader, &body);
ONREQ(ne_request_dispatch(req));
#ifdef NE_DEBUGGING
ne_debug_init(ne_debug_stream, ne_debug_mask & ~NE_DBG_HTTPBODY);
#endif
ret = ne_request_dispatch(req);
#ifdef NE_DEBUGGING
ne_debug_init(ne_debug_stream, ne_debug_mask | NE_DBG_HTTPBODY);
#endif
ONN("file not served", ne_get_status(req)->code != 200);
ONN("decompress succeeded", expect_fail && !ret);
ONV(!expect_fail && ret, ("decompress failed: %s", ne_get_error(sess)));
ONN("decompress succeeded", expect_fail && !ne_decompress_destroy(dc));
ONV(!expect_fail && ne_decompress_destroy(dc),
("decompress failed: %s", ne_get_error(sess)));
NE_DEBUG(NE_DBG_HTTP, "session error: %s\n", ne_get_error(sess));
ne_request_destroy(req);
ne_session_destroy(sess);
ne_buffer_destroy(buf);
CALL(await_server());
if (expect_fail) {
/* if the decompress callback fails, the connection may
* be aborted and hence the server will abort. */
reap_server();
} else {
CALL(await_server());
}
if (!expect_fail) {
ONN("inflated response truncated", failed == f_partial);
@ -211,6 +229,11 @@ static int fail_trailing(void)
return do_fetch(newsfn, "trailing.gz", 0, 1);
}
static int fail_trailing_1b(void)
{
return do_fetch(newsfn, "trailing.gz", 1, 1);
}
static int fail_truncate(void)
{
return do_fetch(newsfn, "truncated.gz", 0, 1);
@ -231,6 +254,16 @@ static int fail_corrupt2(void)
return do_fetch(newsfn, "corrupt2.gz", 0, 1);
}
static int fail_empty(void)
{
return do_fetch(newsfn, "empty.gz", 0, 1);
}
static int notcomp_empty(void)
{
return fetch("empty.gz", NULL, 0);
}
static int auth_cb(void *userdata, const char *realm, int tries,
char *un, char *pw)
{
@ -256,8 +289,7 @@ static int retry_compress_helper(ne_accept_response acceptor,
ONREQ(ne_request_dispatch(req));
ONV(ne_decompress_destroy(dc),
("decompress failed: %s", ne_get_error(sess)));
ne_decompress_destroy(dc);
ONN("got bad response body", failed != f_complete);
@ -342,17 +374,20 @@ ne_test tests[] = {
T(simple),
T(withname),
T(fail_trailing),
T(fail_trailing_1b),
T(fail_bad_csum),
T(fail_truncate),
T(fail_corrupt1),
T(fail_corrupt2),
T(fail_empty),
T(notcomp_empty),
T(chunked_1b),
T(chunked_1b_wn),
T(chunked_12b),
T(chunked_20b),
T(chunked_10b),
T(chunked_10b_wn),
T(retry_notcompress),
T(retry_compress),
T_XFAIL(retry_notcompress),
T_XFAIL(retry_compress),
T(NULL)
};

190
neon/test/largefile.c Normal file
View File

@ -0,0 +1,190 @@
/*
Tests for LFS support in neon
Copyright (C) 2004, Joe Orton <joe@manyfish.co.uk>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "config.h"
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include "ne_request.h"
#include "child.h"
#include "utils.h"
#include "tests.h"
#ifndef INT64_C
#define INT64_C(x) x ## LL
#endif
static const char data[] = "Hello, world.\n";
static off64_t point = INT64_C(2) << 32;
#define SPARSE "sparse.bin"
/* make a sparse large file */
static int make_sparse_file(void)
{
int fd = open64(SPARSE, O_CREAT | O_TRUNC | O_WRONLY, 0644);
ONN("could not create large file " SPARSE, fd < 0);
ONN("seek to point", lseek64(fd, point, SEEK_SET) != point);
ONN("could not write to file",
write(fd, data, strlen(data)) != (ssize_t)strlen(data));
ONN("close failed", close(fd));
return OK;
}
/* server function which checks that the request body sent was the
* same as the 'data' array. */
static int serve_check_body(ne_socket *sock, void *userdata)
{
CALL(discard_request(sock));
if (clength != (ssize_t)strlen(data)) {
CALL(discard_body(sock));
SEND_STRING(sock, "HTTP/1.0 400 Bad Request Body Length\r\n"
"\r\n");
} else {
char buf[20];
if (ne_sock_fullread(sock, buf, clength) == 0) {
SEND_STRING(sock, "HTTP/1.0 200 OK Then!\r\n\r\n");
}
}
return 0;
}
/* sends a small segment of the file from a high offset. */
static int send_high_offset(void)
{
int ret, fd = open64(SPARSE, O_RDONLY);
ne_session *sess;
ne_request *req;
ONN("could not open sparse file", fd < 0);
CALL(make_session(&sess, serve_check_body, NULL));
req = ne_request_create(sess, "PUT", "/sparse");
ne_set_request_body_fd64(req, fd, point, strlen(data));
ret = ne_request_dispatch(req);
CALL(await_server());
ONV(ret != NE_OK || ne_get_status(req)->klass != 2,
("request failed: %s", ne_get_error(sess)));
ne_request_destroy(req);
ne_session_destroy(sess);
close(fd);
return OK;
}
#if 1
#define RESPSIZE INT64_C(4295008256)
#define RESPSTR "4295008256"
#else
#define RESPSIZE INT64_C(2147491840) /* 2^31+8192 */
#define RESPSTR "2147491840"
#endif
/* Reads a request, sends a large response, reads a request, then
* sends a little response. */
static int serve_large_response(ne_socket *sock, void *ud)
{
int n = 0;
char empty[8192];
CALL(discard_request(sock));
SEND_STRING(sock,
"HTTP/1.1 200 OK\r\n"
"Content-Length: " RESPSTR "\r\n"
"Server: BigFileServerTM\r\n" "\r\n");
memset(empty, 0, sizeof empty);
for (n = 0; n < RESPSIZE/sizeof(empty); n++) {
if (ne_sock_fullwrite(sock, empty, sizeof empty)) {
NE_DEBUG(NE_DBG_SOCKET, "fullwrite failed\n");
return 1;
}
}
NE_DEBUG(NE_DBG_SOCKET, "Wrote %d lots of %d\n", n, (int)sizeof empty);
CALL(discard_request(sock));
SEND_STRING(sock, "HTTP/1.1 200 OK\r\n"
"Connection: close\r\n\r\n");
return 0;
}
static int read_large_response(void)
{
ne_session *sess;
ne_request *req;
off64_t count = 0;
int ret;
char buf[8192];
CALL(make_session(&sess, serve_large_response, NULL));
req = ne_request_create(sess, "GET", "/foo");
#ifdef NE_DEBUGGING
ne_debug_init(ne_debug_stream, ne_debug_mask & ~(NE_DBG_HTTPBODY|NE_DBG_HTTP));
#endif
ret = ne_begin_request(req);
if (ret == NE_OK) {
while ((ret = ne_read_response_block(req, buf, sizeof buf)) > 0)
count += ret;
if (ret == NE_OK)
ret = ne_end_request(req);
}
#ifdef NE_DEBUGGING
ne_debug_init(ne_debug_stream, ne_debug_mask & (NE_DBG_HTTPBODY|NE_DBG_HTTP));
#endif
ONV(ret, ("request failed: %s", ne_get_error(sess)));
ONV(count != RESPSIZE,
("response body was %" NE_FMT_OFF64_T " not %" NE_FMT_OFF64_T,
count, RESPSIZE));
ne_request_destroy(req);
CALL(any_2xx_request(sess, "/bar"));
CALL(await_server());
ne_session_destroy(sess);
return OK;
}
ne_test tests[] = {
T(make_sparse_file),
T(send_high_offset),
T(read_large_response),
T(NULL),
};

View File

@ -8,7 +8,7 @@ CONF=${srcdir}/openssl.conf
REQ="${OPENSSL} req -config ${CONF}"
CA="${OPENSSL} ca -config ${CONF} -batch"
# MKCERT makes a self-signed cert
MKCERT="${REQ} -x509 -new -days 9000"
MKCERT="${REQ} -x509 -new -days 900"
REQDN=reqDN
STRMASK=default
@ -70,9 +70,12 @@ ${REQ} -new -key ${srcdir}/server.key -out altname3.csr
csr_fields "Fourth AltName Dept" localhost | \
${REQ} -new -key ${srcdir}/server.key -out altname4.csr
csr_fields "Fifth Altname Dept" localhost | \
csr_fields "Good ipAddress altname Dept" nowhere.example.com | \
${REQ} -new -key ${srcdir}/server.key -out altname5.csr
csr_fields "Bad ipAddress altname Dept" nowhere.example.com | \
${REQ} -new -key ${srcdir}/server.key -out altname6.csr
csr_fields "Self-Signed" | \
${MKCERT} -key ${srcdir}/server.key -out ssigned.pem
@ -117,7 +120,7 @@ fqdn=`hostname -f 2>/dev/null` || true
if [ "x${hostname}.${domain}" = "x${fqdn}" ]; then
csr_fields "Wildcard Cert Dept" "*.${domain}" | \
${REQ} -new -key ${srcdir}/server.key -out wildcard.csr
${CA} -days 9000 -in wildcard.csr -out wildcard.cert
${CA} -days 900 -in wildcard.csr -out wildcard.cert
fi
csr_fields "Neon Client Cert" ignored.example.com | \
@ -138,13 +141,18 @@ echo GB | ${REQ} -new -key ${srcdir}/server.key -out missingcn.csr
REQDN=reqDN.justEmail
echo blah@example.com | ${REQ} -new -key ${srcdir}/server.key -out justmail.csr
# presume AVAs will come out in least->most specific order still...
REQDN=reqDN.twoOU
csr_fields "Second OU Dept
First OU Dept" | ${REQ} -new -key ${srcdir}/server.key -out twoou.csr
### don't put ${REQ} invocations after here
for f in server client twocn caseless cnfirst missingcn justmail; do
for f in server client twocn caseless cnfirst missingcn justmail twoou; do
${CA} -days 900 -in ${f}.csr -out ${f}.cert
done
for n in 1 2 3 4 5; do
for n in 1 2 3 4 5 6; do
${CA} -extensions altExt${n} -days 900 \
-in altname${n}.csr -out altname${n}.cert
done

View File

@ -52,6 +52,10 @@ subjectAltName = email:neon@webdav.org
[altExt5]
subjectAltName = IP:127.0.0.1
# an AltName with a bad IP address
[altExt6]
subjectAltName = IP:1.2.3.4
[reqDN]
countryName = Country Name
stateOrProvinceName = State or Province Name
@ -72,6 +76,16 @@ organizationalUnitName = Organizational Unit Name
1.commonName = Common Name
emailAddress = Email Address
[reqDN.twoOU]
countryName = Country Name
stateOrProvinceName = State or Province Name
localityName = Locality Name
organizationName = Organization Name
0.organizationalUnitName = Organizational Unit Name
1.organizationalUnitName = Organizational Unit Name
commonName = Common Name (eg, your name or your server\'s hostname)
emailAddress = Email Address
[reqDN.CNfirst]
commonName = Common Name

View File

@ -263,8 +263,8 @@ static int run_207_response(char *resp, const char *expected)
CALL(await_server());
ONV(!ne_xml_valid(p),
("response body was invalid: %s", ne_xml_get_error(p)));
ONV(ne_xml_failed(p),
("parse error in response body: %s", ne_xml_get_error(p)));
ONV(strcmp(buf->data, expected),
("comparison failed.\n"
@ -521,7 +521,14 @@ static int pfind_simple(void)
STAT_207("256 Second is OK")))),
"results(/alpha,prop:[{DAV:,fishbone}='strike one':{234 First is OK}];)//"
"results(/beta,prop:[{DAV:,fishbone}='strike two':{256 Second is OK}];)//",
0, 0}
0, 0},
/* whitespace handling. */
{ MULTI_207(RESP_207("\r\nhttp://localhost:7777/alpha ",
PSTAT_207(PROPS_207(APROP_207("alpha", "beta"))
"<D:status>\r\nHTTP/1.1 200 OK </D:status>"))),
"results(http://localhost:7777/alpha,prop:[{DAV:,alpha}='beta':{200 OK}];)//",
0, 0}
};
const ne_propname pset1[] = {
{ "DAV:", "fishbone", },
@ -540,12 +547,51 @@ static int pfind_simple(void)
return OK;
}
static int unbounded_response(const char *header, const char *repeats)
{
ne_session *sess;
struct infinite i = { header, repeats};
int dbg;
CALL(make_session(&sess, serve_infinite, &i));
dbg = ne_debug_mask;
ONN("unbounded PROPFIND response did not fail",
ne_simple_propfind(sess, "/", 0, NULL,
dummy_results, NULL) != NE_ERROR);
CALL(reap_server());
ne_session_destroy(sess);
return OK;
}
static int unbounded_propstats(void)
{
return unbounded_response(
RESP207 "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<multistatus xmlns=\"DAV:\">"
"<response><href>/</href>",
"<propstat></propstat>");
}
static int unbounded_props(void)
{
return unbounded_response(
RESP207 "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<multistatus xmlns=\"DAV:\">"
"<response><href>/</href><propstat>",
"<prop><jim>hello, world</jim></prop>");
}
ne_test tests[] = {
T(two_oh_seven),
T(patch_simple),
T(pfind_simple),
T(regress),
T(patch_regress),
T(unbounded_props),
T(unbounded_propstats),
T(NULL)
};

View File

@ -1,6 +1,6 @@
/*
HTTP request handling tests
Copyright (C) 2001-2003, Joe Orton <joe@manyfish.co.uk>
Copyright (C) 2001-2004, Joe Orton <joe@manyfish.co.uk>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -69,10 +69,11 @@ static int finish_request(void)
#define TE_CHUNKED "Transfer-Encoding: chunked\r\n"
/* takes response body chunks and appends them to a buffer. */
static void collector(void *ud, const char *data, size_t len)
static int collector(void *ud, const char *data, size_t len)
{
ne_buffer *buf = ud;
ne_buffer_append(buf, data, len);
return 0;
}
typedef ne_request *(*construct_request)(ne_session *sess, void *userdata);
@ -251,12 +252,6 @@ static int no_body_204(void)
"Content-Length: 5\r\n\r\n");
}
static int no_body_205(void)
{
return expect_no_body("GET", "HTTP/1.1 205 Reset Content\r\n"
"Content-Length: 5\r\n\r\n");
}
static int no_body_HEAD(void)
{
return expect_no_body("HEAD", "HTTP/1.1 200 OK\r\n"
@ -830,17 +825,12 @@ static int skip_1xx_hdrs(void)
#undef sess
/* server for expect_100_once: eats a dummy request, then serves a
* 100-continue request, and fails if the request body is sent
* twice. */
/* server for expect_100_once: serves a 100-continue request, and
* fails if the request body is sent twice. */
static int serve_100_once(ne_socket *sock, void *ud)
{
struct s1xx_args args = {2, 0};
char ch;
/* dummy first request. */
CALL(discard_request(sock));
CALL(SEND_STRING(sock, RESP200 "Content-Length: 0\r\n\r\n"));
/* now the real 1xx request. */
CALL(serve_1xx(sock, &args));
CALL(discard_body(sock));
ONN("body was served twice", ne_sock_read(sock, &ch, 1) == 1);
@ -857,24 +847,35 @@ static int expect_100_once(void)
char body[BUFSIZ];
CALL(make_session(&sess, serve_100_once, NULL));
ne_set_expect100(sess, 1);
/* 100-continue is only used if the server is known to claim
* HTTP/1.1 compliance; make a dummy request on the socket first,
* to trigger that logic. */
CALL(any_request(sess, "/foo"));
/* now the real request. */
req = ne_request_create(sess, "GET", "/foo");
ne_set_request_expect100(req, 1);
memset(body, 'A', sizeof(body));
ne_set_request_body_buffer(req, body, sizeof(body));
ONN("request failed", ne_request_dispatch(req));
ONREQ(ne_request_dispatch(req));
ne_request_destroy(req);
ne_session_destroy(sess);
CALL(await_server());
return OK;
}
/* regression test for enabling 100-continue without sending a body. */
static int expect_100_nobody(void)
{
ne_session *sess;
ne_request *req;
CALL(make_session(&sess, serve_100_once, NULL));
req = ne_request_create(sess, "GET", "/foo");
ne_set_request_expect100(req, 1);
ONREQ(ne_request_dispatch(req));
ne_request_destroy(req);
ne_session_destroy(sess);
return await_server();
}
struct body {
char *body;
size_t size;
@ -971,19 +972,6 @@ static int send_bodies(void)
return OK;
}
static int serve_infinite_headers(ne_socket *sock, void *userdata)
{
CALL(discard_request(sock));
SEND_STRING(sock, RESP200);
for (;;) {
SEND_STRING(sock, "x-foo: bar\r\n");
}
return 0;
}
/* Utility function: run a request using the given server fn, and the
* request should fail. If 'error' is non-NULL, it must be a substring
* of the error string. */
@ -1052,7 +1040,8 @@ static int fail_request(int with_body, server_fn fn, void *ud, int forever)
static int unbounded_headers(void)
{
return fail_request(0, serve_infinite_headers, NULL, 0);
struct infinite i = { RESP200, "x-foo: bar\r\n" };
return fail_request(0, serve_infinite, &i, 0);
}
static int blank_response(void)
@ -1074,18 +1063,11 @@ static int not_http(void)
return fail_request(0, serve_non_http, NULL, 0);
}
static int serve_infinite_folds(ne_socket *sock, void *ud)
{
SEND_STRING(sock, "HTTP/1.0 200 OK\r\nFoo: bar\r\n");
for (;;) {
SEND_STRING(sock, " hello there.\r\n");
}
return OK;
}
static int unbounded_folding(void)
{
return fail_request(0, serve_infinite_folds, NULL, 0);
struct infinite i = { "HTTP/1.0 200 OK\r\nFoo: bar\r\n",
" hello there.\r\n" };
return fail_request(0, serve_infinite, &i, 0);
}
static int serve_close(ne_socket *sock, void *ud)
@ -1166,11 +1148,13 @@ static enum {
static off_t prog_last = -1, prog_total;
#define FOFF "%" NE_FMT_OFF_T
/* callback for send_progress. */
static void s_progress(void *userdata, off_t prog, off_t total)
{
NE_DEBUG(NE_DBG_HTTP,
"progress callback: %" NE_FMT_OFF_T "/%" NE_FMT_OFF_T ".\n",
"progress callback: " FOFF "/" FOFF ".\n",
prog, total);
switch (prog_state) {
@ -1179,19 +1163,19 @@ static void s_progress(void *userdata, off_t prog, off_t total)
return;
case prog_transfer:
if (total != prog_total) {
t_context("total unexpected: %ld not %ld", total, prog_total);
t_context("total unexpected: " FOFF " not " FOFF "", total, prog_total);
prog_state = prog_error;
}
else if (prog > total) {
t_context("first progress was invalid (%ld/%ld)", prog, total);
t_context("first progress was invalid (" FOFF "/" FOFF ")", prog, total);
prog_state = prog_error;
}
else if (prog_last != -1 && prog_last > prog) {
t_context("progess went backwards: %ld to %ld", prog_last, prog);
t_context("progess went backwards: " FOFF " to " FOFF, prog_last, prog);
prog_state = prog_error;
}
else if (prog_last == prog) {
t_context("no progress made! %ld to %ld", prog_last, prog);
t_context("no progress made! " FOFF " to " FOFF, prog_last, prog);
prog_state = prog_error;
}
else if (prog == total) {
@ -1203,6 +1187,8 @@ static void s_progress(void *userdata, off_t prog, off_t total)
prog_last = prog;
}
#undef FOFF
static ssize_t provide_progress(void *userdata, char *buf, size_t bufsiz)
{
int *count = userdata;
@ -1580,13 +1566,105 @@ static int dup_method(void)
return OK;
}
#ifdef NE_HAVE_IDNA
/* "ħêłłø.com" in UTF-8 and ACE form. */
#define HELLO_DOT_COM "\xc4\xa7" "\xc3\xaa" "\xc5\x82" "\xc5\x82" "\xc3\xb8" ".com"
#define HELLO_IDNA_ACE "xn--bda2a5j8da.com"
static char *host_hdr = NULL;
static void dup_header(char *hdr)
{
host_hdr = strdup(hdr);
}
static int serve_check_host(ne_socket *sock, void *userdata)
{
const char *host = userdata;
want_header = "Host";
got_header = dup_header;
CALL(discard_request(sock));
if (host_hdr == NULL) {
CALL(SEND_STRING(sock, "HTTP/1.0 500 No Host header!?\r\n\r\n"));
} else if (strcmp(host_hdr, host) != 0) {
CALL(SEND_STRING(sock, "HTTP/1.0 500 Bad Host Header\r\n\r\n"));
} else {
CALL(SEND_STRING(sock, "HTTP/1.0 200 Good Host Header\r\n\r\n"));
}
return OK;
}
static int idna_hostname(void)
{
ne_session *sess = ne_session_create("http", HELLO_DOT_COM, 80);
ne_session_proxy(sess, "localhost", 7777);
CALL(spawn_server(7777, serve_check_host, HELLO_IDNA_ACE));
CALL(any_2xx_request(sess, "/idnafoo"));
CALL(await_server());
ne_session_destroy(sess);
return OK;
}
#else
static int idna_hostname(void)
{
t_context("IDNA support not enabled");
return SKIP;
}
#endif
static int abortive_reader(void *userdata, const char *buf, size_t len)
{
ne_session *sess = userdata;
if (len == 5 && strncmp(buf, "abcde", 5) == 0) {
ne_set_error(sess, "Reader callback failed");
} else {
ne_set_error(sess, "Reader callback called with length %" NE_FMT_SIZE_T,
len);
}
return NE_ERROR;
}
static int abort_reader(void)
{
ne_session *sess;
ne_request *req;
int ret;
CALL(make_session(&sess, single_serve_string,
RESP200 "Content-Length: 5\r\n\r\n"
"abcde"
"HTTP/1.1 200 OK\r\n"
"Content-Length: 0\r\n\r\n"));
req = ne_request_create(sess, "GET", "/foo");
ne_add_response_body_reader(req, ne_accept_2xx, abortive_reader, sess);
ret = ne_request_dispatch(req);
ONV(ret != NE_ERROR, ("request did not fail with NE_ERROR: %d", ret));
ONV(strcmp(ne_get_error(sess), "Reader callback failed") != 0,
("unexpected session error string: %s", ne_get_error(sess)));
ne_request_destroy(req);
/* test that the connection was closed. */
ONN("connection not closed after aborted response",
any_2xx_request(sess, "/failmeplease") == OK);
ne_session_destroy(sess);
CALL(await_server());
return OK;
}
ne_test tests[] = {
T(lookup_localhost),
T(single_get_clength),
T(single_get_eof),
T(single_get_chunked),
T(no_body_204),
T(no_body_205),
T(no_body_304),
T(no_body_HEAD),
T(no_body_empty_clength),
@ -1630,6 +1708,7 @@ ne_test tests[] = {
T(skip_1xx_hdrs),
T(send_bodies),
T(expect_100_once),
T(expect_100_nobody),
T(unbounded_headers),
T(unbounded_folding),
T(blank_response),
@ -1652,5 +1731,7 @@ ne_test tests[] = {
T(dup_method),
T(versions),
T(hook_create_req),
T(idna_hostname),
T(abort_reader),
T(NULL)
};

View File

@ -1,12 +1,13 @@
#!/bin/sh
rm -f debug.log
rm -f child.log
rm -f debug.log child.log
ulimit -c unlimited
ulimit -v 10240
# enable an safety-checking malloc in glibc which will abort() if
# heap corruption is detected.
MALLOC_CHECK_=2
export MALLOC_CHECK_
for f in $*; do

View File

@ -43,14 +43,8 @@
#include "utils.h"
#ifdef SOCKET_SSL
#include <openssl/err.h>
#include <openssl/ssl.h>
#include "ne_ssl.h"
SSL_CTX *server_ctx;
ne_ssl_context *client_ctx;
ne_ssl_context *server_ctx, *client_ctx;
#endif
static ne_sock_addr *localhost;
@ -82,25 +76,26 @@ static int multi_init(void)
return OK;
}
static ne_socket *do_connect(ne_sock_addr *addr, unsigned int port)
/* Create and connect *sock to address addr on given port. */
static int do_connect(ne_socket **sock, ne_sock_addr *addr, unsigned int port)
{
ne_socket *sock = ne_sock_create();
const ne_inet_addr *ia;
if (!sock) return NULL;
*sock = ne_sock_create();
ONN("could not create socket", *sock == NULL);
for (ia = ne_addr_first(addr); ia; ia = ne_addr_next(addr)) {
if (ne_sock_connect(sock, ia, port) == 0)
return sock;
if (ne_sock_connect(*sock, ia, port) == 0)
return OK;
}
ne_sock_close(sock);
return NULL;
t_context("could not connect to server: %s", ne_sock_error(*sock));
ne_sock_close(*sock);
return FAIL;
}
#ifdef SOCKET_SSL
/* FIXME: largely cut'n'pasted from ssl.c. */
static int init_ssl(void)
{
char *server_key;
@ -110,26 +105,23 @@ static int init_ssl(void)
if (test_argc > 1) {
server_key = ne_concat(test_argv[1], "/server.key", NULL);
} else {
server_key = "server.key";
server_key = ne_strdup("server.key");
}
ONN("sock_init failed.\n", ne_sock_init());
server_ctx = SSL_CTX_new(SSLv23_server_method());
ONN("sock_init failed", ne_sock_init());
server_ctx = ne_ssl_context_create(1);
ONN("SSL_CTX_new failed", server_ctx == NULL);
ONN("failed to load private key",
!SSL_CTX_use_PrivateKey_file(server_ctx, server_key,
SSL_FILETYPE_PEM));
ONN("failed to load certificate",
!SSL_CTX_use_certificate_file(server_ctx, "server.cert",
SSL_FILETYPE_PEM));
client_ctx = ne_ssl_context_create();
ne_ssl_context_keypair(server_ctx, "server.cert", server_key);
client_ctx = ne_ssl_context_create(0);
ONN("SSL_CTX_new failed for client", client_ctx == NULL);
cert = ne_ssl_cert_read("ca/cert.pem");
ONN("could not load ca/cert.pem", cert == NULL);
ne_ssl_ctx_trustcert(client_ctx, cert);
ne_ssl_context_trustcert(client_ctx, cert);
ne_free(server_key);
return OK;
}
@ -160,24 +152,13 @@ struct serve_pair {
static int wrap_serve(ne_socket *sock, void *ud)
{
struct serve_pair *pair = ud;
int fd = ne_sock_fd(sock), ret;
SSL *ssl = SSL_new(server_ctx);
BIO *bio = BIO_new_socket(fd, BIO_NOCLOSE);
ONN("SSL_new failed", ssl == NULL);
SSL_set_bio(ssl, bio, bio);
#define ERROR_SSL_STRING (ERR_reason_error_string(ERR_get_error()))
NE_DEBUG(NE_DBG_SOCKET, "Doing SSL accept:\n");
ret = SSL_accept(ssl);
if (ret != 1) {
NE_DEBUG(NE_DBG_SOCKET, "SSL_accept failed: %s\n", ERROR_SSL_STRING);
if (ne_sock_accept_ssl(sock, server_ctx)) {
NE_DEBUG(NE_DBG_SOCKET, "SSL_accept failed: %s\n", ne_sock_error(sock));
return 1;
}
NE_DEBUG(NE_DBG_SOCKET, "SSL accept okay.\n");
ne_sock_switch_ssl(sock, ssl);
return pair->fn(sock, pair->userdata);
}
@ -187,8 +168,7 @@ static int begin(ne_socket **sock, server_fn fn, void *ud)
pair.fn = fn;
pair.userdata = ud;
CALL(spawn_server(7777, wrap_serve, &pair));
*sock = do_connect(localhost, 7777);
ONN("could not connect to localhost:7777", *sock == NULL);
CALL(do_connect(sock, localhost, 7777));
ONV(ne_sock_connect_ssl(*sock, client_ctx),
("SSL negotation failed: %s", ne_sock_error(*sock)));
return OK;
@ -199,9 +179,7 @@ static int begin(ne_socket **sock, server_fn fn, void *ud)
static int begin(ne_socket **sock, server_fn fn, void *ud)
{
CALL(spawn_server(7777, fn, ud));
*sock = do_connect(localhost, 7777);
ONN("could not connect to localhost:7777", *sock == NULL);
return OK;
return do_connect(sock, localhost, 7777);
}
#endif
@ -568,7 +546,8 @@ static int line_closure(void)
ret = ne_sock_readline(sock, buffer, BUFSIZ);
ONV(ret != NE_SOCK_CLOSED,
("readline got %" NE_FMT_SSIZE_T " not EOF", ret));
("readline got %" NE_FMT_SSIZE_T " not EOF: %s", ret,
ne_sock_error(sock)));
return finish(sock, 0);
}
@ -792,7 +771,8 @@ static int ssl_closure(void)
ret = ne_sock_fullwrite(sock, "a", 1);
} while (ret == 0);
ONV(ret != NE_SOCK_RESET && ret != NE_SOCK_CLOSED,
("write got %" NE_FMT_SSIZE_T " not reset or closure", ret));
("write got %" NE_FMT_SSIZE_T " not reset or closure: %s", ret,
ne_sock_error(sock)));
return good_close(sock);
}
@ -816,13 +796,20 @@ static int ssl_truncate(void)
}
#else
/* thanks to W Richard Stevens for the precise repro case for getting
* an RST on demand. */
/* use W Richard Stevens' SO_LINGER trick to elicit a TCP RST */
static int serve_reset(ne_socket *sock, void *ud)
{
reset_socket(sock);
exit(0);
return 0;
}
static int write_reset(void)
{
ne_socket *sock;
int ret;
CALL(begin(&sock, serve_close, NULL));
CALL(begin(&sock, serve_reset, NULL));
CALL(full_write(sock, "a", 1));
CALL(await_server());
ret = ne_sock_fullwrite(sock, "a", 1);
@ -830,7 +817,8 @@ static int write_reset(void)
ne_sock_close(sock);
return SKIP;
}
ONV(ret != NE_SOCK_RESET, ("write got %d not reset", ret));
ONV(ret != NE_SOCK_RESET,
("write got %d not reset: %s", ret, ne_sock_error(sock)));
return good_close(sock);
}
@ -838,7 +826,7 @@ static int read_reset(void)
{
ne_socket *sock;
ssize_t ret;
CALL(begin(&sock, serve_close, NULL));
CALL(begin(&sock, serve_reset, NULL));
CALL(full_write(sock, "a", 1));
CALL(await_server());
ret = ne_sock_read(sock, buffer, 1);
@ -846,7 +834,9 @@ static int read_reset(void)
ne_sock_close(sock);
return SKIP;
}
ONV(ret != NE_SOCK_RESET, ("read got %" NE_FMT_SSIZE_T " not reset", ret));
ONV(ret != NE_SOCK_RESET,
("read got %" NE_FMT_SSIZE_T " not reset: %s", ret,
ne_sock_error(sock)));
return good_close(sock);
}
#endif

View File

@ -39,7 +39,7 @@
#include "child.h"
#include "utils.h"
#ifndef NEON_SSL
#ifndef NE_HAVE_SSL
/* this file shouldn't be built if SSL is not enabled. */
#error SSL not supported
#endif
@ -725,10 +725,10 @@ static int get_failures(void *userdata, int fs, const ne_ssl_certificate *c)
/* Helper function: run a request using the given self-signed server
* certificate, and expect the request to fail with the given
* verification failure flags. */
static int fail_ssl_request(char *cert, char *cacert,
static int fail_ssl_request(char *cert, char *cacert, const char *host,
const char *msg, int failures)
{
ne_session *sess = DEFSESS;
ne_session *sess = ne_session_create("https", host, 7777);
int gotf = 0, ret;
ret = any_ssl_request(sess, fail_serve, cert, cacert,
@ -753,14 +753,14 @@ static int fail_ssl_request(char *cert, char *cacert,
return OK;
}
/* Note that the certs used for fail_* are all self-signed, so the
/* Note that the certs used for fail_* are mostly self-signed, so the
* cert is passed as CA cert and server cert to fail_ssl_request. */
/* Check that a certificate with the incorrect commonName attribute is
* flagged as such. */
static int fail_wrongCN(void)
{
return fail_ssl_request("wrongcn.pem", "wrongcn.pem",
return fail_ssl_request("wrongcn.pem", "wrongcn.pem", "localhost",
"certificate with incorrect CN was accepted",
NE_SSL_IDMISMATCH);
}
@ -769,8 +769,8 @@ static int fail_wrongCN(void)
static int fail_expired(void)
{
char *c = ne_concat(srcdir, "/expired.pem", NULL);
CALL(fail_ssl_request(c, c, "expired certificate was accepted",
NE_SSL_EXPIRED));
CALL(fail_ssl_request(c, c, "localhost",
"expired certificate was accepted", NE_SSL_EXPIRED));
ne_free(c);
return OK;
}
@ -778,7 +778,8 @@ static int fail_expired(void)
static int fail_notvalid(void)
{
char *c = ne_concat(srcdir, "/notvalid.pem", NULL);
CALL(fail_ssl_request(c, c, "not yet valid certificate was accepted",
CALL(fail_ssl_request(c, c, "localhost",
"not yet valid certificate was accepted",
NE_SSL_NOTYETVALID));
ne_free(c);
return OK;
@ -788,14 +789,14 @@ static int fail_notvalid(void)
* fail with UNTRUSTED. */
static int fail_untrusted_ca(void)
{
return fail_ssl_request("server.cert", NULL, "untrusted CA.",
NE_SSL_UNTRUSTED);
return fail_ssl_request("server.cert", NULL, "localhost",
"untrusted CA.", NE_SSL_UNTRUSTED);
}
static int fail_self_signed(void)
{
return fail_ssl_request("ssigned.pem", NULL, "self-signed cert",
NE_SSL_UNTRUSTED);
return fail_ssl_request("ssigned.pem", NULL, "localhost",
"self-signed cert", NE_SSL_UNTRUSTED);
}
/* Test for failure when a server cert is presented which has no
@ -815,6 +816,21 @@ static int fail_missing_CN(void)
return OK;
}
/* test for a bad ipAddress altname */
static int fail_bad_ipaltname(void)
{
return fail_ssl_request("altname6.cert", CA_CERT, "127.0.0.1",
"bad IP altname cert", NE_SSL_IDMISMATCH);
}
/* test for a ipAddress which matched against the hostname as per neon
* 0.24 behaviour. */
static int fail_host_ipaltname(void)
{
return fail_ssl_request("altname5.cert", CA_CERT, "localhost",
"bad IP altname cert", NE_SSL_IDMISMATCH);
}
/* Test that the SSL session is cached across connections. */
static int session_cache(void)
{
@ -957,6 +973,7 @@ static int ccert_unencrypted(void)
args.require_cc = 1;
ccert = ne_ssl_clicert_read("unclient.p12");
ONN("could not load unclient.p12", ccert == NULL);
ONN("unclient.p12 was encrypted", ne_ssl_clicert_encrypted(ccert));
ne_ssl_set_clicert(sess, ccert);
@ -1171,6 +1188,7 @@ static int cert_identities(void)
static const struct {
const char *fname, *identity;
} certs[] = {
{ "ssigned.pem", "localhost" },
{ "twocn.cert", "localhost" },
{ "altname1.cert", "localhost" },
{ "altname2.cert", "nohost.example.com" },
@ -1270,7 +1288,9 @@ static int dname_readable(void)
{ "justmail.cert", "blah@example.com", NULL },
{ "t61subj.cert", I18N_DNAME, NULL },
{ "bmpsubj.cert", I18N_DNAME, NULL },
{ "utf8subj.cert", I18N_DNAME, NULL }
{ "utf8subj.cert", I18N_DNAME, NULL },
{ "twoou.cert", "First OU Dept, Second OU Dept, Neon Hackers Ltd, "
"Cambridge, Cambridgeshire, GB" }
};
size_t n;
@ -1538,6 +1558,8 @@ ne_test tests[] = {
T(fail_untrusted_ca),
T(fail_self_signed),
T(fail_missing_CN),
T(fail_host_ipaltname),
T(fail_bad_ipaltname),
T(session_cache),

View File

@ -1,6 +1,6 @@
/*
String handling tests
Copyright (C) 2001-2003, Joe Orton <joe@manyfish.co.uk>
Copyright (C) 2001-2004, Joe Orton <joe@manyfish.co.uk>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -410,7 +410,7 @@ static int base64(void)
unsigned char bits[256];
size_t n;
#define B64B(x, l, y) CALL(b64_check(x, l, y))
#define B64B(x, l, y) CALL(b64_check((unsigned char *)x, l, y))
#define B64(x, y) B64B(x, strlen(x), y)
/* invent these with
@ -464,6 +464,39 @@ static int unbase64(void)
return OK;
}
static int printing(void)
{
struct {
const char *in, *out;
size_t pass, ret;
} ts[] = {
{ "alpha", "alpha", 10, 5 },
{ "alpha", "alph", 5, 4 },
{ "foobar", "", 1, 0 },
{ NULL, NULL, 0, 0}
};
size_t n;
for (n = 0; ts[n].in; n++) {
char buf[512];
size_t ret;
memset(buf, 'A', sizeof buf);
ret = ne_snprintf(buf, ts[n].pass, "%s", ts[n].in);
ONCMP(buf, ts[n].out);
ONV(ret != ts[n].ret,
("got return value %" NE_FMT_SIZE_T " not %" NE_FMT_SIZE_T,
ret, ts[n].ret));
/* byte past the NUL must still be 'A' */
ONN("buffer over-ran!", buf[ret + 1] != 'A');
}
return OK;
}
ne_test tests[] = {
T(simple),
T(buf_concat),
@ -487,6 +520,7 @@ ne_test tests[] = {
T(cleaner),
T(base64),
T(unbase64),
T(printing),
T(NULL)
};

View File

@ -42,11 +42,11 @@
#include "child.h"
#include "utils.h"
#if defined(NEON_ZLIB) && defined(NEON_SSL)
#if defined(NE_HAVE_ZLIB) && defined(NE_HAVE_SSL)
#define NO_TESTS 1
#endif
#ifndef NEON_ZLIB
#ifndef NE_HAVE_ZLIB
static int sd_result = OK;
static void sd_reader(void *ud, const char *block, size_t len)
@ -90,7 +90,7 @@ static int stub_decompress(void)
}
#endif
#ifndef NEON_SSL
#ifndef NE_HAVE_SSL
static int stub_ssl(void)
{
ne_session *sess = ne_session_create("https", "localhost", 7777);
@ -156,10 +156,10 @@ static int null_test(void) { return OK; }
#endif
ne_test tests[] = {
#ifndef NEON_ZLIB
#ifndef NE_HAVE_ZLIB
T(stub_decompress),
#endif
#ifndef NEON_SSL
#ifndef NE_HAVE_SSL
T(stub_ssl),
#endif
/* to prevent failure when SSL and zlib are supported. */

View File

@ -254,10 +254,30 @@ static int version_string(void)
static int support(void)
{
#ifdef NEON_SSL
ONN("SSL support not advertised", !ne_supports_ssl());
#ifdef NE_HAVE_SSL
ONN("SSL support not advertised", !ne_has_support(NE_FEATURE_SSL));
#else
ONN("SSL support advertised", ne_supports_ssl());
ONN("SSL support advertised", ne_has_support(NE_FEATURE_SSL));
#endif
#ifdef NE_HAVE_ZLIB
ONN("zlib support not advertised", !ne_has_support(NE_FEATURE_ZLIB));
#else
ONN("zlib support advertised", ne_has_support(NE_FEATURE_ZLIB));
#endif
#ifdef NE_HAVE_IPV6
ONN("IPv6 support not advertised", !ne_has_support(NE_FEATURE_IPV6));
#else
ONN("IPv6 support advertised", ne_has_support(NE_FEATURE_IPV6));
#endif
#ifdef NE_HAVE_IDNA
ONN("IDNA support not advertised", !ne_has_support(NE_FEATURE_IDNA));
#else
ONN("IDNA support advertised", ne_has_support(NE_FEATURE_IDNA));
#endif
#ifdef NE_HAVE_LFS
ONN("LFS support not advertised", !ne_has_support(NE_FEATURE_LFS));
#else
ONN("LFS support advertised", ne_has_support(NE_FEATURE_LFS));
#endif
return OK;
}

View File

@ -85,7 +85,7 @@ int any_2xx_request(ne_session *sess, const char *uri)
ne_request *req = ne_request_create(sess, "GET", uri);
int ret = ne_request_dispatch(req);
ONV(ret != NE_OK || ne_get_status(req)->klass != 2,
("request failed: %s\n", ne_get_error(sess)));
("request failed: %s", ne_get_error(sess)));
ne_request_destroy(req);
return ret;
}
@ -100,7 +100,7 @@ int any_2xx_request_body(ne_session *sess, const char *uri)
ret = ne_request_dispatch(req);
ne_free(body);
ONV(ret != NE_OK || ne_get_status(req)->klass != 2,
("request failed: %s\n", ne_get_error(sess)));
("request failed: %s", ne_get_error(sess)));
ne_request_destroy(req);
return ret;
}
@ -132,3 +132,17 @@ int serve_sstring_slowly(ne_socket *sock, void *ud)
return 0;
}
int serve_infinite(ne_socket *sock, void *ud)
{
struct infinite *i = ud;
CALL(discard_request(sock));
SEND_STRING(sock, i->header);
while (server_send(sock, i->repeat, strlen(i->repeat)) == 0)
/* nullop */;
return OK;
}

View File

@ -65,4 +65,12 @@ int serve_sstring(ne_socket *sock, void *ud);
/* Serve a struct string slowly. */
int serve_sstring_slowly(ne_socket *sock, void *ud);
struct infinite {
const char *header, *repeat;
};
/* Pass a "struct infinite *" as userdata, this function sends
* ->header and then loops sending ->repeat forever. */
int serve_infinite(ne_socket *sock, void *ud);
#endif /* UTILS_H */

View File

@ -1,6 +1,6 @@
/*
neon test suite
Copyright (C) 2002-2003, Joe Orton <joe@manyfish.co.uk>
Copyright (C) 2002-2004, Joe Orton <joe@manyfish.co.uk>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -35,6 +35,8 @@
#include "child.h"
#include "utils.h"
#define ABORT (-42) /* magic code for abort handlers */
/* A set of SAX handlers which serialize SAX events back into a
* pseudo-XML-like string. */
static int startelm(void *userdata, int state,
@ -60,7 +62,7 @@ static int chardata(void *userdata, int state, const char *cdata, size_t len)
{
ne_buffer *buf = userdata;
ne_buffer_append(buf, cdata, len);
return !strncmp(cdata, "!ABORT!", len);
return strncmp(cdata, "!ABORT!", len) == 0 ? ABORT : NE_XML_DECLINE;
}
static int endelm(void *userdata, int state,
@ -139,7 +141,7 @@ static int startelm_abort(void *buf, int parent,
{
if (strcmp(name, "abort-start") == 0) {
ne_buffer_zappend(buf, "ABORT");
return NE_XML_ABORT;
return ABORT;
} else
return startelm(buf, parent, nspace, name, atts);
}
@ -149,22 +151,25 @@ static int endelm_abort(void *buf, int state,
{
if (strcmp(name, "abort-end") == 0) {
ne_buffer_zappend(buf, "ABORT");
return -1;
return ABORT;
} else
return 0;
}
/* Test mode for parse_match: */
enum match_type {
match_valid = 0,
match_invalid,
match_nohands,
match_encoding
match_valid = 0, /* test that the parse succeeds */
match_invalid, /* test that the parse fails */
match_nohands, /* test with no handlers registered */
match_encoding, /* test whether the encoding is equal to the result string */
match_chunked /* parse the document one byte at a time */
};
static int parse_match(const char *doc, const char *result, enum match_type t)
{
ne_xml_parser *p = ne_xml_create();
ne_buffer *buf = ne_buffer_create();
int ret;
if (t == match_invalid)
ne_xml_push_handler(p, startelm_abort, chardata, endelm_abort, buf);
@ -174,13 +179,26 @@ static int parse_match(const char *doc, const char *result, enum match_type t)
ne_xml_push_handler(p, startelm_xform, chardata, endelm_xform, buf);
}
ne_xml_parse(p, doc, strlen(doc));
ne_xml_parse(p, "", 0);
if (t == match_chunked) {
do {
ret = ne_xml_parse(p, doc++, 1);
} while (ret == 0 && *doc);
} else {
ret = ne_xml_parse(p, doc, strlen(doc));
}
if (ret == 0) {
ne_xml_parse(p, "", 0);
}
ONV(ret != ne_xml_failed(p),
("ne_xml_failed gave %d not %d", ne_xml_failed(p), ret));
if (t == match_invalid)
ONV(ne_xml_valid(p), ("parse did not fail: %s", buf->data));
ONV(ret != ABORT,
("parse got %d not abort failure: %s", ret, buf->data));
else
ONV(!ne_xml_valid(p), ("parse failed: %s", ne_xml_get_error(p)));
ONV(ret, ("parse failed: %s", ne_xml_get_error(p)));
if (t == match_encoding) {
const char *enc = ne_xml_doc_encoding(p);
@ -215,6 +233,11 @@ static int matches(void)
{ PFX "<hello>\r\n<wide> world</wide></hello>",
"<{}hello>\n<{}wide> world</{}wide></{}hello>"},
/* UTF-8 XML Byte Order Mark */
{ "\xEF\xBB\xBF" PFX "<hello/>", "<{}hello></{}hello>" },
/* UTF-8 XML Byte Order Mark */
{ "\xEF\xBB\xBF" PFX "<hello/>", "<{}hello></{}hello>", match_chunked },
/*** Tests for namespace handling. ***/
#define NSA "xmlns:foo='bar'"
{ PFX "<foo:widget " NSA "/>",
@ -329,7 +352,27 @@ static int fail_parse(void)
/* malformed namespace declarations */
PFX "<foo xmlns:D=''/>",
PFX "<foo xmlns:='fish'/>",
PFX "<foo xmlns:.bar='fish'/>",
PFX "<foo xmlns:-bar='fish'/>",
PFX "<foo xmlns:0bar='fish'/>",
PFX "<fee xmlns:8baz='bar'/>",
/* element names which are not valid QNames. */
PFX "<foo: xmlns:foo='bar'/>",
PFX "<:fee/>",
PFX "<0fish/>",
PFX "<foo:0fish xmlns:foo='bar'/>",
PFX "<foo:9fish xmlns:foo='bar'/>",
PFX "<foo:-fish xmlns:foo='bar'/>",
PFX "<foo:.fish xmlns:foo='bar'/>",
#if 0 /* currently disabled to allow SVN to work */
PFX "<foo:bar:baz xmlns:foo='bar'/>",
PFX "<fee xmlns:baz:bar='bar'/>",
PFX "<fee xmlns::bar='bar'/>",
PFX "<foo::fish xmlns:foo='bar'/>",
#endif
#if 0
/* 2-byte encoding of '.': */
PFX "<foo>" "\x2F\xC0\xAE\x2E\x2F" "</foo>",
@ -341,9 +384,14 @@ static int fail_parse(void)
PFX "<foo>" "\x2F\xF8\x80\x80\x80\xAE\x2E\x2F" "</foo>",
/* 6-byte encoding of '.': */
PFX "<foo>" "\x2F\xFC\x80\x80\x80\x80\xAE\x2E\x2F" "</foo>",
#endif
/* two-byte encoding of '<' must not be parsed as a '<': */
PFX "\xC0\xBC" "foo></foo>",
#endif
/* Invalid UTF-8 XML Byte Order Marks */
"\xEF\xBB" PFX "<hello/>",
"\xEF" PFX "<hello/>",
NULL
};
int n;
@ -354,10 +402,13 @@ static int fail_parse(void)
ne_xml_parse(p, docs[n], strlen(docs[n]));
ne_xml_parse(p, "", 0);
ONV(ne_xml_valid(p), ("`%s' was valid", docs[n]));
ONV(ne_xml_failed(p) <= 0,
("`%s' did not get positive parse error", docs[n]));
err = ne_xml_get_error(p);
ONV(strstr(err, "parse error") == NULL,
NE_DEBUG(NE_DBG_HTTP, "Parse error for '%s': %s\n", docs[n], err);
ONV(strstr(err, "parse error") == NULL
&& strstr(err, "Invalid Byte Order Mark") == NULL,
("bad error %s", err));
ne_xml_destroy(p);
@ -426,7 +477,7 @@ static int attributes(void)
ne_xml_parse_v(p, doc, strlen(doc));
ONV(!ne_xml_valid(p), ("parse error: %s", ne_xml_get_error(p)));
ONV(ne_xml_failed(p), ("parse error: %s", ne_xml_get_error(p)));
ne_xml_destroy(p);
return OK;