Update to neon trunk.
CVS patchset: 7523 CVS date: 2004/10/29 13:57:41
This commit is contained in:
parent
e603ae4198
commit
69227ecd1b
|
@ -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
|
||||
|
|
|
@ -1 +1 @@
|
|||
0.24.7
|
||||
0.0.0-dev
|
||||
|
|
|
@ -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>
|
||||
|
|
21
neon/BUGS
21
neon/BUGS
|
@ -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
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
19
neon/NEWS
19
neon/NEWS
|
@ -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
|
||||
|
|
36
neon/README
36
neon/README
|
@ -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>
|
||||
|
|
62
neon/THANKS
62
neon/THANKS
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -1 +1 @@
|
|||
5 July 2004
|
||||
29 October 2004
|
|
@ -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 -->
|
||||
<!-- ******************************************************************* -->
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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 <ne_session.h></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>
|
|
@ -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 <ne_xml.h></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>
|
||||
|
|
@ -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—WebDAV</title>
|
||||
|
@ -116,4 +116,25 @@
|
|||
quotes—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>
|
||||
|
|
|
@ -1 +1 @@
|
|||
0.24.7
|
||||
0.0.0-dev
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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], [
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)"
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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(). */
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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-----
|
|
@ -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-----
|
|
@ -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-----
|
|
@ -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-----
|
|
@ -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-----
|
|
@ -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-----
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
|
|
@ -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),
|
||||
};
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue