summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in2
-rw-r--r--NEWS13
-rw-r--r--THANKS5
-rw-r--r--doc/biblio.xml74
-rw-r--r--doc/manual.css8
-rw-r--r--doc/manual.xml26
-rw-r--r--doc/ref/clicert.xml2
-rw-r--r--doc/ref/neon.xml57
-rw-r--r--doc/ref/req.xml4
-rw-r--r--doc/ref/sess.xml10
-rw-r--r--doc/ref/shave.xml3
-rw-r--r--doc/ref/sslcert.xml177
-rw-r--r--doc/ref/sslcert2.xml49
-rw-r--r--doc/ref/sslcertio.xml95
-rw-r--r--doc/ref/ssldname.xml15
-rw-r--r--doc/ref/ssltrust.xml72
-rw-r--r--doc/ref/sslvfy.xml103
-rw-r--r--doc/ref/status.xml20
-rw-r--r--doc/ssl.xml24
-rw-r--r--doc/xml.xml3
-rw-r--r--macros/ChangeLog8
-rw-r--r--macros/neon.m429
-rw-r--r--src/.cvsignore1
-rw-r--r--src/ChangeLog80
-rw-r--r--src/ne_207.c8
-rw-r--r--src/ne_auth.c146
-rw-r--r--src/ne_compress.c43
-rw-r--r--src/ne_cookies.c1
-rw-r--r--src/ne_defs.h25
-rw-r--r--src/ne_openssl.c8
-rw-r--r--src/ne_private.h2
-rw-r--r--src/ne_request.c29
-rw-r--r--src/ne_session.c25
-rw-r--r--src/ne_socket.c16
-rw-r--r--src/ne_socket.h7
-rw-r--r--src/ne_utils.c50
-rw-r--r--test/.cvsignore4
-rw-r--r--test/ChangeLog13
-rw-r--r--test/Makefile.in183
-rw-r--r--test/common/.cvsignore1
-rw-r--r--test/common/ChangeLog10
-rw-r--r--test/common/tests.c5
-rw-r--r--test/common/tests.h3
-rw-r--r--test/compress.c19
-rw-r--r--test/lock.c2
-rw-r--r--test/run.sh5
-rw-r--r--test/string-tests.c2
47 files changed, 1130 insertions, 357 deletions
diff --git a/Makefile.in b/Makefile.in
index 1d07c7f..bd1833d 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -44,7 +44,7 @@ transform = @program_transform_name@
LIBTOOL = @LIBTOOL@
-XMLTO = xmlto --skip-validation
+XMLTO = xmlto
# The headers to distribute - making up the public interface of neon
DIST_HEADERS = ne_request.h ne_session.h ne_utils.h ne_uri.h ne_socket.h \
diff --git a/NEWS b/NEWS
index 03ea3d2..b7021b1 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,16 @@
+Changes in release 0.24.1:
+* Add support for "GSS-Negotiate" Kerberos authentication scheme (from
+ Risko Gergely and Burjan Gabor).
+* Disable Nagle to improve performance of small requests (thanks to
+ Jim Whitehead and Teng Xu).
+* Fix compatibility with OpenSSL 0.9.6 (broken in 0.24.0).
+* Fix prototype mismatch in ne_207.c.
+* Define ssize_t from ne_request.h for Win32.
+* Prevent segfault on zlib initialization failures.
+* ne_sock_init does not fail if PRNG could not be seeded.
+* Fix segfault in cookies code (Markus Mueller).
+* Documentation updates.
+
Changes in release 0.24.0:
* Major changes to XML interface:
- have the start-element callback either accept, decline, abort,
diff --git a/THANKS b/THANKS
index 43925d5..f600ae0 100644
--- a/THANKS
+++ b/THANKS
@@ -12,12 +12,14 @@ 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>
Michael Sobolev <mss@despair.spb.ru>
Mike Rosellini <m@icopyright.com>
Mo DeJong <mdejong@cygnus.com>
@@ -27,13 +29,16 @@ 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>
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>
diff --git a/doc/biblio.xml b/doc/biblio.xml
new file mode 100644
index 0000000..cda37a7
--- /dev/null
+++ b/doc/biblio.xml
@@ -0,0 +1,74 @@
+<bibliography id="biblio"> <!-- -*- xml -*- -->
+
+<biblioentry id="bib.ssltls">
+ <abbrev>SSL-and-TLS</abbrev>
+ <title><ulink url="http://www.rtfm.com/sslbook/">SSL and
+ TLS: Designing and Building Secure Systems</ulink></title>
+ <author><firstname>Eric</firstname><surname>Rescorla</surname></author>
+ <isbn>0-201-62598-3</isbn>
+ <publisher><publishername>Addison-Wesley</publishername></publisher>
+ <pubdate>March 2001</pubdate>
+</biblioentry>
+
+<biblioentry id="bib.xsltrec">
+ <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>
+</biblioentry>
+
+<biblioentry id="bib.rfc2616">
+ <abbrev>RFC2616</abbrev>
+ <title><ulink url="http://www.ietf.org/rfc/rfc2616.txt">Hypertext Transfer
+ Protocol&mdash;HTTP/1.1</ulink></title>
+ <authorgroup>
+ <author><firstname>Roy</firstname><surname>Fielding</surname></author>
+ <author><firstname>Jim</firstname><surname>Gettys</surname></author>
+ <author><firstname>Jeff</firstname><surname>Mogul</surname></author>
+ <author><firstname>Henrik</firstname><surname>Frystyk</surname></author>
+ <author><firstname>Larry</firstname><surname>Masinter</surname></author>
+ <author><firstname>Paul</firstname><surname>Leach</surname></author>
+ <author><firstname>Tim</firstname><surname>Berners-Lee</surname></author>
+ </authorgroup>
+ <publishername>IETF</publishername>
+ <pubdate>June 1999</pubdate>
+</biblioentry>
+
+<biblioentry id="bib.rfc2518">
+ <abbrev>RFC2518</abbrev>
+ <title><ulink url="http://www.ietf.org/rfc/rfc2518.txt">HTTP Extensions for Distributed Authoring&mdash;WEBDAV</ulink></title>
+ <authorgroup>
+ <author><firstname>Yaron</firstname><surname>Goland</surname></author>
+ <author><firstname>Jim</firstname><surname>Whitehead</surname></author>
+ <author><firstname>Asad</firstname><surname>Faizi</surname></author>
+ <author><firstname>Steve</firstname><surname>Carter</surname></author>
+ <author><firstname>Del</firstname><surname>Jensen</surname></author>
+ </authorgroup>
+ <publishername>IETF</publishername>
+ <pubdate>February 1999</pubdate>
+</biblioentry>
+
+<biblioentry id="bib.rfc3280">
+ <abbrev>RFC3280</abbrev>
+ <title><ulink url="http://www.ietf.org/rfc/rfc3280.txt">Internet X.509 Public Key Infrastructure
+ Certificate and Certificate Revocation List (CRL) Profile</ulink></title>
+ <authorgroup>
+ <author><firstname>Russel</firstname><surname>Housley</surname></author>
+ <author><firstname>Warwick</firstname><surname>Ford</surname></author>
+ <author><firstname>Tim</firstname><surname>Polk</surname></author>
+ <author><firstname>David</firstname><surname>Solo</surname></author>
+ </authorgroup>
+ <publishername>IETF</publishername>
+ <pubdate>April 2002</pubdate>
+</biblioentry>
+
+<!-- RFCs: 2617 -->
+
+<!-- Other interesting RFCs:
+
+ 3490 : Internationalizing Domain Names in Applications (IDNA)
+ 3493 : Basic Socket Interface Extensions for IPv6
+ -->
+
+</bibliography>
diff --git a/doc/manual.css b/doc/manual.css
index 621feb5..feca0a1 100644
--- a/doc/manual.css
+++ b/doc/manual.css
@@ -7,8 +7,8 @@ div.legalnotice { font-size: 80%; margin-left: 2em; }
a:visited { color: darkgreen; }
-div.navheader { border-top: thin solid #bbf2bb; }
-div.navfooter { border-bottom: thin solid #bbf2bb; }
+div.navheader { border-top: 1px solid #bbf2bb; }
+div.navfooter { border-bottom: 1px solid #bbf2bb; }
div.funcprototype { margin-top: 0.2em; margin-left: 0.4em; margin-bottom: 0.2em; }
@@ -25,7 +25,7 @@ div.funcsynopsis, div.cmdsynopsis {
}
div.warning {
- border: thin solid #777777;
+ border: 1px solid #777777;
}
h1.title { border-bottom: thick solid #bbf2bb; padding-bottom: 0.1em; }
@@ -39,4 +39,4 @@ h2, h3 { padding-left: 0.2em; padding-top: -0.1em; }
h2 { background-color: #bbf2bb; font-size: 110%;
padding-bottom: 0.3em; padding-top: 0.2em; spacing-top: 0.1em; }
-h3 { border-bottom: thin solid #bbf2bb; }
+h3 { border-bottom: 1px solid #bbf2bb; }
diff --git a/doc/manual.xml b/doc/manual.xml
index 893f007..06e7bca 100644
--- a/doc/manual.xml
+++ b/doc/manual.xml
@@ -31,9 +31,12 @@
<!ENTITY cdata "<emphasis>character-data</emphasis>">
<!ENTITY endelm "<emphasis>end-element</emphasis>">
-<!ENTITY section.xml SYSTEM "xml.xml">
<!ENTITY section.features SYSTEM "feat.xml">
<!ENTITY section.using SYSTEM "using.xml">
+<!ENTITY section.xml SYSTEM "xml.xml">
+<!ENTITY section.ssl SYSTEM "ssl.xml">
+
+<!ENTITY biblio SYSTEM "biblio.xml">
<!ENTITY refneon SYSTEM "ref/neon.xml">
<!ENTITY refconfig SYSTEM "ref/config.xml">
@@ -43,8 +46,10 @@
<!ENTITY refopts SYSTEM "ref/opts.xml">
<!ENTITY refsslvfy SYSTEM "ref/sslvfy.xml">
<!ENTITY refsslcert SYSTEM "ref/sslcert.xml">
+<!ENTITY refsslcert2 SYSTEM "ref/sslcert2.xml">
+<!ENTITY refsslcertio SYSTEM "ref/sslcertio.xml">
<!ENTITY refssldname SYSTEM "ref/ssldname.xml">
-<!ENTITY refsslca SYSTEM "ref/sslca.xml">
+<!ENTITY refssltrust SYSTEM "ref/ssltrust.xml">
<!ENTITY refreq SYSTEM "ref/req.xml">
<!ENTITY refreqhdr SYSTEM "ref/reqhdr.xml">
<!ENTITY refstatus SYSTEM "ref/status.xml">
@@ -110,10 +115,17 @@ ignoring the WebDAV support if desired.</para>
</chapter>
<chapter id="api">
- <title>The neon API for the C language</title>
+ <title>The &neon; C language interface</title>
+
+ <para>The documentation for the &neon; interface is split between
+ this chapter, which gives a broad introduction to the abstractions
+ exposed by the library, and <xref linkend="ref"/>, which gives a
+ function-by-function breakdown of the interface.</para>
&section.xml;
+<!-- &section.ssl; -->
+
</chapter>
<reference id="ref">
@@ -148,9 +160,11 @@ ignoring the WebDAV support if desired.</para>
&refauth; <!-- ne_set_server_auth -->
&refshave; <!-- ne_shave -->
&refinit; <!-- ne_sock_init -->
- &refsslcert; <!-- ne_ssl_certificate -->
+ &refsslcert; <!-- ne_ssl_cert_identity -->
+ &refsslcert2; <!-- ne_ssl_cert_cmp -->
+ &refsslcertio; <!-- ne_ssl_cert_read -->
&refssldname; <!-- ne_ssl_dname -->
- &refsslca; <!-- ne_ssl_load_ca -->
+ &refssltrust; <!-- ne_ssl_load_ca -->
&refsslvfy; <!-- ne_ssl_set_verify -->
&refclicert; <!-- ne_ssl_client_cert -->
&refstatus; <!-- ne_status -->
@@ -162,6 +176,8 @@ ignoring the WebDAV support if desired.</para>
</reference>
+&biblio;
+
&fdl;
</book>
diff --git a/doc/ref/clicert.xml b/doc/ref/clicert.xml
index 47a2ce0..c61404c 100644
--- a/doc/ref/clicert.xml
+++ b/doc/ref/clicert.xml
@@ -146,7 +146,7 @@ ne_ssl_set_clicert(sess, ccert);
<refsect1>
<title>See also</title>
- <para><xref linkend="ne_ssl_certificate"/></para>
+ <para><xref linkend="ne_ssl_cert_read"/></para>
</refsect1>
</refentry>
diff --git a/doc/ref/neon.xml b/doc/ref/neon.xml
index 9857c63..7c11325 100644
--- a/doc/ref/neon.xml
+++ b/doc/ref/neon.xml
@@ -34,11 +34,38 @@
<refsect2>
<title>Thread-safeness and global initialization</title>
- <para>&neon; itself is implemented to be thread-safe (avoiding
- any use of global state), but in some configurations makes use of
- other libraries which require global initialization. The
- <xref linkend="ne_sock_init"/> function should be called before
- any other use of the &neon; library interface.</para>
+ <para>&neon; itself is implemented to be thread-safe (avoiding any
+ use of global state), but relies on the operating system providing
+ a thread-safe resolver interface. Modern operating systems offer
+ the thread-safe <function>getaddrinfo</function> interface, which
+ &neon; supports; some others implement
+ <function>gethostbyname</function> using thread-local
+ storage.</para>
+
+ <para>To allow thread-safe use of the OpenSSL library, the
+ application must register some locking callbacks in accordance
+ with the <ulink
+ url="http://www.openssl.org/docs/crypto/threads.html">OpenSSL
+ documentation</ulink>.</para>
+
+ <para>Some platforms and libraries used by &neon; require global
+ initialization before use; notably:
+
+ <itemizedlist>
+ <listitem><simpara>OpenSSL requires global initialization to
+ load shared lookup tables.</simpara></listitem>
+
+ <listitem><simpara>The SOCKS library requires initialization
+ before use.</simpara></listitem>
+
+ <listitem><simpara>The Win32 socket library requires
+ initialization before use.</simpara></listitem>
+ </itemizedlist>
+
+ The <xref linkend="ne_sock_init"/> function should be called
+ before any other use of &neon; to perform any necessary
+ initialization needed for the particular platform.</para>
+
</refsect2>
<refsect2>
@@ -91,11 +118,12 @@
<refsect2>
<title>Argument validation</title>
- <para>&neon; does not attempt to validate that arguments passed to
- functions conform to the API (for instance, checking that pointer
- arguments are not &null;). Any use of the &neon; API which is not
- documented to produce a certain behaviour results in
- <emphasis>undefined behaviour</emphasis>, by definition.</para>
+ <para>&neon; does not attempt to validate that the parameters
+ passed to functions conform to the API (for instance, checking
+ that pointer arguments are not &null;). Any use of the &neon; API
+ which is not documented to produce a certain behaviour results is
+ said to produce <emphasis>undefined behaviour</emphasis>; it is
+ likely that &neon; will segfault under these conditions.</para>
</refsect2>
@@ -111,6 +139,15 @@
</refsect2>
<refsect2>
+ <title>User interaction</title>
+
+ <para>As a pure library interface, &neon; will never produce
+ output on <constant>stdout</constant> or
+ <constant>stderr</constant>; all user interaction is the
+ responsibilty of the application.</para>
+ </refsect2>
+
+ <refsect2>
<title>Memory handling</title>
<para>neon does not attempt to cope gracefully with an
diff --git a/doc/ref/req.xml b/doc/ref/req.xml
index 7c36d5c..0dfcd9a 100644
--- a/doc/ref/req.xml
+++ b/doc/ref/req.xml
@@ -53,7 +53,7 @@ parameter, combined with the <parameter>path</parameter> parameter.</para>
<para>The <parameter>path</parameter> string used must conform to the
<literal>abs_path</literal> definition given in RFC2396, with an
optional "?query" part, and must be URI-escaped by the caller (for
-instance, using <function>ne_path_escape</function>. If the string
+instance, using <function>ne_path_escape</function>). If the string
comes from an untrusted source, failure to perform URI-escaping
results in a security vulnerability.</para>
@@ -145,7 +145,7 @@ non-zero error code otherwise.</para>
<title>Example</title>
<para>An example of applying a <literal>MKCOL</literal>
- operation to the resource at the location
+ operation to the resource at the location
<literal>http://www.example.com/foo/bar/</literal>:</para>
<programlisting>ne_session *sess = ne_session_create("http", "www.example.com", 80);
diff --git a/doc/ref/sess.xml b/doc/ref/sess.xml
index 8fcd9cb..93f0038 100644
--- a/doc/ref/sess.xml
+++ b/doc/ref/sess.xml
@@ -65,9 +65,9 @@ global initialization needed by any libraries used by &neon;.</para>
<para>To enable SSL/TLS for the session, pass the string
<literal>"https"</literal> as the <parameter>scheme</parameter>
parameter, and either register a certificate verification function
-(see <xref linkend="ne_ssl_set_verify"/>) or load the appropriate CA
-certificate (see <xref linkend="ne_ssl_load_ca"/>, <xref
-linkend="ne_ssl_load_default_ca"/>).</para>
+(see <xref linkend="ne_ssl_set_verify"/>) or trust the appropriate
+certificate (see <xref linkend="ne_ssl_trust_cert"/>, <xref
+linkend="ne_ssl_trust_default_ca"/>).</para>
<para>If an HTTP proxy server should be used for the session,
<function>ne_session_proxy</function> must be called giving the
@@ -91,7 +91,7 @@ session pointer produces undefined behaviour.</para>
<para>The hostname passed to
<function>ne_session_create</function> is resolved when the first
-request using the session is dispached; a DNS resolution failure can
+request using the session is dispatched; a DNS resolution failure can
only be detected at that time (using the <literal>NE_LOOKUP</literal>
error code); see <xref linkend="ne_request_dispatch"/> for
details.</para>
@@ -117,7 +117,7 @@ ne_session_destroy(sess);
<refsect1>
<title>See Also</title>
- <para><xref linkend="ne_ssl_set_verify"/>, <xref linkend="ne_ssl_load_ca"/>, <xref linkend="ne_sock_init"/></para>
+ <para><xref linkend="ne_ssl_set_verify"/>, <xref linkend="ne_ssl_trust_cert"/>, <xref linkend="ne_sock_init"/></para>
</refsect1>
</refentry>
diff --git a/doc/ref/shave.xml b/doc/ref/shave.xml
index a5b745a..914699d 100644
--- a/doc/ref/shave.xml
+++ b/doc/ref/shave.xml
@@ -32,7 +32,8 @@
<para><function>ne_shave</function> returns a portion of
<parameter>str</parameter> with any leading or trailing characters in
the <parameter>whitespace</parameter> array removed.
-<parameter>str</parameter> may be modified.</para>
+<parameter>str</parameter> may be modified. Note that the return
+value may not be equal to <parameter>str</parameter>.</para>
</refsect1>
diff --git a/doc/ref/sslcert.xml b/doc/ref/sslcert.xml
index 46dbffd..d2d0376 100644
--- a/doc/ref/sslcert.xml
+++ b/doc/ref/sslcert.xml
@@ -1,66 +1,111 @@
- <refentry id="refsslcert">
-
- <refmeta>
- <refentrytitle>ne_ssl_certificate</refentrytitle>
- <manvolnum>3</manvolnum>
- </refmeta>
-
- <refnamediv>
- <refname id="ne_ssl_certificate">ne_ssl_certificate</refname>
- <refname id="ne_ssl_dname">ne_ssl_dname</refname>
- <refpurpose>structures representing SSL certificates</refpurpose>
- </refnamediv>
-
- <refsynopsisdiv>
-
- <funcsynopsis><funcsynopsisinfo>#include &lt;ne_session.h&gt;
-
-/* A simplified X.509 distinguished name. */
-typedef struct {
- const char *country, *state, *locality, *organization;
- const char *organizationalUnit;
- const char *commonName;
-} <type>ne_ssl_dname</type>;
-
-/* A simplified SSL certificate. */
-typedef struct {
- const <type>ne_ssl_dname</type> *subject, *issuer;
- const char *from, *until;
-} <type>ne_ssl_certificate</type>;
-
-</funcsynopsisinfo></funcsynopsis>
-
- </refsynopsisdiv>
-
- <refsect1>
- <title>Description</title>
-
- <para>The <type>ne_ssl_dname</type> structure is used to
-represent a simplified X.509 distinguished name, as used in SSL
-certificates; a distinguished name is used to uniquely identify an
-entity. Along with the fields giving the geographical and
-organizational location of the entity, the
-<structfield>commonName</structfield> field will be assigned the DNS
-hostname of the entity. The
-<function>ne_ssl_readable_dname</function> function can be used to
-create a single-line string out of an <type>ne_ssl_dname</type>
-structure.</para>
-
- <para>The <type>ne_ssl_certificate</type> structure is used to
-represent a simplified SSL certificate; containing the distinguished
-names of the <firstterm>issuer</firstterm> and
-<firstterm>subject</firstterm> of the certificate. The issuer is the
-entity which has digitally signed the certificate to guarantee its
-authenticity; the subject is the owner of the certificate. A
-certificate is only valid for a certain period of time: the
-<structfield>from</structfield> and <structfield>until</structfield>
-contain strings giving the validity period.</para>
-
- </refsect1>
-
- <refsect1>
- <title>See Also</title>
- <para><xref linkend="ne_ssl_dname"/>, <xref linkend="ne_ssl_set_verify"/></para>
- </refsect1>
-
- </refentry>
+<refentry id="refcert">
+
+ <refmeta>
+ <refentrytitle>ne_ssl_cert_identity</refentrytitle>
+ <manvolnum>3</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname id="ne_ssl_cert_identity">ne_ssl_cert_identity</refname>
+ <refname id="ne_ssl_cert_signedby">ne_ssl_cert_signedby</refname>
+ <refname id="ne_ssl_cert_issuer">ne_ssl_cert_issuer</refname>
+ <refname id="ne_ssl_cert_subject">ne_ssl_cert_subject</refname>
+ <refpurpose>functions to access certificate properties</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+
+ <funcsynopsis>
+
+ <funcsynopsisinfo>#include &lt;ne_ssl.h&gt;</funcsynopsisinfo>
+
+ <funcprototype>
+ <funcdef>const char *<function>ne_ssl_cert_identity</function></funcdef>
+ <paramdef>const ne_ssl_certificate *<parameter>cert</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>const ne_ssl_certificate *<function>ne_ssl_cert_signedby</function></funcdef>
+ <paramdef>const ne_ssl_certificate *<parameter>cert</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>const ne_ssl_dname *<function>ne_ssl_cert_subject</function></funcdef>
+ <paramdef>const ne_ssl_certificate *<parameter>cert</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>const ne_ssl_dname *<function>ne_ssl_cert_issuer</function></funcdef>
+ <paramdef>const ne_ssl_certificate *<parameter>cert</parameter></paramdef>
+ </funcprototype>
+
+ </funcsynopsis>
+
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>The function <function>ne_ssl_cert_identity</function>
+ retrieves the <quote>identity</quote> of a certificate; for an
+ SSL server certificate, this will be the hostname for which the
+ certificate was issued. In PKI parlance, the identity is the
+ <emphasis>common name</emphasis> attribute of the distinguished name of
+ the certificate subject.</para>
+
+ <para>The functions <function>ne_ssl_cert_subject</function> and
+ <function>ne_ssl_cert_issuer</function> can be used to access the
+ objects representing the distinguished name of the subject and of
+ the issuer of a certificate, respectively.</para>
+
+ <para>If a certificate object is part of a certificate chain, then
+ <function>ne_ssl_cert_signedby</function> can be used to find the
+ certificate which signed a particular certificate. For a
+ self-signed certificate or a certificate for which the full chain
+ is not available, this function will return &null;.</para>
+
+ </refsect1>
+
+ <refsect1>
+ <title>Return value</title>
+
+ <para><function>ne_ssl_cert_issuer</function> and
+ <function>ne_ssl_cert_subject</function> are guaranteed to never
+ return &null;. <function>ne_ssl_cert_identity</function> may
+ return &null; if the certificate has no specific
+ <quote>identity</quote>. <function>ne_ssl_cert_signedby</function>
+ may return &null; as covered above.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Examples</title>
+
+ <para>The following function could be used to display information
+ about a given certificate:</para>
+
+ <programlisting>void dump_cert(const ne_ssl_certificate *cert) {
+ const char *id = ne_ssl_cert_identity(cert);
+ char *dn;
+
+ if (id)
+ printf("Certificate was issued for '%s'.\n", id);
+
+ dn = ne_ssl_readable_dname(ne_ssl_cert_subject(cert));
+ printf("Subject: %s\n", dn);
+ free(dn);
+
+ dn = ne_ssl_readable_dname(ne_ssl_cert_issuer(cert));
+ printf("Issuer: %s\n", dn);
+ free(dn);
+}</programlisting>
+
+ </refsect1>
+
+ <refsect1>
+ <title>See also</title>
+
+ <para><xref linkend="ne_ssl_cert_cmp"/>, <xref linkend="ne_ssl_readable_dname"/></para>
+ </refsect1>
+
+</refentry>
+
diff --git a/doc/ref/sslcert2.xml b/doc/ref/sslcert2.xml
new file mode 100644
index 0000000..216d294
--- /dev/null
+++ b/doc/ref/sslcert2.xml
@@ -0,0 +1,49 @@
+<refentry id="refsslcert2">
+
+ <refmeta>
+ <refentrytitle>ne_ssl_cert_cmp</refentrytitle>
+ <manvolnum>3</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname id="ne_ssl_cert_cmp">ne_ssl_cert_cmp</refname>
+ <refname id="ne_ssl_cert_free">ne_ssl_cert_free</refname>
+ <refpurpose>functions to operate on certificate objects</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+
+ <funcsynopsis>
+
+ <funcsynopsisinfo>#include &lt;ne_header.h&gt;</funcsynopsisinfo>
+
+ <funcprototype>
+ <funcdef>int <function>ne_ssl_cert_cmp</function></funcdef>
+ <paramdef>const ne_ssl_certificate *<parameter>c1</parameter></paramdef>
+ <paramdef>const ne_ssl_certificate *<parameter>c2</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>void <function>ne_ssl_cert_free</function></funcdef>
+ <paramdef>ne_ssl_certificate *<parameter>cert</parameter></paramdef>
+ </funcprototype>
+
+ </funcsynopsis>
+
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>The <function>ne_ssl_cert_cmp</function> function can be
+ used to compare two certificate objects; it returns zero if they
+ refer to the same certificate, and non-zero otherwise.</para>
+
+ <para>The <function>ne_ssl_cert_free</function> function can be
+ used to destroy a certificate object when it is no longer
+ needed.</para>
+
+ </refsect1>
+
+</refentry>
+
diff --git a/doc/ref/sslcertio.xml b/doc/ref/sslcertio.xml
new file mode 100644
index 0000000..394045e
--- /dev/null
+++ b/doc/ref/sslcertio.xml
@@ -0,0 +1,95 @@
+<refentry id="refsslcertio">
+
+ <refmeta>
+ <refentrytitle>ne_ssl_cert_read</refentrytitle>
+ <manvolnum>3</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname id="ne_ssl_cert_read">ne_ssl_cert_read</refname>
+ <refname id="ne_ssl_cert_write">ne_ssl_cert_write</refname>
+ <refname id="ne_ssl_cert_import">ne_ssl_cert_import</refname>
+ <refname id="ne_ssl_cert_export">ne_ssl_cert_export</refname>
+ <refpurpose>functions to read or write certificates to and from files or strings</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+
+ <funcsynopsis>
+
+ <funcsynopsisinfo>#include &lt;ne_ssl.h&gt;</funcsynopsisinfo>
+
+ <funcprototype>
+ <funcdef>ne_ssl_certificate *<function>ne_ssl_cert_read</function></funcdef>
+ <paramdef>const char *<parameter>filename</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>ne_ssl_cert_write</function></funcdef>
+ <paramdef>const ne_ssl_certificate *<parameter>cert</parameter></paramdef>
+ <paramdef>const char *<parameter>filename</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>ne_ssl_certificate *<function>ne_ssl_cert_import</function></funcdef>
+ <paramdef>const char *<parameter>data</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>char *<function>ne_ssl_cert_export</function></funcdef>
+ <paramdef>const ne_ssl_certificate *<parameter>cert</parameter></paramdef>
+ </funcprototype>
+
+ </funcsynopsis>
+
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>The <function>ne_ssl_cert_write</function> function writes a
+ certificate to a file using the PEM encoding. The
+ <function>ne_ssl_cert_export</function> function returns a
+ base64-encoded &nul;-terminated string representing the
+ certificate. This string is malloc-allocated and should be
+ destroyed using <function>free</function> by the caller.</para>
+
+ <para>The <function>ne_ssl_cert_read</function> function reads a
+ certificate from a PEM-encoded file, and returns a certificate
+ object. The <function>ne_ssl_cert_import</function> function
+ returns a certificate object from a base64-encoded string,
+ <parameter>data</parameter>, as returned by
+ <function>ne_ssl_cert_export</function>. The certificate object
+ returned by these functions should be destroyed using <xref
+ linkend="ne_ssl_cert_free"/> after use.</para>
+
+
+ </refsect1>
+
+ <refsect1>
+ <title>Return value</title>
+
+ <para><function>ne_ssl_cert_read</function> returns &null; if a
+ certificate could not be read from the file.
+ <function>ne_ssl_cert_write</function> returns non-zero if the
+ certificate could not be written to the file.
+ <function>ne_ssl_cert_export</function> always returns a
+ &nul;-terminated string, and never &null;.
+ <function>ne_ssl_cert_import</function> returns &null; if the
+ string was not a valid base64-encoded certificate.</para>
+
+ </refsect1>
+
+ <refsect1>
+ <title>Encoding Formats</title>
+
+ <para>The string produced by
+ <function>ne_ssl_cert_export</function> is the base64 encoding of
+ the DER representation of the certificate. The file written by
+ <function>ne_ssl_cert_write</function> uses the PEM format: this
+ is the base64 encoding of the DER representation with newlines
+ every 64 characters, and start and end marker lines.</para>
+ </refsect1>
+
+</refentry>
+
diff --git a/doc/ref/ssldname.xml b/doc/ref/ssldname.xml
index accc2cb..e1fd454 100644
--- a/doc/ref/ssldname.xml
+++ b/doc/ref/ssldname.xml
@@ -51,16 +51,23 @@ creates a single-line, human-readable string out of an
<refsect1>
<title>Return value</title>
- <para><function>ne_ssl_readable_dname</function> returns a
- <function>malloc</function>-allocated string, and never
- NULL.</para>
+ <para><function>ne_ssl_readable_dname</function> returns a <function>malloc</function>-allocated
+ string, and never &null;.</para>
+
+ </refsect1>
+
+ <refsect1>
+ <title>Examples</title>
+
+ <para>See <xref linkend="ne_ssl_cert_subject"/> for an example
+ use of <function>ne_ssl_readable_dname</function>.</para>
</refsect1>
<refsect1>
<title>See also</title>
- <para><xref linkend="ne_ssl_certificate"/></para>
+ <para><xref linkend="ne_ssl_cert_subject"/></para>
</refsect1>
</refentry>
diff --git a/doc/ref/ssltrust.xml b/doc/ref/ssltrust.xml
new file mode 100644
index 0000000..5a22f50
--- /dev/null
+++ b/doc/ref/ssltrust.xml
@@ -0,0 +1,72 @@
+ <refentry id="refsslca">
+
+ <refmeta>
+ <refentrytitle>ne_ssl_trust_cert</refentrytitle>
+ <manvolnum>3</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname id="ne_ssl_trust_cert">ne_ssl_trust_cert</refname>
+ <refname id="ne_ssl_trust_default_ca">ne_ssl_trust_default_ca</refname>
+ <refpurpose>functions to indicate that certificates are trusted</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+
+ <funcsynopsis>
+
+ <funcsynopsisinfo>#include &lt;ne_session.h&gt;</funcsynopsisinfo>
+
+ <funcprototype>
+ <funcdef>void <function>ne_ssl_trust_cert</function></funcdef>
+ <paramdef>ne_session *<parameter>session</parameter></paramdef>
+ <paramdef>const ne_ssl_certificate *<parameter>cert</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>void <function>ne_ssl_trust_default_ca</function></funcdef>
+ <paramdef>ne_session *<parameter>session</parameter></paramdef>
+ </funcprototype>
+
+ </funcsynopsis>
+
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>To indicate that a given certificate is trusted by the
+user, the certificate object can be passed to
+<function>ne_ssl_trust_cert</function>. The certificate object is
+duplicated internally and can subequently be destroyed.</para>
+
+ <para>The SSL library in use by &neon; may include a default
+set of CA certificates; calling the
+<function>ne_ssl_trust_default_ca</function> function will indicate
+that these CAs are trusted by the user.</para>
+
+ </refsect1>
+
+ <refsect1>
+ <title>Examples</title>
+
+ <para>Load the CA certificate stored in <filename>/path/to/cacert.pem</filename>:</para>
+ <programlisting>&egsess;
+ne_ssl_certificate *cert = ne_ssl_cert_read("/path/to/cacert.pem");
+
+if (cert) {
+ ne_ssl_trust_cert(sess, cert);
+ ne_ssl_cert_free(cert);
+} else {
+ printf("Could not load CA cert: %s\n", ne_get_error(sess));
+}</programlisting>
+ </refsect1>
+
+ <refsect1>
+ <title>See also</title>
+
+ <para><xref linkend="ne_ssl_cert_read"/>, <xref
+ linkend="ne_ssl_cert_import"/>, <xref
+ linkend="ne_ssl_cert_free"/></para> </refsect1>
+
+ </refentry>
diff --git a/doc/ref/sslvfy.xml b/doc/ref/sslvfy.xml
index 98f0054..b044d5b 100644
--- a/doc/ref/sslvfy.xml
+++ b/doc/ref/sslvfy.xml
@@ -1,4 +1,4 @@
- <refentry id="refsslvfy">
+ <refentry id="refsslvfy"> <!-- -*- xml-mode -*- -->
<refmeta>
<refentrytitle>ne_ssl_set_verify</refentrytitle>
@@ -19,7 +19,7 @@
<!-- hard to put data type declarations here -->
<funcprototype>
- <funcdef>typedef int (*<function>ne_ssl_verify_fn</function>)</funcdef>
+ <funcdef>typedef int <function>ne_ssl_verify_fn</function></funcdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
<paramdef>int <parameter>failures</parameter></paramdef>
<paramdef>const ne_ssl_certificate *<parameter>cert</parameter></paramdef>
@@ -44,7 +44,7 @@ callback can be registered using
<function>ne_ssl_set_verify</function>. If such a callback is not
registered, when a connection is established to an SSL server which
does not present a certificate signed by a trusted CA (see <xref
-linkend="ne_ssl_load_ca"/>), or if the certificate presented is invalid in
+linkend="ne_ssl_trust_cert"/>), or if the certificate presented is invalid in
some way, the connection will fail.</para>
<para>When the callback is invoked, the
@@ -54,35 +54,42 @@ is equal to the bit-wise OR of one or more of the following
constants (and is guaranteed to be non-zero):</para>
<variablelist>
- <varlistentry><term><filename>NE_SSL_NOTYETVALID</filename></term>
+ <varlistentry><term><constant>NE_SSL_NOTYETVALID</constant></term>
<listitem>
- <para>The certificate is not yet valid.</para>
+ <simpara>The certificate is not yet valid.</simpara>
</listitem>
</varlistentry>
- <varlistentry><term><filename>NE_SSL_EXPIRED</filename></term>
+ <varlistentry><term><constant>NE_SSL_EXPIRED</constant></term>
<listitem>
- <para>The certificate has expired.</para>
+ <simpara>The certificate has expired.</simpara>
</listitem>
</varlistentry>
- <varlistentry><term><filename>NE_SSL_CNMISMATCH</filename></term>
+ <varlistentry><term><constant>NE_SSL_IDMISMATCH</constant></term>
<listitem>
- <para>The hostname used for the session does not match
-the hostname to which the certificate was issued: this could mean that
-the connection has been intercepted.</para>
+ <simpara>The hostname used for the session does not match
+the hostname to which the certificate was issued.</simpara>
</listitem>
</varlistentry>
- <varlistentry><term><filename>NE_SSL_UNKNOWNCA</filename></term>
+ <varlistentry><term><constant>NE_SSL_UNTRUSTED</constant></term>
<listitem>
- <para>The Certificate Authority which signed the certificate
-is not trusted.</para>
+ <simpara>The Certificate Authority which signed the certificate
+is not trusted.</simpara>
</listitem>
</varlistentry>
</variablelist>
+ <para>Note that if either of the
+ <constant>NE_SSL_IDMISMATCH</constant> or
+ <constant>NE_SSL_UNTRUSTED</constant> failures is given, the
+ connection may have been intercepted by a third party, and
+ must not be presumed to be <quote>secure</quote>.</para>
+
<para>The <parameter>cert</parameter> parameter passed to the
-callback describes the certificate which was presented by the server,
-see <xref linkend="ne_ssl_certificate"/> for more details. The certificate
-object given is only valid until the callback returns.</para>
+callback represents the certificate which was presented by the server.
+If the server presented a chain of certificates, the chain can be
+accessed using <xref linkend="ne_ssl_cert_signedby"/>. The
+<parameter>cert</parameter> object given is not valid after the
+callback returns.</para>
</refsect1>
@@ -97,35 +104,51 @@ which case, the connection will fail).</para>
<refsect1>
<title>Examples</title>
- <para>Manual certificate verification:</para>
+ <para>The following code implements an example verification
+ callback, using the <function>dump_cert</function> function
+ from <xref linkend="ne_ssl_cert_subject"/> to display
+ certification information. Notice that the hostname of the
+ server used for the session is passed as the
+ <parameter>userdata</parameter> parameter to the
+ callback.</para>
+
<programlisting>
static int
my_verify(void *userdata, int failures, const ne_ssl_certificate *cert)
{
- /* leak the return values of ne_ssl_readable_dname for simplicity! */
- printf("Issuer: %s\n", ne_ssl_readable_dname(cert->issuer);
- printf("Subject: %s\n", ne_ssl_readable_dname(cert->subject);
- if (failures &amp; NE_SSL_CNMISMATCH) {
- printf("Server certificate was issued to `%s'; "
- "connection may have been intercepted!\n",
- cert->subject->commonName);
- }
- if (failures &amp; NE_SSL_EXPIRED) {
- printf("Server certificate expired on %s!", cert->until);
- }
- /* ... check for other failures ... */
- if (prompt_user())
- return 1; /* fail verification */
- else
- return 0; /* trust certificate */
+ const char *hostname = userdata;
+
+ dump_cert(cert);
+
+ puts("Certificate verification failed - the connection may have been "
+ "intercepted by a third party!");
+
+ if (failures &amp; NE_SSL_IDMISMATCH) {
+ const char *id = ne_ssl_cert_identity(cert);
+ if (id)
+ printf("Server certificate was issued to '%s' not '%s'.\n",
+ id, hostname);
+ else
+ printf("The certificate was not issued for '%s'\n", hostname);
+ }
+
+ if (failures &amp; NE_SSL_UNTRUSTED)
+ puts("The certificate is not signed by a trusted Certificate Authority.");
+
+ /* ... check for validity failures ... */
+
+ if (prompt_user())
+ return 1; /* fail verification */
+ else
+ return 0; /* trust the certificate anyway */
}
int
main(...)
{
- ne_session *sess = ne_session_create("https", "some.host.name", 443);
- ne_ssl_set_verify(sess, my_verify, NULL);
- ...
+ ne_session *sess = ne_session_create("https", "some.host.name", 443);
+ ne_ssl_set_verify(sess, my_verify, "some.host.name");
+ ...
}</programlisting>
</refsect1>
@@ -133,8 +156,8 @@ main(...)
<refsect1>
<title>See also</title>
- <para><xref linkend="ne_ssl_certificate"/>, <xref linkend="ne_ssl_load_ca"/>,
- <xref linkend="ne_ssl_dname"/>, <xref linkend="ne_ssl_readable_dname"/></para>
+ <para><xref linkend="ne_ssl_trust_cert"/>, <xref
+ linkend="ne_ssl_readable_dname"/>, <xref linkend="ne_ssl_cert_subject"/></para>
</refsect1>
- </refentry>
+ </refentry>
diff --git a/doc/ref/status.xml b/doc/ref/status.xml
index 56616ea..fbc38b7 100644
--- a/doc/ref/status.xml
+++ b/doc/ref/status.xml
@@ -32,8 +32,12 @@ The <structfield>major_version</structfield> and
supported by the server issuing the response. The
<structfield>code</structfield> field gives the status code of the
result (lying between 100 and 999 inclusive), and the
-<structfield>klass</structfield> field gives the class, which is equal
-to the most significant digit of the status.</para>
+<structfield>klass</structfield> field gives the
+class<footnote><para>the field is named <quote>klass</quote> not
+<quote>class</quote> so that the header can be used from a C++
+program, in which <quote>class</quote> is a reserved
+word)</para></footnote>, which is equal to the most significant digit
+of the status.</para>
<para>There are five classes of HTTP status code defined by
RFC2616:</para>
@@ -41,28 +45,28 @@ to the most significant digit of the status.</para>
<variablelist>
<varlistentry>
<term><literal>1xx</literal></term>
- <listitem><para>Informational response.</para></listitem>
+ <listitem><simpara>Informational response.</simpara></listitem>
</varlistentry>
<varlistentry>
<term><literal>2xx</literal></term>
- <listitem><para>Success: the operation was successful</para></listitem>
+ <listitem><simpara>Success: the operation was successful</simpara></listitem>
</varlistentry>
<varlistentry>
<term><literal>3xx</literal></term>
- <listitem><para>Redirection</para></listitem>
+ <listitem><simpara>Redirection</simpara></listitem>
</varlistentry>
<varlistentry>
- <term><literal>4xx</literal></term> <listitem><para>Client
+ <term><literal>4xx</literal></term> <listitem><simpara>Client
error: the request made was incorrect in some
- manner.</para></listitem>
+ manner.</simpara></listitem>
</varlistentry>
<varlistentry>
<term><literal>5xx</literal></term>
- <listitem><para>Server error</para></listitem>
+ <listitem><simpara>Server error</simpara></listitem>
</varlistentry>
</variablelist>
diff --git a/doc/ssl.xml b/doc/ssl.xml
new file mode 100644
index 0000000..5581373
--- /dev/null
+++ b/doc/ssl.xml
@@ -0,0 +1,24 @@
+<sect1 id="ssl"> <!-- -*- xml -*- -->
+
+ <title>Secure connections: HTTP over SSL</title>
+
+ <para>This section gives an introduction to SSL. The text is
+ inspired by <xref linkend="bib.ssltls"/>.</para>
+
+ <para>&neon; supports the use of HTTP over SSL<footnote><para>The
+term <quote>SSL</quote> is used throughout this section to refer in
+general to both the SSL protocol developed by Netscape and its
+successor TLS, as adopted by the IETF.</para></footnote> to implement
+<firstterm>secure connections</firstterm>. A secure connection in
+this context means a connection which has
+<emphasis>integrity</emphasis>, <emphasis>secrecy</emphasis> and is
+<emphasis>authenticated</emphasis>. Applications must go to some
+effort to correctly support secure connections&mdash;an application
+based on &neon; does not magically become <quote>secure</quote> simply
+by flicking a switch and enabling the use of SSL.</para>
+
+<!-- SSL: integrity, secrecy, authentication. -->
+
+<!-- what is a certificate -->
+
+</sect1>
diff --git a/doc/xml.xml b/doc/xml.xml
index c001073..4292eb1 100644
--- a/doc/xml.xml
+++ b/doc/xml.xml
@@ -10,8 +10,7 @@
url="http://www.saxproject.org/">SAX</ulink> API used by XML
parsers, with an additional abstraction, <firstterm>stacked SAX
handlers</firstterm>, and also giving consistent <ulink
- url="http://www.w3.org/TR/REC-xml-names">XML Namespace
- support</ulink>.</para>
+ url="http://www.w3.org/TR/REC-xml-names">XML Namespace</ulink> support.</para>
<sect2 id="xml-sax">
<title>Introduction to SAX</title>
diff --git a/macros/ChangeLog b/macros/ChangeLog
index 5a5ac37..b0a789c 100644
--- a/macros/ChangeLog
+++ b/macros/ChangeLog
@@ -1,3 +1,11 @@
+Thu Sep 4 21:29:06 2003 Joe Orton <joe@manyfish.co.uk>
+
+ * neon.m4 (LIBNEON_SOURCE_CHECKS): Check for netinet/tcp.h.
+
+Wed Jul 23 21:17:40 2003 Joe Orton <joe@manyfish.co.uk>
+
+ * neon.m4 (NEON_GSSAPI): New macro.
+
Mon Apr 21 18:24:12 2003 Joe Orton <joe@manyfish.co.uk>
* neon-xml-parser.m4 (HAVE_EXPAT): Fail if --with-expat is given
diff --git a/macros/neon.m4 b/macros/neon.m4
index 6b0cee6..f18c560 100644
--- a/macros/neon.m4
+++ b/macros/neon.m4
@@ -122,7 +122,7 @@ AC_DEFUN([NEON_VERSIONS], [
# Define the current versions.
NEON_VERSION_MAJOR=0
NEON_VERSION_MINOR=24
-NEON_VERSION_RELEASE=0
+NEON_VERSION_RELEASE=1
NEON_VERSION_TAG=
NEON_VERSION="${NEON_VERSION_MAJOR}.${NEON_VERSION_MINOR}.${NEON_VERSION_RELEASE}${NEON_VERSION_TAG}"
@@ -482,7 +482,7 @@ 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 netdb.h])
+ signal.h sys/socket.h netinet/in.h netinet/tcp.h netdb.h])
AC_REQUIRE([NE_SNPRINTF])
@@ -532,6 +532,7 @@ fi
NEON_SSL()
NEON_SOCKS()
+NEON_GSSAPI()
AC_SUBST(NEON_CFLAGS)
AC_SUBST(NEON_LIBS)
@@ -766,6 +767,30 @@ esac
AC_SUBST(NEON_SUPPORTS_SSL)
])
+dnl Check for Kerberos installation
+AC_DEFUN([NEON_GSSAPI], [
+AC_PATH_PROG([KRB5_CONFIG], krb5-config, none, $PATH:/usr/kerberos/bin)
+if test "x$KRB5_CONFIG" != "xnone"; then
+ NEON_LIBS="$NEON_LIBS `${KRB5_CONFIG} --libs gssapi`"
+ CPPFLAGS="$CPPFLAGS `${KRB5_CONFIG} --cflags gssapi`"
+ # MIT and Heimdal put gssapi.h in different places
+ AC_CHECK_HEADERS(gssapi/gssapi.h gssapi.h, [
+ NE_CHECK_FUNCS(gss_init_sec_context, [
+ AC_MSG_NOTICE([GSSAPI authentication support enabled])
+ AC_DEFINE(HAVE_GSSAPI, 1, [Define if GSSAPI support is enabled])
+ # MIT Kerberos lacks 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])],
+ [#ifdef HAVE_GSSAPI_GSSAPI_H
+#include <gssapi/gssapi.h>
+#else
+#include <gssapi.h>
+#endif])])
+ break
+ ])
+fi])
+
dnl Adds an --enable-warnings argument to configure to allow enabling
dnl compiler warnings
AC_DEFUN([NEON_WARNINGS],[
diff --git a/src/.cvsignore b/src/.cvsignore
index 5561c9e..6eb5bf3 100644
--- a/src/.cvsignore
+++ b/src/.cvsignore
@@ -13,3 +13,4 @@ checkincl.c
*.bb
*.da
*.bbg
+*.[is]
diff --git a/src/ChangeLog b/src/ChangeLog
index 2893290..3aa1649 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,83 @@
+Thu Sep 4 21:41:38 2003 Joe Orton <joe@manyfish.co.uk>
+
+ * ne_socket.c (ne_sock_init): Succeed even if PRNG was not seeded.
+
+Thu Sep 4 21:33:34 2003 Joe Orton <joe@manyfish.co.uk>
+
+ * ne_session.c (ne_set_useragent): Build and store the entire
+ User-Agent header field in sess->user_agent.
+
+ * ne_request.c (add_fixed_headers): Adjust accordingly; avoid
+ unnecessary calls to ne_buffer_*.
+
+Thu Sep 4 21:27:34 2003 Joe Orton <joe@manyfish.co.uk>
+
+ * ne_socket.c: Include netinet/tcp.h.
+ (ne_sock_connect): Disable the Nagle algorithm; thanks to Jim
+ Whitehead and Teng Xu for the analysis.
+
+Thu Sep 4 11:24:04 2003 Joe Orton <joe@manyfish.co.uk>
+
+ * ne_defs.h: Define ssize_t here for Win32.
+
+ * ne_socket.h: Don't define ssize_t here.
+
+Tue Sep 2 20:20:16 2003 Joe Orton <joe@manyfish.co.uk>
+
+ * ne_auth.c (auth_challenge): Update to use ne_token not
+ split_string, patch by Tom Lee <i_am_gnomey@hotmail.com>.
+
+Wed Jul 30 21:54:38 2003 Joe Orton <joe@manyfish.co.uk>
+
+ * ne_cookies.c (set_cookie_hdl): Fix NULL pointer dereference;
+ thanks to Markus Mueller <markus-m.mueller@ubs.com>.
+
+Fri Jul 25 11:05:52 2003 Joe Orton <joe@manyfish.co.uk>
+
+ * ne_request.c (do_connect): On failure to connect, set error
+ string and call ne_sock_close directly rather than using
+ aborted(); fix leak of socket structure.
+
+Wed Jul 23 23:20:42 2003 Joe Orton <joe@manyfish.co.uk>
+
+ Fix SEGV if inflateInit2 fails with Z_MEM_ERROR etc.
+
+ * ne_compress.c (set_zlib_error): New function.
+ (do_inflate, gz_reader): Use it.
+
+Wed Jul 23 22:50:50 2003 Joe Orton <joe@manyfish.co.uk>
+
+ Add support for GSS-Negotiate; patch from Risko Gergely and Burjan
+ Gabor:
+
+ * ne_auth.c [HAVE_GSSAPI]: Include gssapi.h.
+ (auth_scheme): Add auth_scheme_gssapi.
+ (auth_session): Add gssapi_token.
+ (clean_session): Free gssapi_token.
+ (request_gssapi, get_gss_name, gssapi_challenge): New functions.
+ (tokenize): Handle challenge with single token.
+ (auth_challenge): Accept and process a GSS-Negotiate challenge.
+ (ah_pre_send): Send GSS-Negotiate handshake.
+
+Wed Jul 23 22:46:28 2003 Joe Orton <joe@manyfish.co.uk>
+
+ * ne_207.c (ne_207_set_response_handlers,
+ ne_207_set_propstat_handlers): Fix to match declarations (thanks
+ to Diego Tártara).
+
+Fri Jun 27 20:30:45 2003 Joe Orton <joe@manyfish.co.uk>
+
+ * ne_openssl.c [OPENSSL_VERSION_NUMBER < 0x0090700fL]:
+ Fix build against OpenSSL < 0.9.7.
+
+Sun Jun 22 23:07:45 2003 Joe Orton <joe@manyfish.co.uk>
+
+ * ne_session.c (ne_session_destroy): Replace unnecessary use of
+ NE_FREE with ne_free.
+ (set_hostinfo): Don't free hostport/hostinfo here.
+ (ne_session_proxy): Free existing proxy hostname here if
+ necessary.
+
Sat Jun 21 12:58:25 2003 Joe Orton <joe@manyfish.co.uk>
* ne_request.c (ne_begin_request): Set or clear is_http11 flag
diff --git a/src/ne_207.c b/src/ne_207.c
index ad5e6a1..b5676a7 100644
--- a/src/ne_207.c
+++ b/src/ne_207.c
@@ -78,16 +78,16 @@ static const struct ne_xml_idmap map207[] = {
/* Set the callbacks for the parser */
void ne_207_set_response_handlers(ne_207_parser *p,
- ne_207_start_response start,
- ne_207_end_response end)
+ ne_207_start_response *start,
+ ne_207_end_response *end)
{
p->start_response = start;
p->end_response = end;
}
void ne_207_set_propstat_handlers(ne_207_parser *p,
- ne_207_start_propstat start,
- ne_207_end_propstat end)
+ ne_207_start_propstat *start,
+ ne_207_end_propstat *end)
{
p->start_propstat = start;
p->end_propstat = end;
diff --git a/src/ne_auth.c b/src/ne_auth.c
index ba0095c..966d0f4 100644
--- a/src/ne_auth.c
+++ b/src/ne_auth.c
@@ -62,6 +62,15 @@
#include "ne_uri.h"
#include "ne_i18n.h"
+#ifdef HAVE_GSSAPI
+#ifdef HAVE_GSSAPI_GSSAPI_H /* MIT */
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+#else /* Heimdal. */
+#include <gssapi.h>
+#endif
+#endif
+
/* TODO: should remove this eventually. Need it for
* ne_pull_request_body. */
#include "ne_private.h"
@@ -72,7 +81,8 @@
/* The authentication scheme we are using */
typedef enum {
auth_scheme_basic,
- auth_scheme_digest
+ auth_scheme_digest,
+ auth_scheme_gssapi
} auth_scheme;
typedef enum {
@@ -137,6 +147,10 @@ typedef struct {
unsigned int can_handle:1;
/* This used for Basic auth */
char *basic;
+#ifdef HAVE_GSSAPI
+ /* This used for GSSAPI auth */
+ char *gssapi_token;
+#endif
/* These all used for Digest auth */
char *realm;
char *nonce;
@@ -186,6 +200,9 @@ static void clean_session(auth_session *sess)
NE_FREE(sess->cnonce);
NE_FREE(sess->opaque);
NE_FREE(sess->realm);
+#ifdef HAVE_GSSAPI
+ NE_FREE(sess->gssapi_token);
+#endif
}
/* Returns client nonce string. */
@@ -287,6 +304,73 @@ static char *request_basic(auth_session *sess)
return ne_concat("Basic ", sess->basic, "\r\n", NULL);
}
+#ifdef HAVE_GSSAPI
+/* Add GSSAPI authentication credentials to a request */
+static char *request_gssapi(auth_session *sess)
+{
+ return ne_concat("GSS-Negotiate ", sess->gssapi_token, "\r\n", NULL);
+}
+
+static int get_gss_name(gss_name_t *server, auth_session *sess)
+{
+ int major_status, minor_status;
+ gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
+
+ token.value = ne_concat("khttp@", sess->sess->server.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;
+}
+
+/* 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)
+{
+ gss_ctx_id_t context;
+ gss_name_t server_name;
+ int major_status, minor_status;
+ gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
+
+ clean_session(sess);
+
+ if (get_gss_name(&server_name, sess))
+ return -1;
+
+ major_status = gss_init_sec_context(&minor_status,
+ GSS_C_NO_CREDENTIAL,
+ &context,
+ server_name,
+ GSS_C_NO_OID,
+ GSS_C_DELEG_FLAG,
+ 0,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ &input_token,
+ NULL,
+ &output_token,
+ NULL,
+ NULL);
+ if (GSS_ERROR(major_status)) {
+ NE_DEBUG(NE_DBG_HTTPAUTH, "gss_init_sec_context failed.\n");
+ return -1;
+ }
+
+ if (output_token.length == 0)
+ return -1;
+
+ sess->gssapi_token = ne_base64(output_token.value, output_token.length);
+
+ NE_DEBUG(NE_DBG_HTTPAUTH,
+ "Base64 encoded GSSAPI challenge: %s.\n", sess->gssapi_token);
+ sess->scheme = auth_scheme_gssapi;
+ return 0;
+}
+#endif
+
/* Examine a digest challenge: return 0 if it is a valid Digest challenge,
* else non-zero. */
static int digest_challenge(auth_session *sess, struct auth_challenge *parms)
@@ -563,6 +647,10 @@ static int tokenize(char **hdr, char **key, char **value, int ischall)
}
} while (*++pnt != '\0');
+ if (state == BEFORE_EQ && ischall && *key != NULL) {
+ *value = NULL;
+ }
+
*hdr = pnt;
/* End of string: */
@@ -751,6 +839,11 @@ static int auth_challenge(auth_session *sess, const char *value)
} else if (strcasecmp(key, "digest") == 0) {
NE_DEBUG(NE_DBG_HTTPAUTH, "Digest scheme.\n");
chall->scheme = auth_scheme_digest;
+#ifdef HAVE_GSSAPI
+ } else if (strcasecmp(key, "gss-negotiate") == 0) {
+ NE_DEBUG(NE_DBG_HTTPAUTH, "GSSAPI scheme.\n");
+ chall->scheme = auth_scheme_gssapi;
+#endif
} else {
NE_DEBUG(NE_DBG_HTTPAUTH, "Unknown scheme.\n");
ne_free(chall);
@@ -788,18 +881,16 @@ static int auth_challenge(auth_session *sess, const char *value)
chall->alg = auth_alg_unknown;
}
} else if (strcasecmp(key, "qop") == 0) {
- char **qops;
- int qop;
- qops = split_string(val, ',', NULL, " \r\n\t");
- chall->got_qop = 1;
- for (qop = 0; qops[qop] != NULL; qop++) {
- if (strcasecmp(qops[qop], "auth") == 0) {
- chall->qop_auth = 1;
- } else if (strcasecmp(qops[qop], "auth-int") == 0) {
- chall->qop_auth_int = 1;
- }
- }
- split_string_free(qops);
+ /* iterate over each token in the value */
+ do {
+ const char *tok = ne_shave(ne_token(&val, ','), " \t");
+
+ if (strcasecmp(tok, "auth") == 0) {
+ chall->qop_auth = 1;
+ } else if (strcasecmp(tok, "auth-int") == 0 ) {
+ chall->qop_auth_int = 1;
+ }
+ } while (val);
}
}
@@ -813,17 +904,31 @@ static int auth_challenge(auth_session *sess, const char *value)
success = 0;
- NE_DEBUG(NE_DBG_HTTPAUTH, "Looking for Digest challenges.\n");
-
- /* Try a digest challenge */
+#ifdef HAVE_GSSAPI
+ 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_digest) {
- if (!digest_challenge(sess, chall)) {
+ if (chall->scheme == auth_scheme_gssapi) {
+ if (!gssapi_challenge(sess, chall)) {
success = 1;
break;
}
}
}
+#endif
+
+ /* Try a digest challenge */
+ if (!success) {
+ NE_DEBUG(NE_DBG_HTTPAUTH, "Looking for Digest challenges.\n");
+ for (chall = challenges; chall != NULL; chall = chall->next) {
+ if (chall->scheme == auth_scheme_digest) {
+ if (!digest_challenge(sess, chall)) {
+ success = 1;
+ break;
+ }
+ }
+ }
+ }
if (!success) {
NE_DEBUG(NE_DBG_HTTPAUTH,
@@ -921,6 +1026,11 @@ static void ah_pre_send(ne_request *r, void *cookie, ne_buffer *request)
case auth_scheme_digest:
value = request_digest(sess, req);
break;
+#ifdef HAVE_GSSAPI
+ case auth_scheme_gssapi:
+ value = request_gssapi(sess);
+ break;
+#endif
default:
value = NULL;
break;
diff --git a/src/ne_compress.c b/src/ne_compress.c
index b84b46d..56db5a5 100644
--- a/src/ne_compress.c
+++ b/src/ne_compress.c
@@ -31,6 +31,7 @@
#include "ne_request.h"
#include "ne_compress.h"
#include "ne_utils.h"
+#include "ne_i18n.h"
#ifdef NEON_ZLIB
@@ -170,6 +171,26 @@ static void process_footer(ne_decompress *ctx,
}
}
+/* A zlib function failed with 'code'; set the session error string
+ * appropriately. */
+static void set_zlib_error(ne_decompress *ctx, const char *msg, int code)
+{
+ if (ctx->zstr.msg)
+ ne_set_error(ctx->session, _("%s: %s"), msg, ctx->zstr.msg);
+ else {
+ const char *err;
+ switch (code) {
+ case Z_STREAM_ERROR: err = "stream error"; break;
+ case Z_DATA_ERROR: err = "data corrupt"; break;
+ case Z_MEM_ERROR: err = "out of memory"; break;
+ case Z_BUF_ERROR: err = "buffer error"; break;
+ case Z_VERSION_ERROR: err = "library version mismatch"; break;
+ default: err = "unknown error"; break;
+ }
+ ne_set_error(ctx->session, _("%s: %s (code %d)"), msg, err, code);
+ }
+}
+
/* Inflate response buffer 'buf' of length 'len'. */
static void do_inflate(ne_decompress *ctx, const char *buf, size_t len)
{
@@ -212,9 +233,7 @@ static void do_inflate(ne_decompress *ctx, const char *buf, size_t len)
process_footer(ctx, ctx->zstr.next_in, ctx->zstr.avail_in);
} else if (ret != Z_OK) {
ctx->state = NE_Z_ERROR;
- ne_set_error(ctx->session, "Error reading compressed data.");
- NE_DEBUG(NE_DBG_HTTP, "compress: inflate failed (%d): %s\n",
- ret, ctx->zstr.msg?ctx->zstr.msg:"(no message)");
+ set_zlib_error(ctx, _("Could not inflate data"), ret);
}
}
@@ -248,16 +267,15 @@ static void gz_reader(void *ud, const char *buf, size_t len)
case NE_Z_BEFORE_DATA:
/* work out whether this is a compressed response or not. */
if (ctx->enchdr && strcasecmp(ctx->enchdr, "gzip") == 0) {
+ int ret;
NE_DEBUG(NE_DBG_HTTP, "compress: got gzipped stream.\n");
- /* This is the magic bit: using plain inflateInit()
- * doesn't work, and this does, but I have no idea why..
- * Google showed me the way. */
- if (inflateInit2(&ctx->zstr, -MAX_WBITS) != Z_OK) {
- ne_set_error(ctx->session, ctx->zstr.msg);
- ctx->state = NE_Z_ERROR;
- return;
- }
+ /* inflateInit2() works here where inflateInit() doesn't. */
+ ret = inflateInit2(&ctx->zstr, -MAX_WBITS);
+ if (ret != Z_OK) {
+ set_zlib_error(ctx, _("Could not initialize zlib"), ret);
+ return;
+ }
ctx->zstrinit = 1;
} else {
@@ -291,8 +309,6 @@ static void gz_reader(void *ud, const char *buf, size_t len)
len -= count;
switch (parse_header(ctx)) {
- case HDR_ERROR:
- return;
case HDR_EXTENDED:
if (len == 0)
return;
@@ -301,6 +317,7 @@ static void gz_reader(void *ud, const char *buf, size_t len)
if (len > 0) {
do_inflate(ctx, buf, len);
}
+ default:
return;
}
diff --git a/src/ne_cookies.c b/src/ne_cookies.c
index f84f2fa..1cc1a89 100644
--- a/src/ne_cookies.c
+++ b/src/ne_cookies.c
@@ -81,6 +81,7 @@ static void set_cookie_hdl(void *userdata, const char *value)
cook->value = ne_strdup(pairs[1]);
for (n = 2; pairs[n] != NULL; n+=2) {
+ if (!pairs[n+1]) continue;
NE_DEBUG(NE_DBG_HTTP, "Cookie parm %s=%s\n", pairs[n], pairs[n+1]);
if (strcasecmp(pairs[n], "path") == 0) {
cook->path = ne_strdup(pairs[n+1]);
diff --git a/src/ne_defs.h b/src/ne_defs.h
index f029edf..d13a9bf 100644
--- a/src/ne_defs.h
+++ b/src/ne_defs.h
@@ -1,3 +1,23 @@
+/*
+ Standard definitions for neon headers
+ Copyright (C) 2003, 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
+ 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
+
+*/
#undef BEGIN_NEON_DECLS
#undef END_NEON_DECLS
@@ -8,3 +28,8 @@
# define BEGIN_NEON_DECLS /* empty */
# define END_NEON_DECLS /* empty */
#endif
+
+/* define ssize_t for Win32 */
+#if defined(WIN32) && !defined(ssize_t)
+#define ssize_t int
+#endif
diff --git a/src/ne_openssl.c b/src/ne_openssl.c
index 5d21ef1..359f7a4 100644
--- a/src/ne_openssl.c
+++ b/src/ne_openssl.c
@@ -45,6 +45,14 @@
#include "ne_private.h"
#include "ne_privssl.h"
+/* OpenSSL 0.9.6 compatibility */
+#if OPENSSL_VERSION_NUMBER < 0x0090700fL
+#define PKCS12_unpack_authsafes M_PKCS12_unpack_authsafes
+#define PKCS12_unpack_p7data M_PKCS12_unpack_p7data
+/* cast away lack of const-ness */
+#define OBJ_cmp(a,b) OBJ_cmp((ASN1_OBJECT *)(a), (ASN1_OBJECT *)(b))
+#endif
+
struct ne_ssl_dname_s {
X509_NAME *dn;
};
diff --git a/src/ne_private.h b/src/ne_private.h
index 964800d..aad98f4 100644
--- a/src/ne_private.h
+++ b/src/ne_private.h
@@ -86,7 +86,7 @@ struct ne_session_s {
struct hook *create_req_hooks, *pre_send_hooks, *post_send_hooks;
struct hook *destroy_req_hooks, *destroy_sess_hooks, *private;
- char *user_agent; /* full User-Agent string */
+ char *user_agent; /* full User-Agent: header field */
#ifdef NEON_SSL
ne_ssl_client_cert *client_cert;
diff --git a/src/ne_request.c b/src/ne_request.c
index 0d39214..85287de 100644
--- a/src/ne_request.c
+++ b/src/ne_request.c
@@ -431,23 +431,23 @@ static int send_request_body(ne_request *req)
static void add_fixed_headers(ne_request *req)
{
if (req->session->user_agent) {
- ne_buffer_concat(req->headers,
- "User-Agent: ", req->session->user_agent, EOL, NULL);
+ ne_buffer_zappend(req->headers, req->session->user_agent);
}
- /* Send Connection: Keep-Alive for pre-1.1 origin servers, so we
- * might get a persistent connection. 2068 sec 19.7.1 says we MUST
- * NOT do this for proxies, though. So we don't. Note that on the
- * first request on any session, we don't know whether the server
- * is 1.1 compliant, so we presume that it is not. */
+
+ /* Send Connection: Keep-Alive to pre-1.1 origin servers to try
+ * 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) {
- ne_buffer_zappend(req->headers, "Keep-Alive: " EOL);
- ne_buffer_zappend(req->headers, "Connection: TE, Keep-Alive" EOL);
+ ne_buffer_zappend(req->headers,
+ "Keep-Alive: " EOL
+ "Connection: TE, Keep-Alive" EOL
+ "TE: trailers" EOL);
} else {
- ne_buffer_zappend(req->headers, "Connection: TE" EOL);
+ ne_buffer_zappend(req->headers,
+ "Connection: TE" EOL
+ "TE: trailers" EOL);
}
- /* We send TE: trailers since we understand trailers in the chunked
- * response. */
- ne_buffer_zappend(req->headers, "TE: trailers" EOL);
}
@@ -1338,7 +1338,8 @@ static int do_connect(ne_request *req, struct host_info *host, const char *err)
(host->current = ne_addr_next(host->address)) != NULL);
if (ret) {
- aborted(req, err, ret);
+ ne_set_error(sess, "%s: %s", err, ne_sock_error(sess->socket));
+ ne_sock_close(sess->socket);
return NE_CONNECT;
}
diff --git a/src/ne_session.c b/src/ne_session.c
index fe71079..04b777e 100644
--- a/src/ne_session.c
+++ b/src/ne_session.c
@@ -72,13 +72,13 @@ void ne_session_destroy(ne_session *sess)
destroy_hooks(sess->destroy_sess_hooks);
destroy_hooks(sess->private);
- NE_FREE(sess->server.hostname);
- NE_FREE(sess->server.hostport);
+ ne_free(sess->scheme);
+ ne_free(sess->server.hostname);
+ ne_free(sess->server.hostport);
if (sess->server.address) ne_addr_destroy(sess->server.address);
if (sess->proxy.address) ne_addr_destroy(sess->proxy.address);
- NE_FREE(sess->proxy.hostname);
- NE_FREE(sess->scheme);
- NE_FREE(sess->user_agent);
+ if (sess->proxy.hostname) ne_free(sess->proxy.hostname);
+ if (sess->user_agent) ne_free(sess->user_agent);
if (sess->connected) {
ne_close_connection(sess);
@@ -118,8 +118,6 @@ 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)
{
- NE_FREE(info->hostport);
- NE_FREE(info->hostname);
info->hostname = ne_strdup(hostname);
info->port = port;
}
@@ -158,6 +156,7 @@ void ne_session_proxy(ne_session *sess, const char *hostname,
unsigned int port)
{
sess->use_proxy = 1;
+ if (sess->proxy.hostname) ne_free(sess->proxy.hostname);
set_hostinfo(&sess->proxy, hostname, port);
}
@@ -204,13 +203,19 @@ void ne_set_read_timeout(ne_session *sess, int timeout)
sess->rdtimeout = timeout;
}
-#define AGENT " neon/" NEON_VERSION
+#define UAHDR "User-Agent: "
+#define AGENT " neon/" NEON_VERSION "\r\n"
void ne_set_useragent(ne_session *sess, const char *token)
{
if (sess->user_agent) ne_free(sess->user_agent);
- sess->user_agent = ne_malloc(sizeof AGENT + strlen(token));
- strcat(strcpy(sess->user_agent, token), AGENT);
+ sess->user_agent = ne_malloc(strlen(UAHDR) + strlen(AGENT) +
+ strlen(token) + 1);
+#ifdef HAVE_STPCPY
+ strcpy(stpcpy(stpcpy(sess->user_agent, UAHDR), token), AGENT);
+#else
+ strcat(strcat(strcpy(sess->user_agent, UAHDR), token), AGENT);
+#endif
}
const char *ne_get_server_hostport(ne_session *sess)
diff --git a/src/ne_socket.c b/src/ne_socket.c
index f67e233..fd8afdb 100644
--- a/src/ne_socket.c
+++ b/src/ne_socket.c
@@ -50,6 +50,9 @@
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
@@ -318,10 +321,9 @@ int ne_sock_init(void)
#ifdef NEON_SSL
if (init_ssl()) {
NE_DEBUG(NE_DBG_SOCKET, "SSL initialization failed; lacking PRNG?\n");
- init_result = -1;
- return -1;
+ } else {
+ prng_seeded = 1;
}
- prng_seeded = 1;
#endif
init_result = 1;
@@ -859,6 +861,14 @@ int ne_sock_connect(ne_socket *sock,
return -1;
}
+#if defined(TCP_NODELAY) && defined(HAVE_SETSOCKOPT) && defined(IPPROTO_TCP)
+ { /* Disable the Nagle algorithm; better to add write buffering
+ * instead of doing this. */
+ int flag = 1;
+ setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof flag);
+ }
+#endif
+
if (raw_connect(fd, addr, ntohs(port))) {
set_strerror(sock, ne_errno);
ne_close(fd);
diff --git a/src/ne_socket.h b/src/ne_socket.h
index 58f45ff..4da0c0c 100644
--- a/src/ne_socket.h
+++ b/src/ne_socket.h
@@ -1,6 +1,6 @@
/*
socket handling interface
- Copyright (C) 1999-2002, Joe Orton <joe@manyfish.co.uk>
+ Copyright (C) 1999-2003, 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
@@ -29,11 +29,6 @@
BEGIN_NEON_DECLS
-/* define ssize_t for Win32 */
-#if defined(WIN32) && !defined(ssize_t)
-#define ssize_t int
-#endif
-
#define NE_SOCK_ERROR (-1)
/* Read/Write timed out */
#define NE_SOCK_TIMEOUT (-2)
diff --git a/src/ne_utils.c b/src/ne_utils.c
index 84f7470..e840777 100644
--- a/src/ne_utils.c
+++ b/src/ne_utils.c
@@ -135,41 +135,33 @@ int ne_parse_statusline(const char *status_line, ne_status *st)
const char *part;
int major, minor, status_code, klass;
- /* Check they're speaking the right language */
- status_line = strstr(status_line, "HTTP/");
- if (status_line == NULL) {
- return -1;
- }
-
- /* And find out which dialect of this peculiar language
- * they can talk... */
- major = 0;
- minor = 0;
- /* Note, we're good children, and accept leading zero's on the
- * version numbers */
- for (part = status_line + 5; *part != '\0' && isdigit(*part); part++) {
+ /* skip leading garbage if any. */
+ part = strstr(status_line, "HTTP/");
+ if (part == NULL) return -1;
+
+ minor = major = 0;
+
+ /* Parse version string, skipping leading zeroes. */
+ for (part += 5; *part != '\0' && isdigit(*part); part++)
major = major*10 + (*part-'0');
- }
- if (*part != '.') {
- return -1;
- }
- for (part++ ; *part != '\0' && isdigit(*part); part++) {
+
+ if (*part++ != '.') return -1;
+
+ for (;*part != '\0' && isdigit(*part); part++)
minor = minor*10 + (*part-'0');
- }
- if (*part != ' ') {
- return -1;
- }
+
+ if (*part != ' ') return -1;
+
/* Skip any spaces */
- for (; *part == ' ' ; part++) /* noop */;
- /* Now for the Status-Code. part now points at the first Y in
- * "HTTP/x.x YYY". We want value of YYY... could use atoi, but
- * probably quicker this way. */
+ for (; *part == ' '; part++) /* noop */;
+
+ /* Parse the Status-Code; part now points at the first Y in
+ * "HTTP/x.x YYY". */
if (!isdigit(part[0]) || !isdigit(part[1]) || !isdigit(part[2]) ||
- (part[3] != '\0' && part[3] != ' ')) {
- return -1;
- }
+ (part[3] != '\0' && part[3] != ' ')) return -1;
status_code = 100*(part[0]-'0') + 10*(part[1]-'0') + (part[2]-'0');
klass = part[0]-'0';
+
/* Skip whitespace between status-code and reason-phrase */
for (part+=3; *part == ' ' || *part == '\t'; part++) /* noop */;
diff --git a/test/.cvsignore b/test/.cvsignore
index fb288d0..acc3a9a 100644
--- a/test/.cvsignore
+++ b/test/.cvsignore
@@ -7,7 +7,9 @@ server
regress
compress
*.gz
+*.lo
*.tmp
+.libs
acl
auth
lock
@@ -39,3 +41,5 @@ chain.pem
*.p12
client.*
output.pem
+libtest.*
+clog
diff --git a/test/ChangeLog b/test/ChangeLog
index a32791c..2ea156c 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,3 +1,16 @@
+Sat Aug 30 18:59:24 2003 Joe Orton <joe@manyfish.co.uk>
+
+ * Makefile.in: Rewrite to use libtool to build object files and
+ libtest.
+
+ * run.sh: Don't set LD_LIBRARY_PATH.
+
+Wed Jul 23 23:25:39 2003 Joe Orton <joe@manyfish.co.uk>
+
+ * compress.c (do_fetch): Check for response truncation
+ for success case.
+ (fail_corrupt1, fail_corrupt2): New tests.
+
Sat Jun 21 12:59:49 2003 Joe Orton <joe@manyfish.co.uk>
* request.c (versions): Fix and enable test.
diff --git a/test/Makefile.in b/test/Makefile.in
index eb0da59..be5a6ef 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -3,7 +3,7 @@
SHELL = @SHELL@
CPPFLAGS = @CPPFLAGS@ -I. -I$(top_srcdir)/src -I$(top_srcdir)/test/common
CFLAGS = @CFLAGS@ @NEON_CFLAGS@
-LDFLAGS = -L. @LDFLAGS@ -L$(top_srcdir)/src -L../src/.libs
+LDFLAGS = @LDFLAGS@
DEFS = @DEFS@
top_builddir = ..
@@ -14,7 +14,7 @@ VPATH = @srcdir@
AR = ar
RANLIB = @RANLIB@
-LIBS = -ltest -lneon @NEON_LIBS@
+LIBS = $(LIBTEST)
CC = @CC@
OPENSSL = @OPENSSL@
@@ -22,22 +22,33 @@ HELPERS = @HELPERS@
BASIC_TESTS = uri-tests util-tests string-tests session socket \
request auth basic stubs redirect
ZLIB_TESTS = compress
-ZLIB_HELPERS = file1.gz file2.gz trailing.gz badcsum.gz truncated.gz
+ZLIB_HELPERS = file1.gz file2.gz trailing.gz badcsum.gz truncated.gz corrupt1.gz corrupt2.gz
DAV_TESTS = xml acl props lock
SSL_TESTS = socket-ssl ssl
SSL_HELPERS = ca-stamp
TESTS = @TESTS@
-HDRS = common/tests.h common/child.h utils.h $(top_builddir)/config.h
VALGRIND = valgrind --gdb-attach=yes --leak-check=yes
-LIBTEST = libtest.a
+# Make every object depend on libneon.la to force a rebuild on any src/* changes
+OBJDEPS = $(srcdir)/common/tests.h $(srcdir)/common/child.h $(srcdir)/utils.h \
+ $(top_builddir)/config.h $(top_builddir)/src/libneon.la
+# Test program just depends on libtest
+DEPS = $(LIBTEST)
+
+LIBTEST = libtest.la
+
+LIBTOOL = @LIBTOOL@ --silent
+LINK = $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -no-install
+COMPILE = $(LIBTOOL) --mode=compile $(CC) $(CPPFLAGS) $(CFLAGS)
+
+.SUFFIXES: .lo .c
# By default, compile but don't run the tests.
all: $(TESTS)
clean:
- rm -f $(TESTS) $(HELPERS) *.o common/*.o libtest.a *.log
- rm -rf ca
+ rm -f $(TESTS) $(HELPERS) *.o *.lo 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
@@ -47,15 +58,17 @@ check: $(TESTS) $(HELPERS)
grind: $(TESTS) $(HELPERS)
@SRCDIR=$(srcdir) HARNESS="$(VALGRIND)" $(SHELL) $(srcdir)/run.sh $(TESTS)
-file1.gz: ../NEWS
- gzip -c --no-name $(top_srcdir)/NEWS > $@
+NEWS = $(top_srcdir)/NEWS
+
+file1.gz: $(NEWS)
+ gzip -c --no-name $(NEWS) > $@
-file2.gz: ../NEWS
- gzip -c --name $(top_srcdir)/NEWS > $@
+file2.gz: $(NEWS)
+ gzip -c --name $(NEWS) > $@
# gzip file with trailing bytes.
-trailing.gz: ../NEWS
- gzip -c --no-name $(top_srcdir)/NEWS > $@
+trailing.gz: $(NEWS)
+ gzip -c --no-name $(NEWS) > $@
echo "hello, world" >> $@
truncated.gz: file1.gz
@@ -65,6 +78,13 @@ badcsum.gz: file1.gz
dd of=$@ if=file1.gz bs=1 count=`perl -e 'printf "%d", (stat("file1.gz"))[7] - 8;'`
echo 'broken!' >> $@
+corrupt1.gz: file1.gz
+ dd of=$@ if=file1.gz bs=1 count=500
+ cat $(NEWS) >> $@
+
+corrupt2.gz:
+ cat $(NEWS) > $@
+
# Dummy target to create the CA keys etc. makekeys stderr is redirected
# since it changes for every invocation; not helpful for regression
# testing.
@@ -77,95 +97,58 @@ ca-stamp: $(srcdir)/makekeys.sh $(srcdir)/openssl.conf
Makefile: $(srcdir)/Makefile.in
cd .. && ./config.status test/Makefile
-LIBOBJS = common/tests.o common/child.o utils.o
-
-$(LIBTEST): $(LIBOBJS) $(HDRS) ../src/@NEON_TARGET@
- $(AR) cru $@ $(LIBOBJS)
- $(RANLIB) $@
-
-.c.o:
- $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
-
-uri-tests: uri-tests.o $(LIBTEST)
- $(CC) $(LDFLAGS) $(CFLAGS) -o $@ uri-tests.o $(LIBS)
-
-request: request.o $(LIBTEST)
- $(CC) $(LDFLAGS) -o $@ request.o $(LIBS)
-
-string-tests: string-tests.o $(LIBTEST)
- $(CC) $(LDFLAGS) -o $@ string-tests.o $(LIBS)
-
-socket: socket.o $(LIBTEST)
- $(CC) $(LDFLAGS) -o $@ socket.o $(LIBS)
-
-compress: compress.o $(LIBTEST)
- $(CC) $(LDFLAGS) -o $@ compress.o $(LIBS)
-
-acl: acl.o $(LIBTEST)
- $(CC) $(LDFLAGS) -o $@ acl.o $(LIBS)
-
-utils: utils.o $(LIBTEST)
- $(CC) $(LDFLAGS) -o $@ utils.o $(LIBS)
-
-util-tests: util-tests.o $(LIBTEST)
- $(CC) $(LDFLAGS) -o $@ util-tests.o $(LIBS)
+LIBOBJS = common/tests.lo common/child.lo utils.lo
-auth: auth.o $(LIBTEST)
- $(CC) $(LDFLAGS) -o $@ auth.o $(LIBS)
+$(LIBTEST): $(LIBOBJS)
+ $(LINK) -o $(LIBTEST) $(LIBOBJS) $(top_builddir)/src/libneon.la
-lock: lock.o $(LIBTEST)
- $(CC) $(LDFLAGS) -o $@ lock.o $(LIBS)
+.c.lo:
+ $(COMPILE) -c $< -o $@
-basic: basic.o $(LIBTEST)
- $(CC) $(LDFLAGS) -o $@ basic.o $(LIBS)
+%:%.lo
+ $(LINK) -o $@ $< $(LIBS)
# Recompile socket.c with SOCKET_SSL defined
-socket-ssl.o: $(srcdir)/socket.c $(HDRS)
- $(CC) -DSOCKET_SSL $(CPPFLAGS) $(CFLAGS) -c $(srcdir)/socket.c -o $@
-
-socket-ssl: socket-ssl.o $(LIBTEST)
- $(CC) $(LDFLAGS) -o $@ socket-ssl.o $(LIBS)
-
-ssl: ssl.o $(LIBTEST)
- $(CC) $(LDFLAGS) -o $@ ssl.o $(LIBS)
-
-xml: xml.o $(LIBTEST)
- $(CC) $(LDFLAGS) -o $@ xml.o $(LIBS)
-
-stubs: stubs.o $(LIBTEST)
- $(CC) $(LDFLAGS) -o $@ stubs.o $(LIBS)
-
-redirect: redirect.o $(LIBTEST)
- $(CC) $(LDFLAGS) -o $@ redirect.o $(LIBS)
-
-session: session.o $(LIBTEST)
- $(CC) $(LDFLAGS) -o $@ session.o $(LIBS)
-
-cookies: cookies.o $(LIBTEST)
- $(CC) $(LDFLAGS) -o $@ cookies.o $(LIBS)
-
-props: props.o $(LIBTEST)
- $(CC) $(LDFLAGS) -o $@ props.o $(LIBS)
-
-resolve: resolve.o $(LIBTEST)
- $(CC) $(LDFLAGS) -o $@ resolve.o $(LIBS)
-
-#FOO: FOO.o $(LIBTEST)
-# $(CC) $(LDFLAGS) -o $@ FOO.o $(LIBS)
-
-auth.o: auth.c $(HDRS)
-uri-tests.o: uri-tests.c $(HDRS)
-util-tests.o: util-tests.c $(HDRS)
-string-tests.o: string-tests.c $(HDRS)
-socket.o: socket.c $(HDRS)
-server.o: server.c $(HDRS)
-request.o: request.c $(HDRS)
-regress.o: regress.c $(HDRS)
-compress.o: compress.c $(HDRS)
-acl.o: acl.c $(HDRS)
-utils.o: utils.c $(HDRS)
-stubs.o: stubs.c $(HDRS)
-props.o: props.c $(HDRS)
-session.o: session.c $(HDRS)
-redirect.o: redirect.c $(HDRS)
-basic.o: basic.c $(HDRS)
+socket-ssl.lo: $(srcdir)/socket.c $(HDRS)
+ $(COMPILE) -DSOCKET_SSL -c $(srcdir)/socket.c -o $@
+
+socket-ssl: socket-ssl.lo $(LIBTEST)
+ $(LINK) -o $@ socket-ssl.lo $(LIBS)
+
+auth.lo: $(srcdir)/auth.c $(OBJDEPS)
+uri-tests.lo: $(srcdir)/uri-tests.c $(OBJDEPS)
+util-tests.lo: $(srcdir)/util-tests.c $(OBJDEPS)
+string-tests.lo: $(srcdir)/string-tests.c $(OBJDEPS)
+socket.lo: $(srcdir)/socket.c $(OBJDEPS)
+server.lo: $(srcdir)/server.c $(OBJDEPS)
+request.lo: $(srcdir)/request.c $(OBJDEPS)
+regress.lo: $(srcdir)/regress.c $(OBJDEPS)
+compress.lo: $(srcdir)/compress.c $(OBJDEPS)
+acl.lo: $(srcdir)/acl.c $(OBJDEPS)
+utils.lo: $(srcdir)/utils.c $(OBJDEPS)
+stubs.lo: $(srcdir)/stubs.c $(OBJDEPS)
+props.lo: $(srcdir)/props.c $(OBJDEPS)
+session.lo: $(srcdir)/session.c $(OBJDEPS)
+redirect.lo: $(srcdir)/redirect.c $(OBJDEPS)
+basic.lo: $(srcdir)/basic.c $(OBJDEPS)
+ssl.lo: $(srcdir)/ssl.c $(OBJDEPS)
+
+auth: auth.lo $(DEPS)
+uri-tests: uri-tests.lo $(DEPS)
+util-tests: util-tests.lo $(DEPS)
+string-tests: string-tests.lo $(DEPS)
+socket: socket.lo $(DEPS)
+server: server.lo $(DEPS)
+request: request.lo $(DEPS)
+regress: regress.lo $(DEPS)
+compress: compress.lo $(DEPS)
+acl: acl.lo $(DEPS)
+utils: utils.lo $(DEPS)
+stubs: stubs.lo $(DEPS)
+props: props.lo $(DEPS)
+session: session.lo $(DEPS)
+redirect: redirect.lo $(DEPS)
+basic: basic.lo $(DEPS)
+ssl: ssl.lo $(DEPS)
+xml: xml.lo $(DEPS)
+lock: lock.lo $(DEPS)
diff --git a/test/common/.cvsignore b/test/common/.cvsignore
new file mode 100644
index 0000000..c8b522d
--- /dev/null
+++ b/test/common/.cvsignore
@@ -0,0 +1 @@
+*.lo
diff --git a/test/common/ChangeLog b/test/common/ChangeLog
index 11d9840..25d103f 100644
--- a/test/common/ChangeLog
+++ b/test/common/ChangeLog
@@ -1,3 +1,13 @@
+Fri Jul 25 12:13:59 2003 Joe Orton <joe@manyfish.co.uk>
+
+ Add support for test type which is expected to fail
+ memory leak checks.
+
+ * tests.h (T_XLEAKY, T_EXPECT_LEAKS): New defines.
+
+ * test.c (main) [NEON_MEMLEAK]: If T_EXPECT_LEAKS is set, fail if
+ the test did not leak memory.
+
Wed Jun 18 20:10:45 2003 Joe Orton <joe@manyfish.co.uk>
* child.c (server_child, spawn_server_repeat): Adapt for new
diff --git a/test/common/tests.c b/test/common/tests.c
index 2ff6b5f..83f0c52 100644
--- a/test/common/tests.c
+++ b/test/common/tests.c
@@ -219,8 +219,13 @@ int main(int argc, char *argv[])
ne_alloc_used > allocated) {
t_context("memory leak of %" NE_FMT_SIZE_T " bytes",
ne_alloc_used - allocated);
+ fprintf(debug, "Blocks leaked: ");
ne_alloc_dump(debug);
result = FAIL;
+ } else if (tests[n].flags & T_EXPECT_LEAKS && result == OK &&
+ ne_alloc_used == allocated) {
+ t_context("expected memory leak not detected");
+ result = FAIL;
}
#endif
diff --git a/test/common/tests.h b/test/common/tests.h
index 72e8275..2e4e31a 100644
--- a/test/common/tests.h
+++ b/test/common/tests.h
@@ -49,6 +49,7 @@ typedef struct {
/* possible values for flags: */
#define T_CHECK_LEAKS (1) /* check for memory leaks */
#define T_EXPECT_FAIL (2) /* expect failure */
+#define T_EXPECT_LEAKS (4) /* expect memory leak failures */
/* array of tests to run: must be defined by each test suite. */
extern ne_test tests[];
@@ -60,6 +61,8 @@ extern ne_test tests[];
#define T_XFAIL(fn) { fn, #fn, T_EXPECT_FAIL | T_CHECK_LEAKS }
/* define a test function which isn't checked for memory leaks. */
#define T_LEAKY(fn) { fn, #fn, 0 }
+/* define a test function which is expected to fail memory leak checks */
+#define T_XLEAKY(fn) { fn, #fn, T_EXPECT_LEAKS }
/* current test number */
extern int test_num;
diff --git a/test/compress.c b/test/compress.c
index 720ebe0..6bab4ce 100644
--- a/test/compress.c
+++ b/test/compress.c
@@ -122,9 +122,12 @@ static int do_fetch(const char *realfn, const char *gzipfn,
CALL(await_server());
- ONN("inflated response compare", failed);
- if (!expect_fail)
+ if (!expect_fail) {
+ ONN("inflated response compare", failed);
+ /* reader will have set body.len == 0 if the whole body
+ * has been compared. */
ONN("inflated response truncated", body.len != 0);
+ }
return OK;
}
@@ -198,6 +201,16 @@ static int fail_bad_csum(void)
return do_fetch(newsfn, "badcsum.gz", 0, 1);
}
+static int fail_corrupt1(void)
+{
+ return do_fetch(newsfn, "corrupt1.gz", 0, 1);
+}
+
+static int fail_corrupt2(void)
+{
+ return do_fetch(newsfn, "corrupt2.gz", 0, 1);
+}
+
ne_test tests[] = {
T_LEAKY(init),
T(not_compressed),
@@ -206,6 +219,8 @@ ne_test tests[] = {
T(fail_trailing),
T(fail_bad_csum),
T(fail_truncate),
+ T(fail_corrupt1),
+ T(fail_corrupt2),
T(chunked_1b),
T(chunked_1b_wn),
T(chunked_12b),
diff --git a/test/lock.c b/test/lock.c
index 5fb80d4..0adf9e8 100644
--- a/test/lock.c
+++ b/test/lock.c
@@ -534,7 +534,7 @@ ne_test tests[] = {
T(lock_timeout),
T(lock_shared),
T(discover),
- T(fail_discover),
+ T_XLEAKY(fail_discover),
T(NULL)
};
diff --git a/test/run.sh b/test/run.sh
index 7d72749..0464571 100644
--- a/test/run.sh
+++ b/test/run.sh
@@ -3,14 +3,11 @@
rm -f debug.log
rm -f child.log
-# for shared builds.
-LD_LIBRARY_PATH=../src/.libs:$LD_LIBRARY_PATH
-
# enable an safety-checking malloc in glibc which will abort() if
# heap corruption is detected.
MALLOC_CHECK_=2
-export LD_LIBRARY_PATH MALLOC_CHECK_
+export MALLOC_CHECK_
for f in $*; do
if ${HARNESS} ./$f ${SRCDIR}; then
diff --git a/test/string-tests.c b/test/string-tests.c
index 93c8508..2ed7c53 100644
--- a/test/string-tests.c
+++ b/test/string-tests.c
@@ -389,7 +389,7 @@ static int b64_check(const unsigned char *raw, size_t len,
ONV(memcmp(raw, decoded, dlen),
("decoded `%s' as `%.*s' not `%.*s'",
- expected, dlen, decoded, dlen, raw));
+ expected, dlen, decoded, (int)dlen, raw));
ne_free(decoded);
ne_free(encoded);