diff options
author | joe <joe@61a7d7f5-40b7-0310-9c16-bb0ea8cb1845> | 2004-10-02 18:47:02 +0000 |
---|---|---|
committer | joe <joe@61a7d7f5-40b7-0310-9c16-bb0ea8cb1845> | 2004-10-02 18:47:02 +0000 |
commit | 0294ff3d3282d1b1c5497f00ea25e5e55e6f4338 (patch) | |
tree | 978af6f81c7b7715597871b1e89a9ad083907f1a /doc | |
download | neon-0294ff3d3282d1b1c5497f00ea25e5e55e6f4338.tar.gz |
Import neon 0.24.0 to begin 0.24.x branch.
git-svn-id: http://svn.webdav.org/repos/projects/neon/branches/0.24.x@243 61a7d7f5-40b7-0310-9c16-bb0ea8cb1845
Diffstat (limited to 'doc')
40 files changed, 4299 insertions, 0 deletions
diff --git a/doc/.cvsignore b/doc/.cvsignore new file mode 100644 index 0000000..30791a1 --- /dev/null +++ b/doc/.cvsignore @@ -0,0 +1,13 @@ +*.? +*.html +*.pdf +*.ps +*.tex +*.sgml +*.junk +html +man +man3 +man1 +version.xml +date.xml diff --git a/doc/TODO b/doc/TODO new file mode 100644 index 0000000..febed30 --- /dev/null +++ b/doc/TODO @@ -0,0 +1,156 @@ +/* List of interfaces needing reference documentation. -*- c -*- */ + +/* ne_session.h */ + +### DONE: basics +ne_session *ne_session_create(const char *scheme, const char *hostname, int port); +void ne_session_destroy(ne_session *sess); +void ne_close_connection(ne_session *sess); +void ne_session_proxy(ne_session *sess, const char *hostname, int port); + +### DONE: error handling +void ne_set_error(ne_session *sess, const char *format, ...); +const char *ne_get_error(ne_session *sess); + +### DONE: options +void ne_set_useragent(ne_session *sess, const char *product); +void ne_set_expect100(ne_session *sess, int use_expect100); +void ne_set_persist(ne_session *sess, int persist); +void ne_set_read_timeout(ne_session *sess, int timeout); + +### TODO: progress + status callbcacks +void ne_set_progress(ne_session *sess, ne_progress progress, void *userdata); + +### TODO: status callback +typedef enum ne_conn_status; +typedef void (*ne_notify_status)(void *userdata, ne_conn_status status, const char *info); +void ne_set_status(ne_session *sess, ne_notify_status status, void *userdata); + +### DONE: SSL verification + +typedef struct ne_ssl_dname; +char *ne_ssl_readable_dname(const ne_ssl_dname *dn); +typedef struct ne_ssl_certificate; +#define NE_SSL_* +typedef int (*ne_ssl_verify_fn)(void *userdata, int failures, + const ne_ssl_certificate *cert); +void ne_ssl_set_verify(ne_session *sess, ne_ssl_verify_fn fn, void *userdata); + +### DONE: SSL server certs +int ne_ssl_load_ca(ne_session *sess, const char *file); +int ne_ssl_load_default_ca(ne_session *sess); + +### TODO: SSL client certs +typedef int (*ne_ssl_keypw_fn)(void *userdata, char *pwbuf, size_t len); +void ne_ssl_keypw_prompt(ne_session *sess, ne_ssl_keypw_fn fn, void *ud); +int ne_ssl_load_pkcs12(ne_session *sess, const char *fn); +int ne_ssl_load_pem(ne_session *sess, const char *certfn, const char *keyfn); +typedef void (*ne_ssl_provide_fn)(void *userdata, ne_session *sess, + const ne_ssl_dname *server); +void ne_ssl_provide_ccert(ne_session *sess, ne_ssl_provide_fn fn, void *userdata); + +#ifdef NEON_SSL +SSL_CTX *ne_ssl_get_context(ne_session *sess); +X509 *ne_ssl_server_cert(ne_session *req); +#endif + +### TODO: utility functions +int ne_version_pre_http11(ne_session *sess); +const char *ne_get_server_hostport(ne_session *sess); +const char *ne_get_scheme(ne_session *sess); +void ne_fill_server_uri(ne_session *sess, ne_uri *uri); + +/* end of ne_session.h *****************************************/ + +/* ne_request.h */ + +### DONE: request basics +ne_request *ne_request_create(ne_session *sess, const char *method, const char *path); +int ne_request_dispatch(ne_request *req); +void ne_request_destroy(ne_request *req); + +### DONE: request status +const ne_status *ne_get_status(ne_request *req); + +### TODO: request bodies +void ne_set_request_body_buffer(ne_request *req, const char *buf, size_t count); +int ne_set_request_body_fd(ne_request *req, int fd, size_t count); + +typedef ssize_t (*ne_provide_body)(void *userdata, + char *buffer, size_t buflen); +void ne_set_request_body_provider(ne_request *req, size_t size, + ne_provide_body provider, void *userdata); + +### TODO: response bodies +typedef int (*ne_accept_response)(void *userdata, ne_request *req, ne_status *st); +int ne_accept_2xx(void *userdata, ne_request *req, ne_status *st); +int ne_accept_always(void *userdata, ne_request *req, ne_status *st); +void ne_add_response_body_reader(ne_request *req, ne_accept_response accpt, + ne_block_reader reader, void *userdata); + +### TODO: response headers +typedef void (*ne_header_handler)(void *userdata, const char *value); +void ne_add_response_header_handler(ne_request *req, const char *name, + ne_header_handler hdl, void *userdata); +void ne_add_response_header_catcher(ne_request *req, + ne_header_handler hdl, void *userdata); + +void ne_duplicate_header(void *userdata, const char *value); +void ne_handle_numeric_header(void *userdata, const char *value); + +### DONE: request headers +void ne_add_request_header(ne_request *req, const char *name, const char *value); +void ne_print_request_header(ne_request *req, const char *name, const char *format, ...); + +### TODO: misc +ne_session *ne_get_session(ne_request *req); + +### TODO: caller-pulls request interface +int ne_begin_request(ne_request *req); +int ne_end_request(ne_request *req); +ssize_t ne_read_response_block(ne_request *req, char *buffer, size_t buflen); + +### TODO: hooks +typedef void (*ne_free_hooks)(void *cookie); +typedef void (*ne_create_request_fn)(void *userdata, ne_request *req, + const char *method, const char *path); +void ne_hook_create_request(ne_session *sess, ne_create_request_fn fn, void *userdata); + +typedef void (*ne_pre_send_fn)(void *userdata, ne_buffer *header); +void ne_hook_pre_send(ne_session *sess, ne_pre_send_fn fn, void *userdata); + +typedef int (*ne_post_send_fn)(void *userdata, const ne_status *status); +void ne_hook_post_send(ne_session *sess, ne_post_send_fn fn, void *userdata); + +typedef void (*ne_destroy_fn)(void *userdata); +void ne_hook_destroy_request(ne_session *sess, ne_destroy_fn fn, void *userdata); + +void ne_hook_destroy_session(ne_session *sess, ne_destroy_fn fn, void *userdata); + +typedef void *(*ne_accessor_fn)(void *userdata); +void ne_hook_session_accessor(ne_session *sess, const char *id, ne_accessor_fn, void *userdata); +void ne_hook_request_accessor(ne_request *req, const char *id, ne_accessor_fn, void *userdata); + +void *ne_null_accessor(void *userdata); + +void *ne_session_hook_private(ne_session *sess, const char *id); + +void *ne_request_hook_private(ne_request *req, const char *id); + +/* ne_207.h */ +/* ne_acl.h */ +/* DONE: ne_alloc.h */ +/* DONE: ne_auth.h */ +/* ne_basic.h */ +/* ne_compress.h */ +/* ne_cookies.h */ +/* ne_dates.h */ +/* ne_locks.h */ +/* ne_props.h */ +/* ne_redirect.h */ +/* ne_socket.h */ +/* MOSTLY DONE: ne_string.h */ +/* ne_uri.h */ +/* ne_utils.h */ +/* ne_xml.h */ + diff --git a/doc/fdl.sgml b/doc/fdl.sgml new file mode 100644 index 0000000..37470db --- /dev/null +++ b/doc/fdl.sgml @@ -0,0 +1,466 @@ +<appendix id="gfdl"> +<title>GNU Free Documentation License</title> +<!-- - GNU Project - Free Software Foundation (FSF) --> +<!-- LINK REV="made" HREF="mailto:webmasters@gnu.org" --> + + + <!-- sect1> + <title>GNU Free Documentation License</title --> + + <para>Version 1.1, March 2000</para> + + <blockquote> + <para>Copyright (C) 2000 Free Software Foundation, Inc. +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed.</para> + </blockquote> + + <sect1 label="0"> + <title>PREAMBLE</title> + + <para>The purpose of this License is to make a manual, textbook, + or other written document "free" in the sense of freedom: to + assure everyone the effective freedom to copy and redistribute it, + with or without modifying it, either commercially or + noncommercially. Secondarily, this License preserves for the + author and publisher a way to get credit for their work, while not + being considered responsible for modifications made by + others.</para> + + <para>This License is a kind of "copyleft", which means that + derivative works of the document must themselves be free in the + same sense. It complements the GNU General Public License, which + is a copyleft license designed for free software.</para> + + <para>We have designed this License in order to use it for manuals + for free software, because free software needs free documentation: + a free program should come with manuals providing the same + freedoms that the software does. But this License is not limited + to software manuals; it can be used for any textual work, + regardless of subject matter or whether it is published as a + printed book. We recommend this License principally for works + whose purpose is instruction or reference.</para> + </sect1> + + <sect1 label="1"> + <title>APPLICABILITY AND DEFINITIONS</title> + + <para>This License applies to any manual or other work that + contains a notice placed by the copyright holder saying it can be + distributed under the terms of this License. The "Document", + below, refers to any such manual or work. Any member of the + public is a licensee, and is addressed as "you".</para> + + <para>A "Modified Version" of the Document means any work + containing the Document or a portion of it, either copied + verbatim, or with modifications and/or translated into another + language.</para> + + <para>A "Secondary Section" is a named appendix or a front-matter + section of the Document that deals exclusively with the + relationship of the publishers or authors of the Document to the + Document's overall subject (or to related matters) and contains + nothing that could fall directly within that overall subject. + (For example, if the Document is in part a textbook of + mathematics, a Secondary Section may not explain any mathematics.) + The relationship could be a matter of historical connection with + the subject or with related matters, or of legal, commercial, + philosophical, ethical or political position regarding + them.</para> + + <para>The "Invariant Sections" are certain Secondary Sections + whose titles are designated, as being those of Invariant Sections, + in the notice that says that the Document is released under this + License.</para> + + <para>The "Cover Texts" are certain short passages of text that + are listed, as Front-Cover Texts or Back-Cover Texts, in the + notice that says that the Document is released under this + License.</para> + + <para>A "Transparent" copy of the Document means a + machine-readable copy, represented in a format whose specification + is available to the general public, whose contents can be viewed + and edited directly and straightforwardly with generic text + editors or (for images composed of pixels) generic paint programs + or (for drawings) some widely available drawing editor, and that + is suitable for input to text formatters or for automatic + translation to a variety of formats suitable for input to text + formatters. A copy made in an otherwise Transparent file format + whose markup has been designed to thwart or discourage subsequent + modification by readers is not Transparent. A copy that is not + "Transparent" is called "Opaque".</para> + + <para>Examples of suitable formats for Transparent copies include + plain ASCII without markup, Texinfo input format, LaTeX input + format, SGML or XML using a publicly available DTD, and + standard-conforming simple HTML designed for human modification. + Opaque formats include PostScript, PDF, proprietary formats that + can be read and edited only by proprietary word processors, SGML + or XML for which the DTD and/or processing tools are not generally + available, and the machine-generated HTML produced by some word + processors for output purposes only.</para> + + <para>The "Title Page" means, for a printed book, the title page + itself, plus such following pages as are needed to hold, legibly, + the material this License requires to appear in the title page. + For works in formats which do not have any title page as such, + "Title Page" means the text near the most prominent appearance of + the work's title, preceding the beginning of the body of the + text.</para> + </sect1> + + <sect1 label="2"> + <title>VERBATIM COPYING</title> + + <para>You may copy and distribute the Document in any medium, + either commercially or noncommercially, provided that this + License, the copyright notices, and the license notice saying this + License applies to the Document are reproduced in all copies, and + that you add no other conditions whatsoever to those of this + License. You may not use technical measures to obstruct or + control the reading or further copying of the copies you make or + distribute. However, you may accept compensation in exchange for + copies. If you distribute a large enough number of copies you + must also follow the conditions in section 3.</para> + + <para>You may also lend copies, under the same conditions stated + above, and you may publicly display copies.</para> + </sect1> + + <sect1 label="3"> + <title>COPYING IN QUANTITY</title> + + <para>If you publish printed copies of the Document numbering more + than 100, and the Document's license notice requires Cover Texts, + you must enclose the copies in covers that carry, clearly and + legibly, all these Cover Texts: Front-Cover Texts on the front + cover, and Back-Cover Texts on the back cover. Both covers must + also clearly and legibly identify you as the publisher of these + copies. The front cover must present the full title with all + words of the title equally prominent and visible. You may add + other material on the covers in addition. Copying with changes + limited to the covers, as long as they preserve the title of the + Document and satisfy these conditions, can be treated as verbatim + copying in other respects.</para> + + <para>If the required texts for either cover are too voluminous to + fit legibly, you should put the first ones listed (as many as fit + reasonably) on the actual cover, and continue the rest onto + adjacent pages.</para> + + <para>If you publish or distribute Opaque copies of the Document + numbering more than 100, you must either include a + machine-readable Transparent copy along with each Opaque copy, or + state in or with each Opaque copy a publicly-accessible + computer-network location containing a complete Transparent copy + of the Document, free of added material, which the general + network-using public has access to download anonymously at no + charge using public-standard network protocols. If you use the + latter option, you must take reasonably prudent steps, when you + begin distribution of Opaque copies in quantity, to ensure that + this Transparent copy will remain thus accessible at the stated + location until at least one year after the last time you + distribute an Opaque copy (directly or through your agents or + retailers) of that edition to the public.</para> + + <para>It is requested, but not required, that you contact the + authors of the Document well before redistributing any large + number of copies, to give them a chance to provide you with an + updated version of the Document.</para> + </sect1> + + <sect1 label="4"> + <title>MODIFICATIONS</title> + + <para>You may copy and distribute a Modified Version of the + Document under the conditions of sections 2 and 3 above, provided + that you release the Modified Version under precisely this + License, with the Modified Version filling the role of the + Document, thus licensing distribution and modification of the + Modified Version to whoever possesses a copy of it. In addition, + you must do these things in the Modified Version:</para> + + <orderedlist numeration="upperalpha"> + <listitem><para>Use in the Title Page + (and on the covers, if any) a title distinct from that of the + Document, and from those of previous versions (which should, if + there were any, be listed in the History section of the + Document). You may use the same title as a previous version if + the original publisher of that version gives permission.</para> + </listitem> + + <listitem><para>List on the Title Page, + as authors, one or more persons or entities responsible for + authorship of the modifications in the Modified Version, + together with at least five of the principal authors of the + Document (all of its principal authors, if it has less than + five).</para> + </listitem> + + <listitem><para>State on the Title page + the name of the publisher of the Modified Version, as the + publisher.</para> + </listitem> + + <listitem><para>Preserve all the + copyright notices of the Document.</para> + </listitem> + + <listitem><para>Add an appropriate + copyright notice for your modifications adjacent to the other + copyright notices.</para> + </listitem> + + <listitem><para>Include, immediately + after the copyright notices, a license notice giving the public + permission to use the Modified Version under the terms of this + License, in the form shown in the Addendum below.</para> + </listitem> + + <listitem><para>Preserve in that license + notice the full lists of Invariant Sections and required Cover + Texts given in the Document's license notice.</para> + </listitem> + + <listitem><para>Include an unaltered + copy of this License.</para> + </listitem> + + <listitem><para>Preserve the section + entitled "History", and its title, and add to it an item stating + at least the title, year, new authors, and publisher of the + Modified Version as given on the Title Page. If there is no + section entitled "History" in the Document, create one stating + the title, year, authors, and publisher of the Document as given + on its Title Page, then add an item describing the Modified + Version as stated in the previous sentence.</para> + </listitem> + + <listitem><para>Preserve the network + location, if any, given in the Document for public access to a + Transparent copy of the Document, and likewise the network + locations given in the Document for previous versions it was + based on. These may be placed in the "History" section. You + may omit a network location for a work that was published at + least four years before the Document itself, or if the original + publisher of the version it refers to gives permission.</para> + </listitem> + + <listitem><para>In any section entitled + "Acknowledgements" or "Dedications", preserve the section's + title, and preserve in the section all the substance and tone of + each of the contributor acknowledgements and/or dedications + given therein.</para> + </listitem> + + <listitem><para>Preserve all the + Invariant Sections of the Document, unaltered in their text and + in their titles. Section numbers or the equivalent are not + considered part of the section titles.</para> + </listitem> + + <listitem><para>Delete any section + entitled "Endorsements". Such a section may not be included in + the Modified Version.</para> + </listitem> + + <listitem><para>Do not retitle any + existing section as "Endorsements" or to conflict in title with + any Invariant Section.</para> + </listitem> + </orderedlist> + + <para>If the Modified Version includes new front-matter sections + or appendices that qualify as Secondary Sections and contain no + material copied from the Document, you may at your option + designate some or all of these sections as invariant. To do this, + add their titles to the list of Invariant Sections in the Modified + Version's license notice. These titles must be distinct from any + other section titles.</para> + + <para>You may add a section entitled "Endorsements", provided it + contains nothing but endorsements of your Modified Version by + various parties--for example, statements of peer review or that + the text has been approved by an organization as the authoritative + definition of a standard.</para> + + <para>You may add a passage of up to five words as a Front-Cover + Text, and a passage of up to 25 words as a Back-Cover Text, to the + end of the list of Cover Texts in the Modified Version. Only one + passage of Front-Cover Text and one of Back-Cover Text may be + added by (or through arrangements made by) any one entity. If the + Document already includes a cover text for the same cover, + previously added by you or by arrangement made by the same entity + you are acting on behalf of, you may not add another; but you may + replace the old one, on explicit permission from the previous + publisher that added the old one.</para> + + <para>The author(s) and publisher(s) of the Document do not by + this License give permission to use their names for publicity for + or to assert or imply endorsement of any Modified Version.</para> + </sect1> + + <sect1 label="5"> + <title>COMBINING DOCUMENTS</title> + + <para>You may combine the Document with other documents released + under this License, under the terms defined in section 4 above for + modified versions, provided that you include in the combination + all of the Invariant Sections of all of the original documents, + unmodified, and list them all as Invariant Sections of your + combined work in its license notice.</para> + + <para>The combined work need only contain one copy of this + License, and multiple identical Invariant Sections may be replaced + with a single copy. If there are multiple Invariant Sections with + the same name but different contents, make the title of each such + section unique by adding at the end of it, in parentheses, the + name of the original author or publisher of that section if known, + or else a unique number. Make the same adjustment to the section + titles in the list of Invariant Sections in the license notice of + the combined work.</para> + + <para>In the combination, you must combine any sections entitled + "History" in the various original documents, forming one section + entitled "History"; likewise combine any sections entitled + "Acknowledgements", and any sections entitled "Dedications". You + must delete all sections entitled "Endorsements."</para> + </sect1> + + <sect1 label="6"> + <title>COLLECTIONS OF DOCUMENTS</title> + + <para>You may make a collection consisting of the Document and + other documents released under this License, and replace the + individual copies of this License in the various documents with a + single copy that is included in the collection, provided that you + follow the rules of this License for verbatim copying of each of + the documents in all other respects.</para> + + <para>You may extract a single document from such a collection, + and distribute it individually under this License, provided you + insert a copy of this License into the extracted document, and + follow this License in all other respects regarding verbatim + copying of that document.</para> + </sect1> + + <sect1 label="7"> + <title>AGGREGATION WITH INDEPENDENT WORKS</title> + + <para>A compilation of the Document or its derivatives with other + separate and independent documents or works, in or on a volume of + a storage or distribution medium, does not as a whole count as a + Modified Version of the Document, provided no compilation + copyright is claimed for the compilation. Such a compilation is + called an "aggregate", and this License does not apply to the + other self-contained works thus compiled with the Document, on + account of their being thus compiled, if they are not themselves + derivative works of the Document.</para> + + <para>If the Cover Text requirement of section 3 is applicable to + these copies of the Document, then if the Document is less than + one quarter of the entire aggregate, the Document's Cover Texts + may be placed on covers that surround only the Document within the + aggregate. Otherwise they must appear on covers around the whole + aggregate.</para> + </sect1> + + <sect1 label="8"> + <title>TRANSLATION</title> + + <para>Translation is considered a kind of modification, so you may + distribute translations of the Document under the terms of section + 4. Replacing Invariant Sections with translations requires + special permission from their copyright holders, but you may + include translations of some or all Invariant Sections in addition + to the original versions of these Invariant Sections. You may + include a translation of this License provided that you also + include the original English version of this License. In case of + a disagreement between the translation and the original English + version of this License, the original English version will + prevail.</para> + </sect1> + + <sect1 label="9"> + <title>TERMINATION</title> + + <para>You may not copy, modify, sublicense, or distribute the + Document except as expressly provided for under this License. Any + other attempt to copy, modify, sublicense or distribute the + Document is void, and will automatically terminate your rights + under this License. However, parties who have received copies, or + rights, from you under this License will not have their licenses + terminated so long as such parties remain in full + compliance.</para> + </sect1> + + <sect1 label="10"> + <title>FUTURE REVISIONS OF THIS LICENSE</title> + + <para>The Free Software Foundation may publish new, revised + versions of the GNU Free Documentation License from time to time. + Such new versions will be similar in spirit to the present + version, but may differ in detail to address new problems or + concerns. See <ulink + url="http://www.gnu.org/copyleft/">http://www.gnu.org/copyleft/</ulink>.</para> + + <para>Each version of the License is given a distinguishing + version number. If the Document specifies that a particular + numbered version of this License "or any later version" applies to + it, you have the option of following the terms and conditions + either of that specified version or of any later version that has + been published (not as a draft) by the Free Software Foundation. + If the Document does not specify a version number of this License, + you may choose any version ever published (not as a draft) by the + Free Software Foundation.</para> + </sect1> + + <sect1 label=""> + <title>How to use this License for your documents</title> + + <para>To use this License in a document you have written, include + a copy of the License in the document and put the following + copyright and license notices just after the title page:</para> + +<blockquote><para> + Copyright (c) YEAR YOUR NAME. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.1 + or any later version published by the Free Software Foundation; + with the Invariant Sections being LIST THEIR TITLES, with the + Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. + A copy of the license is included in the section entitled "GNU + Free Documentation License". +</para></blockquote> + + <para>If you have no Invariant Sections, write "with no Invariant + Sections" instead of saying which ones are invariant. If you have + no Front-Cover Texts, write "no Front-Cover Texts" instead of + "Front-Cover Texts being LIST"; likewise for Back-Cover + Texts.</para> + + <para>If your document contains nontrivial examples of program + code, we recommend releasing these examples in parallel under your + choice of free software license, such as the GNU General Public + License, to permit their use in free software.</para> + </sect1> + +</appendix> +<!-- Keep this comment at the end of the file +Local variables: +mode: sgml +sgml-omittag:nil +sgml-shorttag:t +sgml-minimize-attributes:nil +sgml-always-quote-attributes:t +sgml-indent-step:2 +sgml-parent-document: ("referenz.sgml" "appendix") +sgml-exposed-tags:nil +sgml-local-ecat-files:nil +sgml-local-catalogs: CATALOG +sgml-validate-command: "nsgmls -s referenz.sgml" +ispell-skip-sgml: t +End: +--> diff --git a/doc/feat.xml b/doc/feat.xml new file mode 100644 index 0000000..547ab9f --- /dev/null +++ b/doc/feat.xml @@ -0,0 +1,78 @@ + <sect1 id="features"> + <title>Feature list</title> + + <para>The major features of the neon library are as follows:</para> + + <itemizedlist> + + <listitem><para>A high-level interface to common HTTP and WebDAV +methods. This allows you to easily dispatch a GET or a MKCOL request +against a resource with a single function call.</para></listitem> + + <listitem><para>A low-level interface for HTTP request +handling; allowing you to implement requests using arbitrary methods +and request headers, capture arbitrary response headers, and so +on.</para></listitem> + + <listitem><para>Persistent connection support; neon groups a +set of requests to a server into a "session"; requests within that +session can use a persistent (also known as "keep-alive") +connection.</para></listitem> + + <listitem><para>Modern HTTP authentication support: a complete +implementation of the new authentication standard, RFC2617, +supporting the Digest (MD5) and Basic schemes, including integrity +checking. Credentials are supplied by an application-defined +callback.</para></listitem> + + <listitem><para>Proxy server support; a session can be set to +use a proxy server. Authentication is supported for the Proxy as well +as the origin server.</para></listitem> + + <listitem><para>Complete SSL support; a simple interface for +enabling SSL, hiding the complexity of using an SSL library directly. +Client certificate support, callback-based server certificate +verification, along with functions to load trusted CA +certificates.</para></listitem> + +<!-- + <listitem><para>Compression support.</para></listitem> +--> + + <listitem><para>Generic XML parsing interface for handling XML +response bodies using SAX-like callbacks. Both the expat and libxml +XML parser libraries are supported.</para></listitem> + + <listitem><para>WebDAV metadata support; set and remove +properties, query properties (PROPFIND); simple interface for +retrieving "flat" byte-string properties, more advanced support for +parsing "complex" XML structured properties.</para></listitem> + +<!-- + <listitem><para>WebDAV locking support</para></listitem> +--> + + <listitem><para>Build environment support: the neon source +tree is designed so that it can be embedded in your application's +build tree; autoconf macros are supplied for integration. To get +started quickly a <xref linkend="refconfig"/> script is included, +to easily determine how to compile and link against an installed copy +of neon</para></listitem> + + <listitem><para>Complete test suite: the neon test suite +comprises half as many lines of source code as the library itself, +including many tests for protocol compliance in network behaviour, and +that the library implementation meets the guarantees made by the +API.</para> </listitem> + +<!-- + + <listitem><para>Thorough documentation: neon documentation is +provided in HTML and man page formats (from a single DocBook XML +source)</para></listitem> + +--> + + </itemizedlist> + + </sect1> diff --git a/doc/html.xsl b/doc/html.xsl new file mode 100644 index 0000000..a96867d --- /dev/null +++ b/doc/html.xsl @@ -0,0 +1,70 @@ +<?xml version='1.0'?> + +<!-- This file wraps around the DocBook HTML XSL stylesheet to customise + - some parameters; add the CSS stylesheet, etc. + --> + +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + version='1.0' + xmlns="http://www.w3.org/TR/xhtml1/transitional" + exclude-result-prefixes="#default"> + +<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/chunk.xsl"/> + +<xsl:variable name="html.stylesheet">../manual.css</xsl:variable> + +<!-- for sections with id attributes, use the id in the filename. + This produces meaningful (and persistent) URLs for the sections. --> +<xsl:variable name="use.id.as.filename" select="1"/> + +<!-- enable the shaded verbatim (programlisting etc) blocks. --> +<!-- <xsl:variable name="shade.verbatim" select="1"/> --> + +<!-- add class="programlisting" attribute on the <pre>s from + <programlisting>s so that the CSS can style them nicely. --> +<xsl:attribute-set name="shade.verbatim.style"> + <xsl:attribute name="class">programlisting</xsl:attribute> +</xsl:attribute-set> + +<!-- use sane ANSI C function prototypes --> +<xsl:variable name="funcsynopsis.style" select="'ansi'"/> + +<!-- split each sect1 into a separate chunk --> +<xsl:variable name="chunk.first.sections" select="1"/> + +<!-- don't generate table of contents within each chapter chunk. --> +<xsl:variable name="generate.chapter.toc" select="0"/> + +<xsl:variable name="generate.appendix.toc" select="0"/> + +<!-- don't include manual page numbers in refentry cross-references, they + look weird --> +<xsl:variable name="refentry.xref.manvolnum" select="0"/> + +<!-- do generate variablelist's as tables --> +<xsl:variable name="variablelist.as.table" select="1"/> + +<!-- and css'ize the tables so they can look pretty --> +<xsl:variable name="table.borders.with.css" select="1"/> + +<!-- disable ugly tabular output --> +<xsl:variable name="funcsynopsis.tabular.threshold" select="99999"/> + +<!-- change some presentation choices --> +<xsl:template match="type"> + <xsl:call-template name="inline.italicseq"/> +</xsl:template> + +<xsl:template match="parameter"> + <xsl:call-template name="inline.monoseq"/> +</xsl:template> + +<!-- enclose the whole funcprototype in <code> --> +<xsl:template match="funcprototype" mode="ansi-nontabular"> + <div class="funcprototype"><code> + <xsl:apply-templates mode="ansi-nontabular"/> + </code></div> +</xsl:template> + +</xsl:stylesheet> + diff --git a/doc/manual.css b/doc/manual.css new file mode 100644 index 0000000..621feb5 --- /dev/null +++ b/doc/manual.css @@ -0,0 +1,42 @@ + +p, pre.funcsynopsisinfo { margin-left: 0.4em; margin-right: 0.4em; } + +span.term { margin-left: 0.6em; margin-bottom: 0.0em } + +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.funcprototype { margin-top: 0.2em; margin-left: 0.4em; margin-bottom: 0.2em; } + +pre.programlisting, pre.screen { + background-color: #dddddd; + margin-left: 0.6em; margin-right: 1em; + padding: 0.3em; width: 50em; +} + +div.funcsynopsis, div.cmdsynopsis { + background-color: #dddddd; + margin-left: 0.4em; margin-right: 0.4em; + padding: 0.1em; +} + +div.warning { + border: thin solid #777777; +} + +h1.title { border-bottom: thick solid #bbf2bb; padding-bottom: 0.1em; } + +div.toc { + border-left: thick solid #bbf2bb; padding-left: 0.5em; + } + +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; } diff --git a/doc/manual.xml b/doc/manual.xml new file mode 100644 index 0000000..893f007 --- /dev/null +++ b/doc/manual.xml @@ -0,0 +1,167 @@ +<?xml version='1.0'?> <!-- -*- text -*- --> + +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" + "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [ + +<!ENTITY % isoent SYSTEM + "http://www.oasis-open.org/docbook/xml/4.2/ent/iso-num.ent"> +<!ENTITY % isopub SYSTEM + "http://www.oasis-open.org/docbook/xml/4.2/ent/iso-pub.ent"> + +%isoent; +%isopub; + +<!ENTITY fdl SYSTEM "fdl.sgml"> + +<!-- date/version stamp files created as release tarball is rolled --> +<!ENTITY date SYSTEM "date.xml"> +<!ENTITY version SYSTEM "version.xml"> + +<!ENTITY neon "neon"> + +<!-- a useful entity for writing reference examples --> +<!ENTITY egsess "ne_session *sess = ne_session_create(...);"> + +<!ENTITY null "<literal>NULL</literal>"> + +<!ENTITY nul "<literal>NUL</literal>"> + +<!-- xml.xml entities: --> +<!ENTITY startelm "<emphasis>start-element</emphasis>"> +<!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 refneon SYSTEM "ref/neon.xml"> +<!ENTITY refconfig SYSTEM "ref/config.xml"> + +<!ENTITY refsess SYSTEM "ref/sess.xml"> +<!ENTITY referr SYSTEM "ref/err.xml"> +<!ENTITY refopts SYSTEM "ref/opts.xml"> +<!ENTITY refsslvfy SYSTEM "ref/sslvfy.xml"> +<!ENTITY refsslcert SYSTEM "ref/sslcert.xml"> +<!ENTITY refssldname SYSTEM "ref/ssldname.xml"> +<!ENTITY refsslca SYSTEM "ref/sslca.xml"> +<!ENTITY refreq SYSTEM "ref/req.xml"> +<!ENTITY refreqhdr SYSTEM "ref/reqhdr.xml"> +<!ENTITY refstatus SYSTEM "ref/status.xml"> +<!ENTITY refgetst SYSTEM "ref/getst.xml"> +<!ENTITY refreqbody SYSTEM "ref/reqbody.xml"> +<!ENTITY refauth SYSTEM "ref/auth.xml"> +<!ENTITY refalloc SYSTEM "ref/alloc.xml"> +<!ENTITY refbuf SYSTEM "ref/buf.xml"> +<!ENTITY refbufcr SYSTEM "ref/bufcr.xml"> +<!ENTITY refbufapp SYSTEM "ref/bufapp.xml"> +<!ENTITY refbufdest SYSTEM "ref/bufdest.xml"> +<!ENTITY refbufutil SYSTEM "ref/bufutil.xml"> +<!ENTITY reftok SYSTEM "ref/tok.xml"> +<!ENTITY refshave SYSTEM "ref/shave.xml"> +<!ENTITY refvers SYSTEM "ref/vers.xml"> +<!ENTITY refinit SYSTEM "ref/init.xml"> +<!ENTITY refresolve SYSTEM "ref/resolve.xml"> +<!ENTITY refiaddr SYSTEM "ref/iaddr.xml"> +<!ENTITY refclicert SYSTEM "ref/clicert.xml"> + +]> + +<book> + <bookinfo> + <title>neon HTTP/WebDAV client library</title> + <author> + <firstname>Joe</firstname><surname>Orton</surname> + <affiliation> + <address><email>neon@webdav.org</email></address> + </affiliation> + </author> + <copyright><year>2001-2003</year><holder>Joe Orton</holder></copyright> + + <legalnotice> + <para>Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.1 + or any later version published by the Free Software Foundation; + with no Invariant Sections, with no Front-Cover Texts, + and with no Back-Cover Texts. + A copy of the license is included in the section entitled "GNU + Free Documentation License".</para> + </legalnotice> + + </bookinfo> + + <chapter id="intro"> + <title>Introduction</title> + + <para>This chapter provides an introduction to neon, giving an +overview of the range of features offered, and some general guidelines +for using the neon API.</para> + + <para>neon aims to provide a modern, flexible, and simple API +in the C programming language for implementing HTTP and WebDAV +support. The WebDAV functionality is entirely separate from the basic +HTTP functionality; neon can be used simply as an HTTP client library, +ignoring the WebDAV support if desired.</para> + + §ion.features; + + §ion.using; + + </chapter> + + <chapter id="api"> + <title>The neon API for the C language</title> + + §ion.xml; + + </chapter> + + <reference id="ref"> + + <!-- these are used in the man page header/footers --> + <referenceinfo> + <title>neon API reference</title> + <date>&date;</date> + <productname>neon &version;</productname> + </referenceinfo> + + <title>neon API reference</title> + + &refneon; <!-- neon --> + &refconfig; <!-- neon-config --> + + &refreqhdr; <!-- ne_add_request_header --> + &refresolve; <!-- ne_addr_resolve --> + &refbuf; <!-- ne_buffer --> + &refbufapp; <!-- ne_buffer_append --> + &refbufutil; <!-- ne_buffer_clear --> + &refbufcr; <!-- ne_buffer_create --> + &refbufdest; <!-- ne_buffer_destroy --> + &referr; <!-- ne_get_error --> + &refgetst; <!-- ne_get_status --> + &refiaddr; <!-- ne_iaddr_make --> + &refalloc; <!-- ne_malloc --> + &refreq; <!-- ne_request_create --> + &refsess; <!-- ne_session_create --> + &refopts; <!-- ne_set_useragent --> + &refreqbody; <!-- ne_set_request_body_buffer --> + &refauth; <!-- ne_set_server_auth --> + &refshave; <!-- ne_shave --> + &refinit; <!-- ne_sock_init --> + &refsslcert; <!-- ne_ssl_certificate --> + &refssldname; <!-- ne_ssl_dname --> + &refsslca; <!-- ne_ssl_load_ca --> + &refsslvfy; <!-- ne_ssl_set_verify --> + &refclicert; <!-- ne_ssl_client_cert --> + &refstatus; <!-- ne_status --> + &reftok; <!-- ne_token --> + &refvers; <!-- ne_version_match --> + + <!-- REFEND --> + <!-- ******************************************************************* --> + + </reference> + +&fdl; + +</book> diff --git a/doc/parsing-xml.txt b/doc/parsing-xml.txt new file mode 100644 index 0000000..dc3e467 --- /dev/null +++ b/doc/parsing-xml.txt @@ -0,0 +1,170 @@ + +Requirements for XML parsing in neon +------------------------------------ + +Before describing the interface given in neon for parsing XML, here +are the requirements which it must satisfy: + + 1. to support using either libxml or expat as the underlying parser + 2. to allow "independent" sections to handle parsing one XML + document + 3. to map element namespaces/names to an integer for easier + comparison. + +A description of requirement (2) is useful since it is the "hard" +requirement, and adds most of the complexity of interface: WebDAV +PROPFIND responses are made up of a large boilerplate XML + + <multistatus><response><propstat><prop>...</prop></propstat> etc. + +neon should handle the parsing of these standard elements, and expose +the meaning of the response using a convenient interface. But, within +the <prop> elements, there may also be fragments of XML: neon can +never know how to parse these, since they are property- and hence +application-specific. The simplest example of this is the +DAV:resourcetype property. + +So there is requirement (2) that two "independent" sections of code +can handle the parsing of one XML document. + +Callback-based XML parsing +-------------------------- + +There are two ways of parsing XML documents commonly used: + + 1. Build an in-memory tree of the document + 2. Use callbacks + +Where practical, using callbacks is more efficient than building a +tree, so this is what neon uses. The standard interface for +callback-based XML parsing is called SAX, so understanding the SAX +interface is useful to understanding the XML parsing interface +provided by neon. + +The SAX interface works by registering callbacks which are called *as +the XML is parsed*. The most important callbacks are for 'start +element' and 'end element'. For instance, if the XML document below is +parsed by a SAX-like interface: + + <hello> + <foobar></foobar> + </hello> + +Say we have registered callbacks "startelm" for 'start element' and +"endelm" for 'end element'. Simplified somewhat, the callbacks will +be called in this order, with these arguments: + + 1. startelm("hello") + 2. startelm("foobar") + 3. endelm("foobar") + 4. endelm("hello") + +See the expat 'xmlparse.h' header for a more complete definition of a +SAX-like interface. + +The hip_xml interface +--------------------- + +The hip_xml interface satisfies requirement (2) by introducing the +"handler" concept. A handler is made up of these things: + + - a set of XML elements + - a callback to validate an element + - a callback which is called when an element is opened + - a callback which is called when an element is closed + - (optionally, a callback which is called for CDATA) + +Registering a handler essentially says: + + "If you encounter any of this set of elements, I want these + callbacks to be called." + +Handlers are kept in a STACK inside hip_xml. The first handler +registered becomes the BASE of the stack, subsequent handlers are +PUSHed on top. + +During XML parsing, the handler which is used for an XML element is +recorded. When a new element is started, the search for a handler for +this element begins at the handler used for the parent element, and +carries on up the stack. For the root element, the search always +starts at the BASE of the stack. + +A user's guide to hip_xml +------------------------- + +The first thing to do when using hip_xml is to know what set of XML +elements you are going to be parsing. This can usually be done by +looking at the DTD provided for the documents you are going to be +parsing. The DTD is also very useful in writing the 'validate' +callback function, since it can tell you what parent/child pairs are +valid, and which aren't. + +In this example, we'll parse XML documents which look like: + +<T:list-of-things xmlns:T="http://things.org/"> + <T:a-thing>foo</T:a-thing> + <T:a-thing>bar</T:a-thing> +</T:list-of-things> + +So, given the set of elements, declare the element id's and the +element array: + +#define ELM_listofthings (HIP_ELM_UNUSED) +#define ELM_a_thing (HIP_ELM_UNUSED + 1) + +const static struct my_elms[] = { + { "http://things.org/", "list-of-things", ELM_listofthings, 0 }, + { "http://things.org/", "a-thing", ELM_a_thing, HIP_XML_CDATA }, + { NULL } +}; + +This declares we know about two elements: list-of-things, and a-thing, +and that the 'a-thing' element contains character data. + +The definition of the validation callback is very simple: + +static int validate(hip_xml_elmid parent, hip_xml_elmid child) +{ + /* Only allow 'list-of-things' as the root element. */ + if (parent == HIP_ELM_root && child == ELM_listofthings || + parent = ELM_listofthings && child == ELM_a_thing) { + return HIP_XML_VALID; + } else { + return HIP_XML_INVALID; + } +} + +For this example, we can ignore the start-element callback, and just +use the end-element callback: + +static int endelm(void *userdata, const struct hip_xml_elm *s, + const char *cdata) +{ + printf("Got a thing: %s\n", cdata); + return 0; +} + +This endelm callback just prints the cdata which was contained in the +"a-thing" element. + +Now, on to parsing. A new parser object is created for parsing each +XML document. Creating a new parser object is as simple as: + + hip_xml_parser *parser; + + parser = hip_xml_create(); + +Next register the handler, passing NULL as the start-element callback, +and also as userdata, which we don't use here. + + hip_xml_push_handler(parser, my_elms, + validate, NULL, endelm, + NULL); + +Finally, call hip_xml_parse, passing the chunks of XML document to the +hip_xml as you get them. The output should be: + + Got a thing: foo + Got a thing: bar + +for the XML document. diff --git a/doc/ref/alloc.xml b/doc/ref/alloc.xml new file mode 100644 index 0000000..cc0ac22 --- /dev/null +++ b/doc/ref/alloc.xml @@ -0,0 +1,88 @@ + <refentry id="refalloc"> + + <refmeta> + <refentrytitle>ne_malloc</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname id="ne_malloc">ne_malloc</refname> + <refname id="ne_calloc">ne_calloc</refname> + <refname id="ne_realloc">ne_realloc</refname> + <refname id="ne_strdup">ne_strdup</refname> + <refname id="ne_strndup">ne_strndup</refname> + <refname id="ne_oom_callback">ne_oom_callback</refname> + <refpurpose>memory allocation wrappers</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <funcsynopsis> + + <funcsynopsisinfo>#include <ne_alloc.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>void *<function>ne_malloc</function></funcdef> + <paramdef>size_t <parameter>size</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>void *<function>ne_calloc</function></funcdef> + <paramdef>size_t <parameter>size</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>void *<function>ne_realloc</function></funcdef> + <paramdef>void *<parameter>size</parameter></paramdef> + <paramdef>size_t <parameter>len</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>char *<function>ne_strdup</function></funcdef> + <paramdef>const char *<parameter>s</parameter></paramdef> + <paramdef>size_t <parameter>size</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>char *<function>ne_strndup</function></funcdef> + <paramdef>const char *<parameter>s</parameter></paramdef> + <paramdef>size_t <parameter>size</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>void <function>ne_oom_callback</function></funcdef> + <paramdef>void (*<parameter>callback</parameter>)(void)</paramdef> + </funcprototype> + + </funcsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para>The functions <function>ne_malloc</function>, +<function>ne_calloc</function>, <function>ne_realloc</function>, +<function>ne_strdup</function> and <function>ne_strdnup</function> +provide wrappers for the equivalent functions in the standard C +library. The wrappers provide the extra guarantee that if the C +library equivalent returns &null; when no memory is available, an +optional callback will be called, and the library will then call +<function>abort</function>().</para> + + <para><function>ne_oom_callback</function> registers a callback +which will be invoked if an out of memory error is detected.</para> + + </refsect1> + + <refsect1> + <title>Notes</title> + + <para>If the operating system uses optimistic memory +allocation, the C library memory allocation routines will not return +&null;, so it is not possible to gracefully handle memory allocation +failures.</para> + + </refsect1> + + </refentry> diff --git a/doc/ref/auth.xml b/doc/ref/auth.xml new file mode 100644 index 0000000..9b20201 --- /dev/null +++ b/doc/ref/auth.xml @@ -0,0 +1,114 @@ + <refentry id="refauth"> + + <refmeta> + <refentrytitle>ne_set_server_auth</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname id="ne_set_server_auth">ne_set_server_auth</refname> + <refname id="ne_set_proxy_auth">ne_set_proxy_auth</refname> + <refname id="ne_forget_auth">ne_forget_auth</refname> + <refpurpose>register authentication callbacks</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <funcsynopsis> + + <funcsynopsisinfo>#include <ne_auth.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>typedef int (*<function>ne_request_auth</function>)</funcdef> + <paramdef>void *<parameter>userdata</parameter></paramdef> + <paramdef>const char *<parameter>realm</parameter></paramdef> + <paramdef>int <parameter>attempt</parameter></paramdef> + <paramdef>char *<parameter>username</parameter></paramdef> + <paramdef>char *<parameter>password</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>void <function>ne_set_server_auth</function></funcdef> + <paramdef>ne_session *<parameter>session</parameter></paramdef> + <paramdef>ne_request_auth <parameter>callback</parameter></paramdef> + <paramdef>void *<parameter>userdata</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>void <function>ne_set_proxy_auth</function></funcdef> + <paramdef>ne_session *<parameter>session</parameter></paramdef> + <paramdef>ne_request_auth <parameter>callback</parameter></paramdef> + <paramdef>void *<parameter>userdata</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>void <function>ne_forget_auth</function></funcdef> + <paramdef>ne_session *<parameter>session</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para>The <type>ne_request_auth</type> function type defines a +callback which is invoked when a server or proxy server requires user +authentication for a particular request. The +<parameter>realm</parameter> string is supplied by the server. <!-- +FIXME --> The <parameter>attempt</parameter> is a counter giving the +number of times the request has been retried with different +authentication credentials. The first time the callback is invoked +for a particular request, <parameter>attempt</parameter> will be zero.</para> + + <para>To retry the request using new authentication +credentials, the callback should return zero, and the +<parameter>username</parameter> and <parameter>password</parameter> +buffers must contain &nul;-terminated strings. The +<literal>NE_ABUFSIZ</literal> constant gives the size of these +buffers.</para> + + <tip> + <para>If you only wish to allow the user one attempt to enter +credentials, use the value of the <parameter>attempt</parameter> +parameter as the return value of the callback.</para> + </tip> + + <para>To abort the request, the callback should return a +non-zero value; in which case the contents of the +<parameter>username</parameter> and <parameter>password</parameter> +buffers are ignored.</para> + + <para>The <function>ne_forget_auth</function> function can be +used to discard the cached authentication credentials.</para> + + </refsect1> + + <refsect1> + <title>Examples</title> + + <programlisting> +/* Function which prompts for a line of user input: */ +extern char *prompt_for(const char *prompt); + +static int +my_auth(void *userdata, const char *realm, int attempts, + char *username, char *password) +{ + strncpy(username, prompt_for("Username: "), NE_ABUFSIZ); + strncpy(password, prompt_for("Password: "), NE_ABUFSIZ); + return attempts; +} + +int main(...) +{ + &egsess; + + ne_set_server_auth(sess, my_auth, NULL); + + /* ... */ +}</programlisting> + </refsect1> + + </refentry> diff --git a/doc/ref/buf.xml b/doc/ref/buf.xml new file mode 100644 index 0000000..68b515c --- /dev/null +++ b/doc/ref/buf.xml @@ -0,0 +1,53 @@ + <refentry id="refbuf"> + + <refmeta> + <refentrytitle>ne_buffer</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname id="ne_buffer">ne_buffer</refname> + <refpurpose>string buffer handling</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <funcsynopsis><funcsynopsisinfo>#include <ne_string.h> + +typedef struct { + char *data; + size_t used; + size_t length; +} <type>ne_buffer</type>;</funcsynopsisinfo></funcsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para>The <type>ne_buffer</type> type represents an expandable +memory buffer for holding &nul;-terminated strings. The +<structfield>data</structfield> field points to the beginnning of the +string, the length of which is given by the +<structfield>used</structfield> field. The current size of memory +allocated is given by the <structfield>length</structfield> field. It +is not recommended that the fields of a buffer are manipulated +directly. The <structfield>data</structfield> pointer may change when +the buffer is modified.</para> + + <para>A buffer is created using <xref +linkend="ne_buffer_create"/> or <xref +linkend="ne_buffer_create_sized"/>, and destroyed using <xref +linkend="ne_buffer_destroy"/> or <xref linkend="ne_buffer_finish"/>. +The functions <xref linkend="ne_buffer_append"/>, <xref +linkend="ne_buffer_zappend"/> and <xref linkend="ne_buffer_concat"/> are +used to append data to a buffer.</para> + + <para>If the string referenced by the +<structfield>data</structfield> pointer is modified directly (rather +than using one of the functions listed above), +<function>ne_buffer_altered</function> must be called.</para> + + </refsect1> + + </refentry> diff --git a/doc/ref/bufapp.xml b/doc/ref/bufapp.xml new file mode 100644 index 0000000..a75ce81 --- /dev/null +++ b/doc/ref/bufapp.xml @@ -0,0 +1,89 @@ + <refentry id="refbufapp"> + + <refmeta> + <refentrytitle>ne_buffer_append</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname id="ne_buffer_append">ne_buffer_append</refname> + <refname id="ne_buffer_zappend">ne_buffer_zappend</refname> + <refname id="ne_buffer_concat">ne_buffer_concat</refname> + <refpurpose>append data to a string buffer</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <funcsynopsis> + + <funcsynopsisinfo>#include <ne_string.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>void <function>ne_buffer_append</function></funcdef> + <paramdef>ne_buffer *<parameter>buf</parameter></paramdef> + <paramdef>const char *<parameter>string</parameter></paramdef> + <paramdef>size_t <parameter>len</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>void <function>ne_buffer_zappend</function></funcdef> + <paramdef>ne_buffer *<parameter>buf</parameter></paramdef> + <paramdef>const char *<parameter>string</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>void <function>ne_buffer_concat</function></funcdef> + <paramdef>ne_buffer *<parameter>buf</parameter></paramdef> + <paramdef>const char *<parameter>str</parameter></paramdef> + <paramdef>...</paramdef> + </funcprototype> + + </funcsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para>The <function>ne_buffer_append</function> and +<function>ne_buffer_zappend</function> functions append a string to +the end of a buffer; extending the buffer as necessary. The +<parameter>len</parameter> passed to +<function>ne_buffer_append</function> specifies the length of the +string to append; there must be no &nul; terminator in the first +<parameter>len</parameter> bytes of the string. +<function>ne_buffer_zappend</function> must be passed a +&nul;-terminated string.</para> + + <para>The <function>ne_buffer_concat</function> function takes +a variable-length argument list following <parameter>str</parameter>; +each argument must be a <type>char *</type> pointer to a +&nul;-terminated string. A &null; pointer must be given as the last +argument to mark the end of the list. The strings (including +<parameter>str</parameter>) are appended to the buffer in the order +given. None of the strings passed to +<function>ne_buffer_concat</function> are modified.</para> + + </refsect1> + + <refsect1> + <title>Examples</title> + + <para>The following code will output "<literal>Hello, world. +And goodbye.</literal>".</para> + + <programlisting>ne_buffer *buf = ne_buffer_create(); +ne_buffer_zappend(buf, "Hello"); +ne_buffer_concat(buf, ", world. ", "And ", "goodbye.", NULL); +puts(buf->data); +ne_buffer_destroy(buf);</programlisting> + </refsect1> + + <refsect1> + <title>See also</title> + + <para><xref linkend="ne_buffer"/>, <xref linkend="ne_buffer_create"/>, +<xref linkend="ne_buffer_destroy"/></para> + </refsect1> + + </refentry> diff --git a/doc/ref/bufcr.xml b/doc/ref/bufcr.xml new file mode 100644 index 0000000..0c572a6 --- /dev/null +++ b/doc/ref/bufcr.xml @@ -0,0 +1,60 @@ + <refentry id="refbufcr"> + + <refmeta> + <refentrytitle>ne_buffer_create</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname id="ne_buffer_create">ne_buffer_create</refname> + <refname id="ne_buffer_create_sized">ne_buffer_ncreate</refname> + <refpurpose>general purpose of group of functions</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <funcsynopsis> + + <funcsynopsisinfo>#include <ne_alloc.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>ne_buffer *<function>ne_buffer_create</function></funcdef> + <void/> + </funcprototype> + + <funcprototype> + <funcdef>ne_buffer *<function>ne_buffer_ncreate</function></funcdef> + <paramdef>size_t <parameter>size</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para><function>ne_buffer_create</function> creates a new +buffer object, with an implementation-defined initial size. +<function>ne_buffer_ncreate</function> creates an +<type>ne_buffer</type> where the minimum initial size is given in the +<parameter>size</parameter> parameter. The buffer created will +contain the empty string (<literal>""</literal>).</para> + + </refsect1> + + <refsect1> + <title>Return value</title> + + <para>Both functions return a pointer to a new buffer object, +and never &null;.</para> + + </refsect1> + + <refsect1> + <title>See also</title> + + <para><xref linkend="ne_buffer"/></para> + </refsect1> + + </refentry> diff --git a/doc/ref/bufdest.xml b/doc/ref/bufdest.xml new file mode 100644 index 0000000..5dc4dfc --- /dev/null +++ b/doc/ref/bufdest.xml @@ -0,0 +1,81 @@ + <refentry id="refbufdest"> + + <refmeta> + <refentrytitle>ne_buffer_destroy</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname id="ne_buffer_destroy">ne_buffer_destroy</refname> + <refname id="ne_buffer_finish">ne_buffer_finish</refname> + <refpurpose>destroy a buffer object</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <funcsynopsis> + + <funcsynopsisinfo>#include <ne_string.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>void <function>ne_buffer_destroy</function></funcdef> + <paramdef>ne_buffer *<parameter>buf</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>char *<function>ne_buffer_finish</function></funcdef> + <paramdef>ne_buffer *<parameter>buf</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para><function>ne_buffer_destroy</function> frees all memory +associated with the buffer. <function>ne_buffer_finish</function> +frees the buffer structure, but not the actual string stored in the +buffer, which is returned and must be <function>free</function>()d by +the caller.</para> + + <para>Any use of the buffer object after calling either of these +functions gives undefined behaviour.</para> + + </refsect1> + + <refsect1> + <title>Return value</title> + + <para><function>ne_buffer_finish</function> returns the +<function>malloc</function>-allocated string stored in the buffer.</para> + + </refsect1> + + <refsect1> + <title>Examples</title> + + <para>An example use of <function>ne_buffer_finish</function>; +the <function>duplicate</function> function returns a string made up of +<parameter>n</parameter> copies of <parameter>str</parameter>:</para> + + <programlisting>static char *duplicate(int n, const char *str) +{ + ne_buffer *buf = ne_buffer_create(); + while (n--) { + ne_buffer_zappend(buf, str); + } + return ne_buffer_finish(buf); +}</programlisting> + + </refsect1> + + <refsect1> + <title>See also</title> + + <para><xref linkend="ne_buffer"/>, <xref linkend="ne_buffer_create"/>, +<xref linkend="ne_buffer_zappend"/></para> + </refsect1> + + </refentry> diff --git a/doc/ref/bufutil.xml b/doc/ref/bufutil.xml new file mode 100644 index 0000000..3f3f3c5 --- /dev/null +++ b/doc/ref/bufutil.xml @@ -0,0 +1,62 @@ + <refentry id="refbufutil"> + + <refmeta> + <refentrytitle>ne_buffer_clear</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname id="ne_buffer_clear">ne_buffer_clear</refname> + <refname id="ne_buffer_grow">ne_buffer_grow</refname> + <refname id="ne_buffer_altered">ne_buffer_altered</refname> + <refpurpose>general purpose of group of functions</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <funcsynopsis> + + <funcsynopsisinfo>#include <ne_string.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>void <function>ne_buffer_clear</function></funcdef> + <paramdef>ne_buffer *<parameter>buf</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>void <function>ne_buffer_altered</function></funcdef> + <paramdef>ne_buffer *<parameter>buf</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>void <function>ne_buffer_grow</function></funcdef> + <paramdef>ne_buffer *<parameter>buf</parameter></paramdef> + <paramdef>size_t <parameter>size</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para>The <function>ne_buffer_clear</function> function sets +the string stored in <parameter>buf</parameter> to be the empty string +(<literal>""</literal>).</para> + + <para>The <function>ne_buffer_altered</function> function must +be used after the string stored in the buffer +<parameter>buf</parameter> is modified by directly rather than using +<xref linkend="ne_buffer_append"/>, <xref linkend="ne_buffer_zappend"/> +or <xref linkend="ne_buffer_concat"/>.</para> + + <para>The <function>ne_buffer_grow</function> function +ensures that at least <parameter>size</parameter> bytes are allocated +for the string; this can be used if a large amount of data is going to +be appended to the buffer and may result in more efficient memory +allocation.</para> + + </refsect1> + + </refentry> diff --git a/doc/ref/clicert.xml b/doc/ref/clicert.xml new file mode 100644 index 0000000..47a2ce0 --- /dev/null +++ b/doc/ref/clicert.xml @@ -0,0 +1,153 @@ +<refentry id="refclicert"> + + <refmeta> + <refentrytitle>ne_ssl_client_cert</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname id="ne_ssl_clicert_read">ne_ssl_clicert_read</refname> + <refname id="ne_ssl_clicert_name">ne_ssl_clicert_name</refname> + <refname id="ne_ssl_clicert_encrypted">ne_ssl_clicert_encrypted</refname> + <refname id="ne_ssl_clicert_decrypt">ne_ssl_clicert_decrypt</refname> + <refname id="ne_ssl_clicert_owner">ne_ssl_clicert_owner</refname> + <refname id="ne_ssl_clicert_free">ne_ssl_clicert_free</refname> + <refpurpose>SSL client certificate handling</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <funcsynopsis> + + <funcsynopsisinfo>#include <ne_ssl.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>ne_ssl_client_cert *<function>ne_ssl_clicert_read</function></funcdef> + <paramdef>const char *<parameter>filename</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>const char *<function>ne_ssl_clicert_name</function></funcdef> + <paramdef>const ne_ssl_client_cert *<parameter>ccert</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>int <function>ne_ssl_clicert_encrypted</function></funcdef> + <paramdef>const ne_ssl_client_cert *<parameter>ccert</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>int <function>ne_ssl_clicert_decrypt</function></funcdef> + <paramdef>ne_ssl_client_cert *<parameter>ccert</parameter></paramdef> + <paramdef>const char *<parameter>password</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>const ne_ssl_certificate *<function>ne_ssl_clicert_owner</function></funcdef> + <paramdef>const ne_ssl_client_cert *<parameter>ccert</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>void <function>ne_ssl_clicert_free</function></funcdef> + <paramdef>ne_ssl_client_cert *<parameter>ccert</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <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 + certificate is encrypted, it must be decrypted before it is used. + An <type>ne_ssl_client_certificate</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> + + <para>A client certificate can be in one of two states: + <emphasis>encrypted</emphasis> or <emphasis>decrypted</emphasis>. + The <function>ne_ssl_clicert_encrypted</function> function will + return non-zero if the client certificate is in the + <emphasis>encrypted</emphasis> state. A client certificate object + returned by <function>ne_ssl_clicert_read</function> may be + initially in either state, depending on whether the file was + encrypted or not.</para> + + <para><function>ne_ssl_clicert_decrypt</function> can be used to + decrypt a client certificate using the appropriate password. This + function must only be called if the object is in the + <emphasis>encrypted</emphasis> state; if decryption fails, the + certificate state does not change, so decryption can be attempted + more than once using different passwords.</para> + + <para>A client certificate can be given a "friendly name" when it + is created; <function>ne_ssl_clicert_owner</function> will return + this name (or &null; if no friendly name was specified). + <function>ne_ssl_clicert_owner</function> can be used when the + client certificate is in either the encrypted or decrypted state, + and will return the same string for the lifetime of the + object.</para> + + <para>The function <function>ne_ssl_clicert_owner</function> + returns the certificate part of the client certificate; it must + only be called if the client certificate is in the + <emphasis>decrypted</emphasis> state.</para> + + <para>When the client certificate is no longer needed, the + <function>ne_ssl_clicert_free</function> function should be used + to destroy the object.</para> + + </refsect1> + + <refsect1> + <title>Return value</title> + + <para><function>ne_ssl_clicert_read</function> returns a client + certificate object, or &null; if the file could not be read. + <function>ne_ssl_clicert_encrypted</function> returns zero if the + object is in the decrypted state, or non-zero if it is in the + encrypted state. <function>ne_ssl_clicert_name</function> returns + a &nul;-terminated friendly name string, or &null;. + <function>ne_ssl_clicert_owner</function> returns a certificate + object.</para> + + </refsect1> + + <refsect1> + <title>Examples</title> + + <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; + +ccert = ne_ssl_clicert_read("/path/to/client.p12"); + +if (ccert == NULL) { + /* handle error... */ +} else if (ne_ssl_clicert_encrypted(ccert)) { + char *password = prompt_for_password(); + + if (ne_ssl_clicert_decrypt(ccert, password)) { + /* could not decrypt! handle error... */ + } +} + +ne_ssl_set_clicert(sess, ccert); +</programlisting> + + </refsect1> + + <refsect1> + <title>See also</title> + + <para><xref linkend="ne_ssl_certificate"/></para> + </refsect1> + +</refentry> + diff --git a/doc/ref/config.xml b/doc/ref/config.xml new file mode 100644 index 0000000..4823cca --- /dev/null +++ b/doc/ref/config.xml @@ -0,0 +1,124 @@ + <refentry id="refconfig"> + + <refentryinfo><title>neon</title></refentryinfo> + + <refmeta> + <refentrytitle>neon-config</refentrytitle> + <manvolnum>1</manvolnum> + </refmeta> + + <refnamediv> + <refname id="neon-config">neon-config</refname> + + <refpurpose>script providing information about installed copy + of neon library</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <cmdsynopsis> + <command>neon-config</command> + <arg choice="opt"><option>--prefix</option></arg> + <group> + <arg><option>--cflags</option></arg> + <arg><option>--libs</option></arg> + <arg><option>--la-file</option></arg> + <arg><option>--support</option> <replaceable>feature</replaceable></arg> + <arg><option>--help</option></arg> + <arg><option>--version</option></arg> + </group> + </cmdsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para>The <command>neon-config</command> script provides +information about an installed copy of the neon library. The +<option>--cflags</option> and <option>--libs</option> options instruct +how to compile and link an application against the library; the +<option>--version</option> and <option>--support</option> options can +help determine whether the library meets the applications +requirements.</para> + + </refsect1> + + <refsect1> + <title>Options</title> + + <variablelist> + + <varlistentry> + <term><option>--cflags</option></term> + <listitem><simpara>Print the flags which should be passed to +the C compiler when compiling object files, when the object files use +neon header files.</simpara></listitem> + </varlistentry> + + <varlistentry> + <term><option>--libs</option></term> + <listitem><simpara>Print the flags which should be passed to +the linker when linking an application which uses the neon +library</simpara></listitem> + </varlistentry> + + <varlistentry> + <term><option>--la-file</option></term> + <listitem><simpara>Print the location of the libtool library +script, <filename>libneon.la</filename>, which can be used to link against +&neon; by applications using libtool.</simpara></listitem> + </varlistentry> + + <varlistentry> + <term><option>--version</option></term> + <listitem><simpara>Print the version of the library</simpara></listitem> + </varlistentry> + + <varlistentry> + <term><option>--prefix</option> <replaceable>dir</replaceable></term> + <listitem><simpara>If <replaceable>dir</replaceable> is given; relocate output of +<option>--cflags</option> and <option>--libs</option> as if neon was +installed in given prefix directory. Otherwise, print the +installation prefix of the library.</simpara></listitem> + </varlistentry> + + <varlistentry> + <term><option>--support</option> <replaceable>feature</replaceable></term> + <listitem><simpara>The script exits with success if +<replaceable>feature</replaceable> is supported by the +library.</simpara></listitem> + </varlistentry> + + <varlistentry> + <term><option>--help</option></term> + <listitem><simpara>Print help message; includes list of known + features and whether they are supported or not.</simpara></listitem> + </varlistentry> + + </variablelist> + + </refsect1> + + <refsect1 id="example"> + <title>Example</title> + + <para>Below is a Makefile fragment which could be used to +build an application against an installed neon library, when the +<command>neon-config</command> script can be found in +<envar>$PATH</envar>.</para> + + <programlisting>CFLAGS = `neon-config --cflags` +LIBS = `neon-config --libs` +OBJECTS = myapp.o +TARGET = myapp + +$(TARGET): $(OBJECTS) + $(CC) $(LDFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS) + +myapp.o: myapp.c + $(CC) $(CFLAGS) -c myapp.c -o myapp.o</programlisting> + + </refsect1> + + </refentry> diff --git a/doc/ref/err.xml b/doc/ref/err.xml new file mode 100644 index 0000000..50551b5 --- /dev/null +++ b/doc/ref/err.xml @@ -0,0 +1,66 @@ + <refentry id="referr"> + + <refmeta> + <refentrytitle>ne_get_error</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname id="ne_get_error">ne_get_error</refname> + <refname id="ne_set_error">ne_set_error</refname> + <refpurpose>error handling for HTTP sessions</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <funcsynopsis> + + <funcsynopsisinfo>#include <ne_session.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>const char *<function>ne_get_error</function></funcdef> + <paramdef>ne_sesssion *<parameter>session</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>void <function>ne_set_error</function></funcdef> + <paramdef>ne_sesssion *<parameter>session</parameter></paramdef> + <paramdef>const char *<parameter>format</parameter></paramdef> + <paramdef>...</paramdef> + </funcprototype> + + </funcsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para>The session error string is used to store any +human-readable error information associated with any errors which +occur whilst using the HTTP session.</para> + + <para>The <function>ne_get_error</function> function returns the current +session error string. This string persists only until it is changed by a +subsequent operation on the session.</para> + + <para>The <function>ne_set_error</function> function can be +used to set a new session error string, using a +<function>printf</function>-style format string interface.</para> + + </refsect1> + + <refsect1> + <title>Examples</title> + <para>Retrieve the current error string:</para> + <programlisting>&egsess; +... +printf("Error was: %s\n", ne_get_error(sess));</programlisting> + + <para>Set a new error string:</para> + <programlisting>&egsess; +... +ne_set_error(sess, "Response missing header %s", "somestring");</programlisting> + </refsect1> + + </refentry> diff --git a/doc/ref/getst.xml b/doc/ref/getst.xml new file mode 100644 index 0000000..5a419c4 --- /dev/null +++ b/doc/ref/getst.xml @@ -0,0 +1,63 @@ + <refentry id="refgetst"> + + <refmeta> + <refentrytitle>ne_get_status</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname id="ne_get_status">ne_get_status</refname> + <refpurpose>retrieve HTTP response status for request</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <funcsynopsis> + + <funcsynopsisinfo>#include <ne_request.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>const ne_status *<function>ne_get_status</function></funcdef> + <paramdef>const ne_request *<parameter>request</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para>The <function>ne_get_status</function> function returns +a pointer to the HTTP status object giving the result of a request. +The object returned only becomes valid once the request has been +<emphasis>successfully</emphasis> dispatched (the return value of +<function>ne_request_dispatch</function> or +<function>ne_begin_request</function> was zero). The object remains +valid until the associated request object is destroyed.</para> + + </refsect1> + + <refsect1> + <title>See also</title> + + <para><xref linkend="ne_status"/>, <xref + linkend="ne_request_create"/></para> + + </refsect1> + + <refsect1> + <title>Example</title> + + <para>Display the response status code of applying the +<literal>HEAD</literal> method to some resource.</para> + + <programlisting>ne_request *req = ne_request_create(sess, "HEAD", "/foo/bar"); +if (ne_request_dispatch(req)) + /* handle errors... */ +else + printf("Response status code was %d\n", ne_get_status(req)->code); +ne_request_destroy(req);</programlisting> + </refsect1> + + </refentry> diff --git a/doc/ref/iaddr.xml b/doc/ref/iaddr.xml new file mode 100644 index 0000000..cf64a13 --- /dev/null +++ b/doc/ref/iaddr.xml @@ -0,0 +1,124 @@ +<refentry id="refiaddr"> + + <refmeta> + <refentrytitle>ne_iaddr_make</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <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_free">ne_iaddr_free</refname> + <refpurpose>functions to manipulate and compare network addresses</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <funcsynopsis> + + <funcsynopsisinfo>#include <ne_socket.h> + +typedef enum { + ne_iaddr_ipv4 = 0, + ne_iaddr_ipv6 +} <type>ne_iaddr_type</type>;</funcsynopsisinfo> + + <funcprototype> + <funcdef>ne_inet_addr *<function>ne_iaddr_make</function></funcdef> + <paramdef>ne_iaddr_type <parameter>type</parameter></paramdef> + <paramdef>const unsigned char *<parameter>raw</parameter></paramdef> + </funcprototype> + + <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> + </funcprototype> + + <funcprototype> + <funcdef>char *<function>ne_iaddr_print</function></funcdef> + <paramdef>const ne_inet_addr *<parameter>ia</parameter></paramdef> + <paramdef>char *<parameter>buffer</parameter></paramdef> + <paramdef>size_t <parameter>bufsiz</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>void <function>ne_iaddr_free</function></funcdef> + <paramdef>const ne_inet_addr *<parameter>addr</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para><function>ne_iaddr_make</function> creates an + <type>ne_inet_addr</type> object from a raw binary network + address; for instance the four bytes <literal>0x7f 0x00 0x00 + 0x01</literal> represent the IPv4 address + <literal>127.0.0.1</literal>. The object returned is suitable for + passing to <function>ne_sock_connect</function>. A binary IPv4 + address contains four bytes; a binary IPv6 address contains + sixteen bytes; addresses passed must be in network byte + order.</para> + + <para><function>ne_iaddr_cmp</function> can be used to compare two + network addresses; returning zero only if they are identical. The + addresses need not be of the same address type; if the addresses + are not of the same type, the return value is guaranteed to be + non-zero.</para> + + <para><function>ne_iaddr_print</function> can be used to print the + human-readable string representation of a network address into a + buffer, for instance the string + <literal>"127.0.0.1"</literal>.</para> + + <para><function>ne_iaddr_free</function> releases the memory + associated with a network address object.</para> + + </refsect1> + + <refsect1> + <title>Return value</title> + + <para><function>ne_iaddr_make</function> returns &null; if the + address type passed is not supported (for instance on a platform + which does not support IPv6).</para> + + + <para><function>ne_iaddr_print</function> returns the + <parameter>buffer</parameter> pointer, and never &null;.</para> + + </refsect1> + + <refsect1> + <title>Examples</title> + + <para>The following example connects a socket to port 80 at the + address <literal>127.0.0.1</literal>.</para> + + <programlisting>unsigned char addr[] = "\0x7f\0x00\0x00\0x01"; +ne_inet_addr *ia; + +ia = ne_iaddr_make(ne_iaddr_ipv4, addr); +if (ia != NULL) { + ne_socket *sock = ne_sock_connect(ia, 80); + ne_iaddr_free(ia); + /* ... */ +} else { + /* ... */ +}</programlisting> + + </refsect1> + + <refsect1> + <title>See also</title> + + <para><xref linkend="ne_addr_resolve"/></para> + </refsect1> + +</refentry> + diff --git a/doc/ref/init.xml b/doc/ref/init.xml new file mode 100644 index 0000000..32dcda5 --- /dev/null +++ b/doc/ref/init.xml @@ -0,0 +1,55 @@ +<refentry id="refsockinit"> + + <refmeta> + <refentrytitle>ne_sock_init</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname id="ne_sock_init">ne_sock_init</refname> + <refpurpose>perform library initialization</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <funcsynopsis> + + <funcsynopsisinfo>#include <ne_socket.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>int <function>ne_sock_init</function></funcdef> + <void/> + </funcprototype> + + </funcsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para>In some platforms and configurations, &neon; may be using + some socket or SSL libraries which require global initialization + before use. To perform this initialization, the + <function>ne_sock_init</function> function must be called once + before any other library functions are used.</para> + + </refsect1> + + <refsect1> + <title>Return value</title> + + <para><function>ne_sock_init</function> returns zero on success, + or non-zero on error. If an error occurs, no further use of the + &neon; library should be attempted.</para> + + </refsect1> + + <refsect1> + <title>See also</title> + + <para><xref linkend="refneon"/></para> + </refsect1> + +</refentry> + diff --git a/doc/ref/neon.xml b/doc/ref/neon.xml new file mode 100644 index 0000000..9857c63 --- /dev/null +++ b/doc/ref/neon.xml @@ -0,0 +1,145 @@ +<refentry id="refneon"> + + <refmeta> + <refentrytitle>neon</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname>neon</refname> + <refpurpose>HTTP and WebDAV client library</refpurpose> + </refnamediv> + + <refsect1> + <title>Description</title> + + <para>neon is an HTTP and WebDAV client library. The major + abstractions exposed are the HTTP <emphasis>session</emphasis>, + created by <xref linkend="ne_session_create"/>; and the HTTP + <emphasis>request</emphasis>, created by <xref + linkend="ne_request_create"/>. HTTP authentication is handled + transparently for server and proxy servers, see <xref + linkend="ne_set_server_auth"/>; complete SSL/TLS support is also + included, see <xref linkend="ne_ssl_set_verify"/>.</para> + + </refsect1> + + <refsect1> + <title>Conventions</title> + + <para>Some conventions are used throughout the neon API, to + provide a consistent and simple interface; these are documented + below.</para> + + <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> + </refsect2> + + <refsect2> + <title>Namespaces</title> + + <para>To avoid possible collisions between names used for symbols + and preprocessor macros by an application and the libraries it + uses, it is good practice for each library to reserve a particular + <emphasis>namespace prefix</emphasis>. An application which + ensures it uses no names with these prefixes is then guaranteed to + avoid such collisions.</para> + + <para>The &neon; library reserves the use of the namespace + prefixes <literal>ne_</literal> and <literal>NE_</literal>. The + libraries used by &neon; may also reserve certain namespaces; + collisions between these libraries and a &neon;-based application + will not be detected at compile time, since the underlying library + interfaces are not exposed through the &neon; header files. Such + collisions can only be detected at link time, when the linker + attempts to resolve symbols. The following list documents some of + the namespaces claimed by libraries used by &neon;; this list may + be incomplete.</para> + + <variablelist> + + <varlistentry> + <term>SSL, ssl, TLS, tls, ERR_, BIO_, d2i_, i2d_, ASN1_</term> + <listitem><simpara>Some of the many prefixes used by the OpenSSL + library; little attempt has been made to keep exported symbols + within any particular prefixes for this + library.</simpara></listitem> + </varlistentry> + + <varlistentry> + <term>XML_, Xml[A-Z]</term> <listitem><simpara>Namespaces + used by the expat library.</simpara></listitem> + </varlistentry> + + <varlistentry> + <term>xml[A-Z], html[A-Z], docb[A-Z]</term> + <listitem><simpara>Namespaces used by the libxml2 library; a + relatively small number of symbols are used without these + prefixes.</simpara></listitem> + </varlistentry> + + </variablelist> + + </refsect2> + + <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> + + </refsect2> + + <refsect2> + <title>URI paths, WebDAV metadata</title> + + <para>The path strings passed to any function must be + <emphasis>URI-encoded</emphasis> by the application; &neon; never + performs any URI encoding or decoding internally. WebDAV property + names and values must be valid UTF-8 encoded Unicode + strings.</para> + + </refsect2> + + <refsect2> + <title>Memory handling</title> + + <para>neon does not attempt to cope gracefully with an + out-of-memory situation; instead, by default, the + <function>abort</function> function is called to immediately + terminate the process. An application may register a custom + function which will be called before <function>abort</function> in + such a situation; see <xref linkend="ne_oom_callback"/>.</para> + + </refsect2> + + <refsect2> + <title>Callbacks and userdata</title> + + <para>Whenever a callback is registered, a + <literal>userdata</literal> pointer is also used to allow the + application to associate a context with the callback. The + userdata is of type <type>void *</type>, allowing any pointer to + be used.</para> + + </refsect2> + + </refsect1> + + <refsect1> + <title>See also</title> + + <para><xref linkend="refsess"/>, <xref linkend="ne_oom_callback"/></para> + </refsect1> + +</refentry> + diff --git a/doc/ref/opts.xml b/doc/ref/opts.xml new file mode 100644 index 0000000..fe8f368 --- /dev/null +++ b/doc/ref/opts.xml @@ -0,0 +1,126 @@ + <refentry id="refopts"> + + <refmeta> + <refentrytitle>ne_set_useragent</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname id="ne_set_useragent">ne_set_useragent</refname> + <refname id="ne_set_persist">ne_set_persist</refname> + <refname id="ne_set_read_timeout">ne_set_read_timeout</refname> + <refname id="ne_set_expect100">ne_set_expect100</refname> + <refpurpose>common settings for HTTP sessions</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <funcsynopsis> + + <funcsynopsisinfo>#include <ne_session.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>void <function>ne_set_useragent</function></funcdef> + <paramdef>ne_session *<parameter>session</parameter></paramdef> + <paramdef>const char *<parameter>product</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>void <function>ne_set_persist</function></funcdef> + <paramdef>ne_session *<parameter>session</parameter></paramdef> + <paramdef>int <parameter>flag</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>void <function>ne_set_read_timeout</function></funcdef> + <paramdef>ne_session *<parameter>session</parameter></paramdef> + <paramdef>int <parameter>timeout</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>void <function>ne_set_expect100</function></funcdef> + <paramdef>ne_session *<parameter>session</parameter></paramdef> + <paramdef>int <parameter>flag</parameter></paramdef> + </funcprototype> + +<!-- + <funcprototype> + <funcdef>const char *<function>ne_get_scheme</function></funcdef> + <paramdef>ne_sesssion *<parameter>session</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>const char *<function>ne_get_server_hostport</function></funcdef> + <paramdef>ne_sesssion *<parameter>session</parameter></paramdef> + </funcprototype> +--> + + </funcsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <!-- TODO: intro para? --> + + <para>The <literal>User-Agent</literal> request header is used +to identify the software which generated the request for statistical +or debugging purposes. neon does not send a +<literal>User-Agent</literal> header unless a call is made to the +<function>ne_set_useragent</function>. +<function>ne_set_useragent</function> must be passed a product string +conforming to RFC2616's product token grammar; of the form +<literal>"Product/Version"</literal>.</para> + + <para>By default neon will use a persistent connection +whenever possible. For specific applications, or for debugging +purposes, it is sometimes useful to disable persistent connections. +The <function>ne_set_persist</function> function will disable +persistent connections if passed a <parameter>flag</parameter> +parameter of <literal>0</literal>, and will enable them +otherwise.</para> + + <para>When neon reads from a socket, by default the read +operation will time out after 60 seconds, and the request will fail +giving an <errorcode>NE_TIMEOUT</errorcode> error. To configure this +timeout interval, call <function>ne_set_read_timeout</function> giving +the desired number of seconds as the <parameter>timeout</parameter> +parameter.</para> + + <para>An extension introduced in the HTTP/1.1 specification +was the use of the <literal>Expect: 100-continue</literal> header. +This header allows an HTTP client to be informed of the expected +response status before the request message body is sent: a useful +optimisation for situations where a large message body is to be sent. +The <function>ne_set_expect100</function> function can be used to +enable this feature by passing the <parameter>flag</parameter> +parameter as any non-zero integer.</para> + +<warning><para>Unfortunately, if this header is sent to a server which +is not fully compliant with the HTTP/1.1 specification, a deadlock +occurs resulting in a temporarily "hung" connection. neon will +recover gracefully from this situation, but only after a 15 second +timeout. It is highly recommended that this option is not enabled +unless it is known that the server in use correctly implements +<literal>Expect: 100-continue</literal> support.</para></warning> + + </refsect1> + + <refsect1> + <title>Examples</title> + <para>Set a user-agent string:</para> + <programlisting>&egsess; +ne_set_useragent(sess, "MyApplication/2.1");</programlisting> + + <para>Disable use of persistent connections:</para> + <programlisting>ne_session *sess = ne_session_create(...); +ne_set_persist(sess, 0);</programlisting> + + <para>Set a 30 second read timeout:</para> + <programlisting>&egsess; +ne_set_read_timeout(sess, 30);</programlisting> + + </refsect1> + + </refentry> diff --git a/doc/ref/req.xml b/doc/ref/req.xml new file mode 100644 index 0000000..7c36d5c --- /dev/null +++ b/doc/ref/req.xml @@ -0,0 +1,169 @@ + <refentry id="refreq"> + + <refmeta> + <refentrytitle>ne_request_create</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname id="ne_request_create">ne_request_create</refname> + <refname id="ne_request_dispatch">ne_request_dispatch</refname> + <refname id="ne_request_destroy">ne_request_destroy</refname> + <refpurpose>low-level HTTP request handling</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <funcsynopsis> + + <funcsynopsisinfo>#include <ne_request.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>ne_request *<function>ne_request_create</function></funcdef> + <paramdef>ne_session *<parameter>session</parameter></paramdef> + <paramdef>const char *<parameter>method</parameter></paramdef> + <paramdef>const char *<parameter>path</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>int <function>ne_request_dispatch</function></funcdef> + <paramdef>ne_request *<parameter>req</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>void <function>ne_request_destroy</function></funcdef> + <paramdef>ne_request *<parameter>req</parameter></paramdef> + </funcprototype> + </funcsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para>An HTTP request, represented by the +<type>ne_request</type> type, specifies that some operation is to be +performed on some resource. The +<function>ne_request_create</function> function creates a request +object, specifying the operation in the <parameter>method</parameter> +parameter. The location of the resource is determined by the server in +use for the session given by the <parameter>sess</parameter> +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 +comes from an untrusted source, failure to perform URI-escaping +results in a security vulnerability.</para> + + <para>To dispatch a request, and process the response, the +<function>ne_request_dispatch</function> function can be used. An +alternative is to use the (more complex, but more flexible) +combination of the <function>ne_begin_request</function>, +<function>ne_end_request</function>, and +<function>ne_read_response_block</function> functions; see +<function>ne_begin_request</function>.</para> + + <para>To add extra headers in the request, the functions <xref +linkend="ne_add_request_header"/> and <xref +linkend="ne_print_request_header"/> can be used. To include a message +body with the request, one of the functions +<function>ne_set_request_body_buffer</function>, <xref +linkend="ne_set_request_body_fd"/>, or +<function>ne_set_request_body_provider</function> can be used.</para> + + <para>The return value of +<function>ne_request_dispatch</function> indicates merely whether the +request was sent and the response read successfully. To discover the +result of the operation, <xref linkend="ne_get_status"/>, along with +any processing of the response headers and message body.</para> + + <para>A request can only be dispatched once: calling +<function>ne_request_dispatch</function> more than once on a single +<type>ne_request</type> object produces undefined behaviour. Once all +processing associated with the request object is complete, use the +<function>ne_request_destroy</function> function to destroy the +resources associated with it. Any subsequent use of the request +object produces undefined behaviour.</para> + + </refsect1> + + <refsect1> + <title>Return value</title> + + <para>The <function>ne_request_create</function> function +returns a pointer to a request object (and never &null;).</para> + + <para>The <function>ne_request_dispatch</function> function +returns zero if the request was dispatched successfully, and a +non-zero error code otherwise.</para> + + </refsect1> + +<!-- TODO: abs_path description in a NOTES section --> + + <refsect1> + <title>Errors</title> + + <variablelist> + <varlistentry><term><errorcode>NE_ERROR</errorcode></term> + <listitem> + <simpara>Request failed (see session error string)</simpara> + </listitem> + </varlistentry> + <varlistentry><term><errorcode>NE_LOOKUP</errorcode></term> + <listitem> + <simpara>The DNS lookup for the server (or proxy server) failed.</simpara> + </listitem> + </varlistentry> + <varlistentry><term><errorcode>NE_AUTH</errorcode></term> + <listitem> + <simpara>Authentication failed on the server.</simpara> + </listitem> + </varlistentry> + <varlistentry><term><errorcode>NE_PROXYAUTH</errorcode></term> + <listitem> + <simpara>Authentication failed on the proxy server.</simpara> + </listitem> + </varlistentry> + <varlistentry><term><errorcode>NE_CONNECT</errorcode></term> + <listitem> + <simpara>A connection to the server could not be established.</simpara> + </listitem> + </varlistentry> + <varlistentry><term><errorcode>NE_TIMEOUT</errorcode></term> + <listitem> + <simpara>A timeout occurred while waiting for the server to respond.</simpara> + </listitem> + </varlistentry> + </variablelist> + + </refsect1> + + <refsect1> + <title>Example</title> + + <para>An example of applying a <literal>MKCOL</literal> + 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); +ne_request *req = ne_request_create(sess, "MKCOL", "/foo/bar/"); +if (ne_request_dispatch(req)) { + printf("Request failed: %s\n", ne_get_error(sess)); +} +ne_request_destroy(req);</programlisting> + </refsect1> + + <refsect1> + <title>See also</title> + + <para><xref linkend="ne_get_error"/>, <xref +linkend="ne_set_error"/>, <xref linkend="ne_get_status"/>, <xref +linkend="ne_add_request_header"/>, <xref +linkend="ne_set_request_body_buffer"/>.</para> + + </refsect1> + + </refentry> diff --git a/doc/ref/reqbody.xml b/doc/ref/reqbody.xml new file mode 100644 index 0000000..e2c8eb3 --- /dev/null +++ b/doc/ref/reqbody.xml @@ -0,0 +1,69 @@ + <refentry id="refreqbody"> + + <refmeta> + <refentrytitle>ne_set_request_body_buffer</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname id="ne_set_request_body_buffer">ne_set_request_body_buffer</refname> + <refname id="ne_set_request_body_fd">ne_set_request_body_fd</refname> + <refpurpose>include a message body with a request</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <funcsynopsis> + + <funcsynopsisinfo>#include <ne_request.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>void <function>ne_set_request_body_buffer</function></funcdef> + <paramdef>ne_request *<parameter>req</parameter></paramdef> + <paramdef>const char *<parameter>buf</parameter></paramdef> + <paramdef>size_t <parameter>count</parameter></paramdef> + </funcprototype> + + <!-- this is a better interface for set_request_body_fd: + <funcprototype> + <funcdef>int <function>ne_set_request_body_fd</function></funcdef> + <paramdef>ne_request *<parameter>req</parameter></paramdef> + <paramdef>int <parameter>fd</parameter></paramdef> + <paramdef>off_t <parameter>begin</parameter></paramdef> + <paramdef>size_t <parameter>count</parameter></paramdef> + </funcprototype> + --> + + </funcsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para>The <function>ne_set_request_body_buffer</function> +function specifies that a message body should be included with the +body, which is stored in the <parameter>count</parameter> bytes buffer +<parameter>buf</parameter>.</para> + +<!-- + <para>The <function>ne_set_request_body_fd</function> function +can be used to include a message body with a request which is read +from a file descriptor. The body is read from the file descriptor +<parameter>fd</parameter>, which must be a associated with a seekable +file (not a pipe, socket, or FIFO). <parameter>count</parameter> +bytes are read, beginning at offset <parameter>begin</parameter> +(passing <parameter>begin</parameter> as zero means the body is read +from the beginning of the file).</para> + +--> + + </refsect1> + + <refsect1> + <title>See also</title> + + <para><xref linkend="ne_request_create"/></para> + </refsect1> + + </refentry> diff --git a/doc/ref/reqhdr.xml b/doc/ref/reqhdr.xml new file mode 100644 index 0000000..4d811b1 --- /dev/null +++ b/doc/ref/reqhdr.xml @@ -0,0 +1,63 @@ + <refentry id="refreqhdr"> + + <refmeta> + <refentrytitle>ne_add_request_header</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname id="ne_add_request_header">ne_add_request_header</refname> + <refname id="ne_print_request_header">ne_print_request_header</refname> + <refpurpose>add headers to a request</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <funcsynopsis> + + <funcsynopsisinfo>#include <ne_request.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>void <function>ne_add_request_header</function></funcdef> + <paramdef>ne_request *<parameter>request</parameter></paramdef> + <paramdef>const char *<parameter>name</parameter></paramdef> + <paramdef>const char *<parameter>value</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>void <function>ne_print_request_header</function></funcdef> + <paramdef>ne_request *<parameter>request</parameter></paramdef> + <paramdef>const char *<parameter>name</parameter></paramdef> + <paramdef>const char *<parameter>format</parameter></paramdef> + <paramdef>...</paramdef> + </funcprototype> + + </funcsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para>The functions <function>ne_add_request_header</function> +and <function>ne_print_request_header</function> can be used to add +headers to a request, before it is sent.</para> + + <para><function>ne_add_request_header</function> simply adds a +header of given <parameter>name</parameter>, with given +<parameter>value</parameter>.</para> + + <para><function>ne_print_request_header</function> adds a +header of given <parameter>name</parameter>, taking the value from the +<function>printf</function>-like <parameter>format</parameter> string +parameter and subsequent variable-length argument list.</para> + + </refsect1> + + <refsect1> + <title>See also</title> + + <para><xref linkend="ne_request_create"/></para> + </refsect1> + + </refentry> diff --git a/doc/ref/resolve.xml b/doc/ref/resolve.xml new file mode 100644 index 0000000..067cf61 --- /dev/null +++ b/doc/ref/resolve.xml @@ -0,0 +1,145 @@ +<refentry id="refresolve"> + + <refmeta> + <refentrytitle>ne_addr_resolve</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname id="ne_addr_resolve">ne_addr_resolve</refname> + <refname id="ne_addr_result">ne_addr_result</refname> + <refname id="ne_addr_first">ne_addr_first</refname> + <refname id="ne_addr_next">ne_addr_next</refname> + <refname id="ne_addr_error">ne_addr_error</refname> + <refname id="ne_addr_destroy">ne_addr_destroy</refname> + <refpurpose>functions to resolve hostnames to addresses</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <funcsynopsis> + + <funcsynopsisinfo>#include <ne_socket.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>ne_sock_addr *<function>ne_addr_resolve</function></funcdef> + <paramdef>const char *<parameter>hostname</parameter></paramdef> + <paramdef>int <parameter>flags</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>int <function>ne_addr_result</function></funcdef> + <paramdef>const ne_sock_addr *<parameter>addr</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>const ne_inet_addr *<function>ne_addr_first</function></funcdef> + <paramdef>ne_sock_addr *<parameter>addr</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>const ne_inet_addr *<function>ne_addr_next</function></funcdef> + <paramdef>ne_sock_addr *<parameter>addr</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>char *<function>ne_addr_error</function></funcdef> + <paramdef>const ne_sock_addr *<parameter>addr</parameter></paramdef> + <paramdef>char *<parameter>buffer</parameter></paramdef> + <paramdef>size_t <parameter>bufsiz</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>void <function>ne_addr_destroy</function></funcdef> + <paramdef>ne_sock_addr *<parameter>addr</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para>The <function>ne_addr_resolve</function> function resolves + the given <parameter>hostname</parameter>, returning an + <type>ne_sock_addr</type> object representing the address (or + addresses) associated with the hostname. The + <parameter>flags</parameter> parameter is currently unused, and + must be passed as 0.</para> + + <para>The <parameter>hostname</parameter> passed to + <function>ne_addr_resolve</function> can be a DNS hostname + (e.g. <literal>"www.example.com"</literal>) or an IPv4 dotted quad + (e.g. <literal>"192.0.34.72"</literal>); or, on systems which + support IPv6, an IPv6 hex address, which may be enclosed in + brackets, e.g. <literal>"[::1]"</literal>.</para> + + <para>To determine whether the hostname was successfully resolved, + the <function>ne_addr_result</function> function is used, which + returns non-zero if an error occurred. If an error did occur, the + <function>ne_addr_error</function> function can be used, which + will copy the error string into a given + <parameter>buffer</parameter> (of size + <parameter>bufsiz</parameter>).</para> + + <para>The functions <function>ne_addr_first</function> and + <function>ne_addr_next</function> are used to retrieve the + Internet addresses associated with an address object which has + been successfully resolved. <function>ne_addr_first</function> + returns the first address; <function>ne_addr_next</function> + returns the next address after the most recent call to + <function>ne_addr_next</function> or + <function>ne_addr_first</function>, or &null; if there are no more + addresses. The <type>ne_inet_addr</type> pointer returned by + these functions can be passed to + <function>ne_sock_connect</function> to connect a socket.</para> + + <para>After the address object has been used, it should be + destroyed using <function>ne_addr_destroy</function>.</para> + + </refsect1> + + <refsect1> + <title>Return value</title> + + <para><function>ne_addr_resolve</function> returns a pointer to an + address object, and never &null;. + <function>ne_addr_error</function> returns the + <parameter>buffer</parameter> parameter .</para> + + </refsect1> + + <refsect1> + <title>Examples</title> + + <para>The code below prints out the set of addresses associated + with the hostname <literal>www.google.com</literal>.</para> + + <programlisting>ne_sock_addr *addr; +char buf[256]; + +addr = ne_addr_resolve("www.google.com", 0); +if (ne_addr_result(addr)) { + printf("Could not resolve www.google.com: %s\n", + ne_addr_error(addr, buf, sizeof buf)); +} else { + const ne_inet_addr *ia; + printf("www.google.com:"); + for (ia = ne_addr_first(addr); ia != NULL; ia = ne_addr_next(addr)) { + printf(" %s", ne_iaddr_print(ia, buf, sizeof buf)); + } + putchar('\n'); +} +ne_addr_destroy(addr); +</programlisting> + </refsect1> + + <refsect1> + <title>See also</title> + + <para><xref linkend="ne_iaddr_print"/></para> + </refsect1> + +</refentry> + diff --git a/doc/ref/sess.xml b/doc/ref/sess.xml new file mode 100644 index 0000000..8fcd9cb --- /dev/null +++ b/doc/ref/sess.xml @@ -0,0 +1,123 @@ + <refentry id="refsess"> + + <refmeta> + <refentrytitle>ne_session_create</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname id="ne_session_create">ne_session_create</refname> + <refname id="ne_close_connection">ne_close_connection</refname> + <refname id="ne_session_proxy">ne_session_proxy</refname> + <refname id="ne_session_destroy">ne_session_destroy</refname> + <refpurpose>set up HTTP sessions</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <funcsynopsis> + <funcsynopsisinfo>#include <ne_session.h></funcsynopsisinfo> + <funcprototype> + <funcdef>ne_session *<function>ne_session_create</function></funcdef> + <paramdef>const char *<parameter>scheme</parameter></paramdef> + <paramdef>const char *<parameter>hostname</parameter></paramdef> + <paramdef>unsigned int <parameter>port</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>void <function>ne_session_proxy</function></funcdef> + <paramdef>ne_session *<parameter>session</parameter></paramdef> + <paramdef>const char *<parameter>hostname</parameter></paramdef> + <paramdef>unsigned int <parameter>port</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>void <function>ne_close_connection</function></funcdef> + <paramdef>ne_session *<parameter>session</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>void <function>ne_session_destroy</function></funcdef> + <paramdef>ne_session *<parameter>session</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para>An <type>ne_session</type> object represents an HTTP +session - a logical grouping of a sequence of HTTP requests made to a +certain server. Any requests made using the session can use a +persistent connection, share cached authentication credentials and any +other common attributes.</para> + + <para>A new HTTP session is created using +<function>ne_session_create</function>, giving the +<parameter>hostname</parameter> and <parameter>port</parameter> of the +server to use, along with the <parameter>scheme</parameter> used to +contact the server (usually <literal>"http"</literal>). Before the +first use of <function>ne_session_create</function> in a process, +<xref linkend="ne_sock_init"/> must have been called to perform any +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> + + <para>If an HTTP proxy server should be used for the session, +<function>ne_session_proxy</function> must be called giving the +hostname and port on which to contact the proxy.</para> + + <para>If it is known that the session will not be used for a +significant period of time, <function>ne_close_connection</function> +can be called to close the connection, if one remains open. Use of +this function is entirely optional, but it must not be called if there +is a request active using the session.</para> + + <para>Once a session has been completed, +<function>ne_session_destroy</function> must be called to destroy the +resources associated with the session. Any subsequent use of the +session pointer produces undefined behaviour.</para> + + </refsect1> + + <refsect1> + <title>Notes</title> + + <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 +only be detected at that time (using the <literal>NE_LOOKUP</literal> +error code); see <xref linkend="ne_request_dispatch"/> for +details.</para> + + </refsect1> + + <refsect1> + <title>Return Values</title> + <para><function>ne_session_create</function> will return + a pointer to a new session object (and never &null;).</para> + </refsect1> + + <refsect1> + <title>Examples</title> + <para>Create and destroy a session:</para> + <programlisting>ne_session *sess; +sess = ne_session_create("http", "host.example.com", 80); +/* ... use sess ... */ +ne_session_destroy(sess); +</programlisting> + </refsect1> + + <refsect1> + <title>See Also</title> + + <para><xref linkend="ne_ssl_set_verify"/>, <xref linkend="ne_ssl_load_ca"/>, <xref linkend="ne_sock_init"/></para> + </refsect1> + + </refentry> diff --git a/doc/ref/shave.xml b/doc/ref/shave.xml new file mode 100644 index 0000000..a5b745a --- /dev/null +++ b/doc/ref/shave.xml @@ -0,0 +1,51 @@ + <refentry id="refshave"> + + <refmeta> + <refentrytitle>ne_shave</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname>ne_shave</refname> + <refpurpose>trim whitespace from a string</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <funcsynopsis> + + <funcsynopsisinfo>#include <ne_string.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>char *<function>ne_shave</function></funcdef> + <paramdef>char *<parameter>str</parameter></paramdef> + <paramdef>const char *<parameter>whitespace</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <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> + + </refsect1> + + <refsect1> + <title>Examples</title> + + <para>The following code segment will output + <literal>"fish"</literal>:</para> + + <programlisting>char s[] = ".!.fish!.!"; +puts(ne_shave(s, ".!"));</programlisting> + + </refsect1> + + </refentry> + diff --git a/doc/ref/sslca.xml b/doc/ref/sslca.xml new file mode 100644 index 0000000..c68739d --- /dev/null +++ b/doc/ref/sslca.xml @@ -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> diff --git a/doc/ref/sslcert.xml b/doc/ref/sslcert.xml new file mode 100644 index 0000000..46dbffd --- /dev/null +++ b/doc/ref/sslcert.xml @@ -0,0 +1,66 @@ + <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 <ne_session.h> + +/* 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> diff --git a/doc/ref/ssldname.xml b/doc/ref/ssldname.xml new file mode 100644 index 0000000..accc2cb --- /dev/null +++ b/doc/ref/ssldname.xml @@ -0,0 +1,66 @@ + + <refentry id="refssldname"> + + <refmeta> + <refentrytitle>ne_ssl_dname</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname id="ne_ssl_readable_dname">ne_ssl_readable_dname</refname> + <refname id="ne_ssl_dname_cmp">ne_ssl_dname_cmp</refname> + <refpurpose>SSL distinguished name handling</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <funcsynopsis> + + <funcsynopsisinfo>#include <ne_ssl.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>const char *<function>ne_ssl_readable_dname</function></funcdef> + <paramdef>const ne_ssl_dname *<parameter>dname</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>int <function>ne_ssl_dname_cmp</function></funcdef> + <paramdef>const ne_ssl_dname *<parameter>dn1</parameter></paramdef> + <paramdef>const ne_ssl_dname *<parameter>dn2</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para>The <function>ne_ssl_readable_dname</function> function +creates a single-line, human-readable string out of an +<type>ne_ssl_dname</type> object. The returned string is +<function>malloc</function>()-allocated, and must be +<function>free</function>()d by the caller.</para> + + <para>The <function>ne_ssl_dname_cmp</function> function + compares two distinguished names, and returns zero if they are + equal, or non-zero otherwise.</para> + + </refsect1> + + <refsect1> + <title>Return value</title> + + <para><function>ne_ssl_readable_dname</function> returns a + <function>malloc</function>-allocated string, and never + NULL.</para> + + </refsect1> + + <refsect1> + <title>See also</title> + + <para><xref linkend="ne_ssl_certificate"/></para> + </refsect1> + + </refentry> diff --git a/doc/ref/sslvfy.xml b/doc/ref/sslvfy.xml new file mode 100644 index 0000000..98f0054 --- /dev/null +++ b/doc/ref/sslvfy.xml @@ -0,0 +1,140 @@ + <refentry id="refsslvfy"> + + <refmeta> + <refentrytitle>ne_ssl_set_verify</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname id="ne_ssl_set_verify">ne_ssl_set_verify</refname> + <refpurpose>register an SSL certificate verification callback</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <funcsynopsis> + + <funcsynopsisinfo>#include <ne_session.h></funcsynopsisinfo> + + <!-- hard to put data type declarations here --> + + <funcprototype> + <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> + </funcprototype> + + <funcprototype> + <funcdef>void <function>ne_ssl_set_verify</function></funcdef> + <paramdef>ne_session *<parameter>session</parameter></paramdef> + <paramdef>ne_ssl_verify_fn <parameter>verify_fn</parameter></paramdef> + <paramdef>void *<parameter>userdata</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para>To enable manual SSL certificate verification, a +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 +some way, the connection will fail.</para> + + <para>When the callback is invoked, the +<parameter>failures</parameter> parameter gives a bitmask indicating +in what way the automatic certificate verification failed. The value +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> + <listitem> + <para>The certificate is not yet valid.</para> + </listitem> + </varlistentry> + <varlistentry><term><filename>NE_SSL_EXPIRED</filename></term> + <listitem> + <para>The certificate has expired.</para> + </listitem> + </varlistentry> + <varlistentry><term><filename>NE_SSL_CNMISMATCH</filename></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> + </listitem> + </varlistentry> + <varlistentry><term><filename>NE_SSL_UNKNOWNCA</filename></term> + <listitem> + <para>The Certificate Authority which signed the certificate +is not trusted.</para> + </listitem> + </varlistentry> + </variablelist> + + <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> + + </refsect1> + + <refsect1> + <title>Return value</title> + + <para>The verification callback must return zero to indicate +that the certificate should be trusted; and non-zero otherwise (in +which case, the connection will fail).</para> + </refsect1> + + <refsect1> + <title>Examples</title> + + <para>Manual certificate verification:</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 & NE_SSL_CNMISMATCH) { + printf("Server certificate was issued to `%s'; " + "connection may have been intercepted!\n", + cert->subject->commonName); + } + if (failures & 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 */ +} + +int +main(...) +{ + ne_session *sess = ne_session_create("https", "some.host.name", 443); + ne_ssl_set_verify(sess, my_verify, NULL); + ... +}</programlisting> + + </refsect1> + + <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> + </refsect1> + + </refentry> diff --git a/doc/ref/status.xml b/doc/ref/status.xml new file mode 100644 index 0000000..56616ea --- /dev/null +++ b/doc/ref/status.xml @@ -0,0 +1,74 @@ + <refentry id="refstatus"> + + <refmeta> + <refentrytitle>ne_status</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname id="ne_status">ne_status</refname> + <refpurpose>HTTP status structure</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <funcsynopsis><funcsynopsisinfo>#include <ne_utils.h> + +typedef struct { + int major_version, minor_version; + int code, klass; + const char *reason_phrase; +} <type>ne_status</type>;</funcsynopsisinfo></funcsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para>An <type>ne_status</type> type represents an HTTP +response status; used in response messages giving a result of request. +The <structfield>major_version</structfield> and +<structfield>minor_version</structfield> fields give the HTTP version +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> + + <para>There are five classes of HTTP status code defined by + RFC2616:</para> + + <variablelist> + <varlistentry> + <term><literal>1xx</literal></term> + <listitem><para>Informational response.</para></listitem> + </varlistentry> + + <varlistentry> + <term><literal>2xx</literal></term> + <listitem><para>Success: the operation was successful</para></listitem> + </varlistentry> + + <varlistentry> + <term><literal>3xx</literal></term> + <listitem><para>Redirection</para></listitem> + </varlistentry> + + <varlistentry> + <term><literal>4xx</literal></term> <listitem><para>Client + error: the request made was incorrect in some + manner.</para></listitem> + </varlistentry> + + <varlistentry> + <term><literal>5xx</literal></term> + <listitem><para>Server error</para></listitem> + </varlistentry> + </variablelist> + + </refsect1> + + <refsect1> <title>See also</title> <para><xref +linkend="ne_get_status"/>.</para> </refsect1> + + </refentry> diff --git a/doc/ref/tok.xml b/doc/ref/tok.xml new file mode 100644 index 0000000..2e6211f --- /dev/null +++ b/doc/ref/tok.xml @@ -0,0 +1,76 @@ + <refentry id="reftok"> + + <refmeta> + <refentrytitle>ne_token</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname>ne_token</refname> + <refname>ne_qtoken</refname> + <refpurpose>string tokenizers</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <funcsynopsis> + + <funcsynopsisinfo>#include <ne_string.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>char *<function>ne_token</function></funcdef> + <paramdef>char **<parameter>str</parameter></paramdef> + <paramdef>char <parameter>sep</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>char *<function>ne_qtoken</function></funcdef> + <paramdef>char **<parameter>str</parameter></paramdef> + <paramdef>char <parameter>sep</parameter></paramdef> + <paramdef>const char *<parameter>quotes</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <!-- FIXME: italics on tokenize --> + + <para><function>ne_token</function> and +<function>ne_qtoken</function> tokenize the string at the location +stored in the pointer <parameter>str</parameter>. Each time the +function is called, it returns the next token, and modifies the +<parameter>str</parameter> pointer to point to the remainer of the +string, or &null; if there are no more tokens in the string. A token +is delimited by the separator character <parameter>sep</parameter>; if +<function>ne_qtoken</function> is used any quoted segments of the +string are skipped when searching for a separator. A quoted segment +is enclosed in a pair of one of the characters given in the +<parameter>quotes</parameter> string.</para> + + <para>The string being tokenized is modified each time +the tokenizing function is called; replacing the next separator +character with a &nul; terminator.</para> + + </refsect1> + + <refsect1> + <title>Examples</title> + + <para>The following function prints out each token in a +comma-separated string <parameter>list</parameter>, which is +modified in-place:</para> + + <programlisting>static void splitter(char *list) +{ + do { + printf("Token: %s\n", ne_token(&list, ',')); + while (list); +}</programlisting> + + </refsect1> + + </refentry> diff --git a/doc/ref/vers.xml b/doc/ref/vers.xml new file mode 100644 index 0000000..2e7a50d --- /dev/null +++ b/doc/ref/vers.xml @@ -0,0 +1,63 @@ +<refentry id="refvers"> + + <refmeta> + <refentrytitle>ne_version_match</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname>ne_version_match</refname> + <refname>ne_version_string</refname> + <refpurpose>library versioning</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <funcsynopsis> + + <funcsynopsisinfo>#include <ne_utils.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>int <function>ne_version_match</function></funcdef> + <paramdef>int <parameter>major</parameter></paramdef> + <paramdef>int <parameter>minor</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>const char *<function>ne_version_string</function></funcdef> + <void/> + </funcprototype> + + </funcsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para>The <function>ne_version_match</function> function returns + non-zero if the library version is not of major version + <parameter>major</parameter>, or the minor version is less than + <parameter>minor</parameter>. For &neon; versions 0.x, every + minor version is assumed to be incompatible with every other minor + version.</para> <!-- TODO: remove that for 1.0 --> + + <para>The <function>ne_version_string</function> function returns + a string giving the library version.</para> + + </refsect1> + + <refsect1> + <title>Examples</title> + + <para>To require &neon; 1.x, version 1.2 or later:</para> + + <programlisting>if (ne_version_match(1, 2)) { + printf("Library version out of date: 1.2 required, found %s.", + ne_version_string()); + exit(1); +}</programlisting> + + </refsect1> + +</refentry> diff --git a/doc/refentry.xml b/doc/refentry.xml new file mode 100644 index 0000000..bf724e0 --- /dev/null +++ b/doc/refentry.xml @@ -0,0 +1,56 @@ +<refentry id="refXXXX"> + + <refmeta> + <refentrytitle>ne_foo</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname id="ne_foo">ne_foo</refname> + <refname id="ne_bar">ne_bar</refname> + <refpurpose>functions which do foo and bar</refpurpose> + </refnamediv> + + <refsynopsisdiv> + + <funcsynopsis> + + <funcsynopsisinfo>#include <ne_header.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>void <function>ne_set_useragent</function></funcdef> + <paramdef>ne_session *<parameter>session</parameter></paramdef> + <paramdef>const char *<parameter>product</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para>XXX</para> + + </refsect1> + + <refsect1> + <title>Return value</title> + + <para>XXX</para> + </refsect1> + + <refsect1> + <title>Examples</title> + + <para>XXX</para> + </refsect1> + + <refsect1> + <title>See also</title> + + <para>XXX</para> + </refsect1> + +</refentry> + diff --git a/doc/using-neon.txt b/doc/using-neon.txt new file mode 100644 index 0000000..45ddfc3 --- /dev/null +++ b/doc/using-neon.txt @@ -0,0 +1,166 @@ + +Guide to neon +============= + +Using libneon from applications +------------------------------- + +The neon source package is designed to be easily incorporated into +applications: + +- autoconf macros are distributed in the 'macros' subdirectory of the + neon distribution. Use NEON_LIBRARY from your configure.in to check + for the presence of the neon library installed on the system. The + macro adds an '--with-neon=...' argument to configure, which allows + the user to specify a location for the library (the standard /usr + and /usr/local directories are checked automatically without having + to be specified). + +- The 'src' directory of the neon package can be imported directly + into your application, if you do not wish to add an external + dependency. If you wish to bundle, use the NEON_BUNDLED macro + to configure neon in your application: here, the neon sources are + bundled in a directory called 'libneon': + + NEON_BUNDLED(libneon, ...) + + If your application supports builds where srcdir != builddir, you + should use the NEON_VPATH_BUNDLED macro like this: + + NEON_VPATH_BUNDLED(${srcdir}/libneon, libneon, ...) + + (thanks to Peter Moulder for getting this working properly). + + If you use this macro, a '--with-included-neon' option will + be added to the generated configure script. This allows the user + to force the bundled neon to be used in the application, rather than + any neon library found on the system. If you allow neon to be + configured this way, you must also configure an XML parser. Use + the NEON_XML_PARSER macro to do this. + +- The final argument to the _BUNDLED macros is a set of actions which + are executed if the bundled build *is* chosen (rather than an + external neon which might have been found on the user's system). + In here, use either the NEON_LIBTOOL_BUILD or NEON_NORMAL_BUILD + macro to set up the neon Makefile appropriately: including adding + the neon source directory to the recursive make. + +- A full fragment might be: + + NEON_BUNDLED(libneon, [ + NEON_NORMAL_BUILD + NEON_XML_PARSER + SUBDIRS="libneon $SUBDIRS" + ]) + + This means the bundled neon source directory (called 'libneon') is + used if no neon is found on the system, and the standard XML parser + search is used. + +The neon API +============ + +neon offers two levels of API for use in applications: + +- Low-level HTTP request/response handling +- High-level method invocation + +The low-level interface allows for easily designing new method +handlers, taking care of things like persistent connections, +authentication, and proxy servers. The high-level interface allows +you to easily integrate existing HTTP (and WebDAV) methods into your +application. This document details both interfaces. + +N.B.: Documentation is always WRONG. The definitive API reference is in +src/*.c, with src/*.h is hopefully fairly similar. + +PLEASE NOTE: the neon API is NOT STABLE, and is not considered to be +stable or backwards-compatible until version 1.0 is reached. If +you are not happy with this constraint, then please either: + +1. pick a version of neon and never upgrade +2. don't use neon (yet). +3. contribute sufficient development resources to neon that all + bugs are fixed yesterday, features added tomorrow, and 1.0 is + reached on by the end of the week. + +An Important Note +----------------- + +Most neon functions which allocate memory with malloc() will call +abort() if malloc() returns NULL. This is a design decision, the +rationale being: + +- it makes the interfaces cleaner. + +- if malloc() DOES return NULL there is not much you can do about it. + +- Apparently, malloc() won't return NULL on systems which over-commit + memory (e.g. Linux), so it doesn't make any real difference anyway. + +The author is open to persuasion on this: mail neon@webdav.org. + +Namespaces +---------- + +neon reserves these namespaces: + ne_* + uri_* + sock_* + +Eventually all symbols globally defined by the library should fall +within a reserved namespace. The author is considering moving +all symbols into the ne_* namespace. + +Note that the XML parser used will also reserve a namespace: +expat takes XML_*, libxml takes xml* + +The http_session type +--------------------- + +The http_session type is used whether you are writing to the low-level +or the high-level interface. An http_session object is created to +store data which persists beyond a single HTTP request: + + - Protocol options, e.g. (proxy) server details + - Authentication information + - Persistent connection + +A session is created with the 'ne_session_create' call. Before +creating a request for the session, the server details must be set, as +follows: + + ne_session *sess; + /* Initialize the socket library */ + sock_init(); + /* Create the session */ + sess = ne_session_create(); + /* Optionally, set a proxy server */ + ne_session_proxy(sess, "proxy.myisp.com", 8080); + /* Set the server */ + ne_session_server(sess, "my.server.com", 80); + +The proxy server should be set BEFORE the origin server; otherwise a +DNS lookup will be performed on the origin server by the +ne_session_server call, which may well fail if the client is +firewalled. ne_session_{proxy,server} will return NE_LOOKUP if +the DNS lookup fails; otherwise NE_OK. + +The 'ne_set_persist' call can be used to turn off persistent +connection handling: it is on by default. + +The 'ne_set_useragent' call can be used to set the User-Agent header +to be sent with requests. A product token of the form +"myhttpclient/0.1.2" should be passed, and will have "neon/x.y.z" +appended in the actual header sent. + +When a session has been finished with, it should be destroyed using +ne_session_destroy. Any subsequent operations on the session object +will have undefined results (i.e. will segfault). + +Low-level HTTP Request/Response Handling +---------------------------------------- + +... + + diff --git a/doc/using.xml b/doc/using.xml new file mode 100644 index 0000000..efb53d1 --- /dev/null +++ b/doc/using.xml @@ -0,0 +1,119 @@ + <sect1 id="using"> + <title>How to use neon from your application</title> + + <para>This section describes how to add &neon; support to an + application. If you just want to quickly try out &neon;, use + the <xref linkend="refconfig"/> script.</para> + + <para>The &neon; source code is designed to be easily embedded + into an application source tree. &neon; has no dependencies on + libraries other than an SSL toolkit and XML parser, though the + source tree can be configured to have no support for SSL or XML + if desired. To configure the &neon; source code some <ulink + url="http://www.gnu.org/software/autoconf/">GNU autoconf</ulink> + macros are supplied, which can be used in a number of ways, as + follows:</para> + + <itemizedlist> + <listitem> + + <para>autoconf macros are distributed in the 'macros' + subdirectory of the neon distribution. Use the NEON_LIBRARY + macro from your configure.in to check for the presence of + the neon library installed on the system. The macro adds an + '--with-neon=...' argument to configure, which allows the + user to specify a location for the library (the standard + /usr and /usr/local directories are checked automatically + without having to be specified).</para></listitem> + + <listitem><para>The 'src' directory of the neon package can be + imported directly into your application, if you do not wish + to add an external dependency. If you wish to bundle, use + the NEON_BUNDLED macro to configure neon in your application: + here, the neon sources are bundled in a directory called + 'libneon':</para> + + <programlisting>NEON_BUNDLED(libneon, ...)</programlisting> + + <para>If your application supports builds where srcdir != builddir, + you should use the NEON_VPATH_BUNDLED macro like this:</para> + + <programlisting>NEON_VPATH_BUNDLED(${srcdir}/libneon, libneon, ...)</programlisting> + + <para>If you use this macro, a '--with-included-neon' option + will be added to the generated configure script. This + allows the user to force the bundled neon to be used in the + application, rather than any neon library found on the + system. If you allow neon to be configured this way, you + must also configure an XML parser. Use the NEON_XML_PARSER + macro to do this.</para></listitem> + + <listitem><para>The final argument to the _BUNDLED macros is a + set of actions which are executed if the bundled build *is* + chosen (rather than an external neon which might have been + found on the user's system). In here, use either the + NEON_LIBTOOL_BUILD or NEON_NORMAL_BUILD macro to set up the + neon Makefile appropriately: including adding the neon source + directory to the recursive make.</para></listitem> + + </itemizedlist> + + <para>A full fragment might be:</para> + +<programlisting>NEON_BUNDLED(libneon, [ + NEON_NORMAL_BUILD + NEON_XML_PARSER + SUBDIRS="libneon $SUBDIRS" +])</programlisting> + + <para>This means the bundled neon source directory (called 'libneon') + is used if no neon is found on the system, and the standard XML + parser search is used.</para> + + </sect1> + + <sect1 id="compliance"> + <title>Protocol 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 + exceptions are documented in this section.</para> + + <sect2><title>RFC 2518, HTTP Extensions for Distributed Authoring—WebDAV</title> + + <para>&neon; is deliberately not compliant with section + 23.4.2, and treats property names as a (namespace-URI, name) + pair. This is <ulink + url="http://lists.w3.org/Archives/Public/w3c-dist-auth/1999OctDec/0343.html">generally + considered</ulink> to be correct behaviour by the WebDAV + working group, and is likely to formally adopted in a future + revision of the specification.</para></sect2> + + <sect2><title>RFC 2616, Hypertext Transfer Protocol—HTTP/1.1</title> + + <para>There is some confusion in this specification about the + use of the <quote>identity</quote> + <firstterm>transfer-coding</firstterm>. &neon; treats the + presence of <emphasis>any</emphasis> + <literal>Transfer-Encoding</literal> response header as an + indication that the response message uses the + <quote>chunked</quote> transfer-coding. This was the + suggested resolution <ulink + url="http://lists.w3.org/Archives/Public/ietf-http-wg-old/2001SepDec/0018.html">proposed + by Larry Masinter</ulink>.</para></sect2> + + <sect2> + <title>RFC 2617, HTTP Authentication: Basic and Digest Access Authentication</title> + + <para>&neon; is not strictly compliant with the quoting rules + given in the grammar for the <literal>Authorization</literal> + header. The grammar requires that the <literal>qop</literal> + and <literal>algorithm</literal> parameters are not quoted, + however one widely deployed server implementation + (Microsoft® IIS 5) rejects the request if these parameters + are not quoted. &neon; sends these parameters with + quotes—this is not known to cause any problems with + other server implementations.</para></sect2> + + </sect1> diff --git a/doc/xml.xml b/doc/xml.xml new file mode 100644 index 0000000..c001073 --- /dev/null +++ b/doc/xml.xml @@ -0,0 +1,207 @@ +<!-- neon XML interface -*- text -*- --> + +<sect1 id="xml"> + + <title>Parsing XML</title> + + <para>The &neon; XML interface is exposed by the + <filename>ne_xml.h</filename> header file. This interface gives a + wrapper around the standard <ulink + 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> + +<sect2 id="xml-sax"> + <title>Introduction to SAX</title> + + <para>A SAX-based parser works by emitting a sequence of + <firstterm>events</firstterm> to reflect the tokens being parsed + from the XML document. For example, parsing the following document + fragment: + +<programlisting><![CDATA[ +<hello>world</hello> +]]></programlisting> + + results in the following events: + + <orderedlist> + <listitem> + <simpara>&startelm; "hello"</simpara> + </listitem> + <listitem> + <simpara>&cdata; "world"</simpara> + </listitem> + <listitem> + <simpara>&endelm; "hello"</simpara> + </listitem> + </orderedlist> + + This example demonstrates the three event types used used in the + subset of SAX exposed by the &neon; XML interface: &startelm;, + &cdata; and &endelm;. In a C API, an <quote>event</quote> is + implemented as a function callback; three callback types are used in + &neon;, one for each type of event.</para> + +</sect2> + +<sect2 id="xml-stacked"> + <title>Stacked SAX handlers</title> + + <para>WebDAV property values are represented as fragments of XML, + transmitted as parts of larger XML documents over HTTP (notably in + the body of the response to a <literal>PROPFIND</literal> request). + When &neon; parses such documents, the SAX events generated for + these property value fragments may need to be handled by the + application, since &neon; has no knowledge of the structure of + properties used by the application.</para> + + <para>To solve this problem<footnote><para>This + <quote>problem</quote> only needs solving because the SAX interface + is so inflexible when implemented as C function callbacks; a better + approach would be to use an XML parser interface which is not based + on callbacks.</para></footnote> the &neon; XML interface introduces + the concept of a <firstterm>SAX handler</firstterm>. A SAX handler + comprises a &startelm;, &cdata; and &endelm; callback; the + &startelm; callback being defined such that each handler may + <emphasis>accept</emphasis> or <emphasis>decline</emphasis> the + &startelm; event. Handlers are composed into a <firstterm>handler + stack</firstterm> before parsing a document. When a new &startelm; + event is generated by the XML parser, &neon; invokes each &startelm; + callback in the handler stack in turn until one accepts the event. + The handler which accepts the event will then be subsequently be + passed &cdata; events if the element contains character data, + followed by an &endelm; event when the element is closed. If no + handler in the stack accepts a &startelm; event, the branch of the + tree is ignored.</para> + + <para>To illustrate, given a handler A, which accepts the + <literal>cat</literal> and <literal>age</literal> elements, and a + handler B, which accepts the <literal>name</literal> element, the + following document: + +<example id="xml-example"> +<title>An example XML document</title> +<programlisting><![CDATA[ +<cat> + <age>3</age> + <name>Bob</name> +</cat> +]]></programlisting></example> + + would be parsed as follows: + + <orderedlist> + <listitem> + <simpara>A &startelm; "cat" → <emphasis>accept</emphasis></simpara> + </listitem> + <listitem> + <simpara>A &startelm; "age" → <emphasis>accept</emphasis></simpara> + </listitem> + <listitem> + <simpara>A &cdata; "3"</simpara> + </listitem> + <listitem> + <simpara>A &endelm; "age"</simpara> + </listitem> + <listitem> + <simpara>A &startelm; "name" → <emphasis>decline</emphasis></simpara> + </listitem> + <listitem> + <simpara>B &startelm; "name" → <emphasis>accept</emphasis></simpara> + </listitem> + <listitem> + <simpara>B &cdata; "Bob"</simpara> + </listitem> + <listitem> + <simpara>B &endelm; "name"</simpara> + </listitem> + <listitem> + <simpara>A &endelm; "cat"</simpara> + </listitem> + </orderedlist></para> + + <para>The search for a handler which will accept a &startelm; event + begins at the handler of the parent element and continues toward the + top of the stack. For the root element, it begins at the base of + the stack. In the above example, handler A is at the base, and + handler B at the top; if the <literal>name</literal> element had any + children, only B's &startelm; would be invoked to accept + them.</para> + +</sect2> + +<sect2 id="xml-state"> + <title>Maintaining state</title> + + <para>To facilitate communication between independent handlers, a + <firstterm>state integer</firstterm> is associated with each element + being parsed. This integer is returned by &startelm; callback and + is passed to the subsequent &cdata; and &endelm; callbacks + associated with the element. The state integer of the parent + element is also passed to each &startelm; callback, the value zero + used for the root element (which by definition has no + parent).</para> + + <para>To further extend <xref linkend="xml-example"/>: if handler A + defines that the state of the root element <sgmltag>cat</sgmltag> + will be <literal>42</literal>, the event trace would be as + follows: + + <orderedlist> + <listitem> + <simpara>A &startelm; (parent = 0, "cat") → + <emphasis>accept</emphasis>, state = 42 + </simpara> + </listitem> + <listitem> + <simpara>A &startelm; (parent = 42, "age") → + <emphasis>accept</emphasis>, state = 50 + </simpara> + </listitem> + <listitem> + <simpara>A &cdata; (state = 50, "3")</simpara> + </listitem> + <listitem> + <simpara>A &endelm; (state = 50, "age")</simpara> + </listitem> + <listitem> + <simpara>A &startelm; (parent = 42, "name") → + <emphasis>decline</emphasis></simpara> + </listitem> + <listitem> + <simpara>B &startelm; (parent = 42, "name") → + <emphasis>accept</emphasis>, state = 99</simpara> + </listitem> + <listitem> + <simpara>B &cdata; (state = 99, "Bob")</simpara> + </listitem> + <listitem> + <simpara>B &endelm; (state = 99, "name")</simpara> + </listitem> + <listitem> + <simpara>A &endelm; (state = 42, "cat")</simpara> + </listitem> + </orderedlist></para> + + <para>To avoid collisions between state integers used by different + handlers, the interface definition of any handler includes the range + of integers it will use.</para> + +</sect2> + +<sect2 id="xml-ns"> + <title>XML namespaces</title> + + <para>To support XML namespaces, every element name is represented + as a <emphasis>(namespace, name)</emphasis> pair. The &startelm; + and &endelm; callbacks are passed namespace and name strings + accordingly. If an element in the XML document has no declared + namespace, the namespace given will be the empty string, + <literal>""</literal>.</para> + +</sect2> + +</sect1> |