diff options
Diffstat (limited to 'doc')
-rwxr-xr-x | doc/tutorial.xml | 611 |
1 files changed, 408 insertions, 203 deletions
diff --git a/doc/tutorial.xml b/doc/tutorial.xml index 3db45bd..827bbb7 100755 --- a/doc/tutorial.xml +++ b/doc/tutorial.xml @@ -1,300 +1,504 @@ -<!-- <?xml version='1.0' encoding='ISO-8859-1' ?> -->
+
<article>
<articleinfo>
- <title>cSOAP Implementation Guide $Revision: 1.2 $</title>
+ <title>cSOAP Implementation Guide $Revision: 1.3 $</title>
<author><firstname>Ferhat</firstname><surname>Ayaz</surname></author>
<copyright><year>2004</year><holder>csoap</holder></copyright>
</articleinfo>
+
<section>
- <title>Introduction</title>
+<title>Introduction</title>
- <para>
- This document gives you information about how to use the cSOAP API in your applications.
- </para>
+<para>
+ This document shows in short examples how to use cSOAP
+for the client and server side implementation.
+</para>
-</section>
+<para>
+ cSOAP is a simple client/server SOAP library to implement standalone
+and embedded SOAP applications. cSOAP was implemented in pure C to
+support platforms as far as possible.
+</para>
-<section>
-<title>Implementing a simple SOAP Client</title>
+<para>
+ The underlying xml layer is libxml2 (http://xmlsoft.org). We used
+this library because it is fast and still maintained. You can find also
+some documentations about using libxml2.
+</para>
-<example>
-<title>A simple SOAP client</title>
+<para>
+ The transport of SOAP messages will be established via HTTP. cSOAP
+contains the subproject "nanohttp" which will do all the HTTP specific
+stuff. It implements a simple HTTP client and a server which can also
+be used outside the cSOAP project.
+</para>
-<programlistingco>
+</section>
-<areaspec>
- <area id="ex.client.newmethod" coords="11"/>
- <area id="ex.client.additem" coords="13"/>
- <area id="ex.client.invoke" coords="15"/>
- <area id="ex.client.print" coords="17"/>
- <areaset id="ex.client.free" coords="">
- <area id="ex.client.free1" coords='19'/>
- <area id="ex.client.free2" coords='20'/>
- </areaset>
-</areaspec>
+<section>
+<title>Nameconvention in cSOAP</title>
-<programlisting>
-/* FILE: simpleclient.c */
-static const char *url = "http://csoap.sourceforge.net/cgi-bin/csoapserver";
-static const char *urn = "urn:examples";
-static const char *method = "sayHello";
+<para>
+ cSOAP contains the following simple modules:
+</para>
-int main(int argc, char *argv[])
-{
- SoapEnv *env, *res;
+<synopsis>
+ + client : soap-client.h
+ + server : soap-server.h
+ + ctx : soap-ctx.h
+ + env : soap-env.h
+ + fault : soap-fault.h
+ + router : soap-router.h
+ + service : soap-service.h
+</synopsis>
- <callout arearefs="ex.client.newmethod"/> env = soap_env_new_with_method(urn, method);
+<para>
+ Each module declares the functions in the following name convention:
+</para>
- <callout arearefs="ex.client.additem"/> soap_env_add_item(env, "xsd:string",
- "name", "Jonny B. Good");
- <callout arearefs="ex.client.invoke"/> res = soap_client_invoke(env, url , "");
+<synopsis><![CDATA[
+ herror_t soap_<module>_<operation>();
+]]></synopsis>
- <callout arearefs="ex.client.print"/> soap_xml_doc_print(res->root->doc);
-
- <callout arearefs="ex.client.free"/> soap_env_free(res);
- <callout arearefs="ex.client.free"/> soap_env_free(env);
- return 0;
-}
-</programlisting>
+<para>
+ For example: The function to invoke a SOAP call from the client side:
+</para>
+<synopsis>
+ herror_t soap_client_invoke(....);
+</synopsis>
-<calloutlist>
+</section>
-<callout arearefs="ex.client.newmethod">
+<section>
+<title>Error handling</title>
<para>
- First we create a SOAP envelope (<type>SoapEnv</type>) using the
- <function>soap_env_new_with_method()</function>. This creates the
- following SOAP envelope.
+ Almost all function will return a "herror_t" object. If the function
+returns with success this object is H_OK. Another herror_t object
+will be returned otherwise. Following functions can be used with a
+returned herror_t object:
</para>
-<example>
-<title>Generated SOAP envelope</title>
+<synopsis>
+ herror_code() : Returns the error code
+ herror_func() : Returns the function name, where the error occured
+ herror_message() : Returns the human readable error message
+ herror_release() : Frees the herror_t object.
+</synopsis>
+<example>
<programlisting>
-<![CDATA[
-
-<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
- xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
- xmlns:xsd="http://www.w3.org/1999/XMLSchema"
- SOAP-ENV:encoding="http://schemas.xmlsoap.org/soap/encoding/">
-
- <SOAP-ENV:Body>
- <m:sayHello xmlns:m="urn:examples">
- </m:sayHello>
- </SOAP-ENV:Body>
-</SOAP-ENV:Envelope>
-
-]]>
+ herror_t err = soap_client_invoke(...);
+ if (err != H_OK) {
+ printf("Message: %s\n", herror_message(err));
+ printf("Error code: %d\n", herror_code(err));
+ printf("In function: %s\n", herror_func(err));
+ herror_release(err);
+ }
</programlisting>
-
</example>
-</callout>
+<note>
+ Note that you "must" call herror_release() to free the resources.
+</note>
-<callout arearefs="ex.client.additem">
+<note>
+ The error codes are defined in "nanohttp-common.h". Here some examples:
+</note>
-<para><function>soap_env_add_item()</function> will add a xml parameter to the envelope like follows</para>
+<synopsis>
-<example>
-<title>Added "name" parameter</title>
-<programlisting>
-<![CDATA[
+#define HSOCKET_ERROR_CREATE 1001
+#define URL_ERROR_UNKNOWN_PROTOCOL 1101
+#define XML_ERROR_PARSE 1601
-<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
- xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
- xmlns:xsd="http://www.w3.org/1999/XMLSchema"
- SOAP-ENV:encoding="http://schemas.xmlsoap.org/soap/encoding/">
-
- <SOAP-ENV:Body>
- <m:sayHello xmlns:m="urn:examples">
- <m:name xsi:type="xsd:string">Jonny B. Good</m:name>
- </m:sayHello>
- </SOAP-ENV:Body>
+</synopsis>
-</SOAP-ENV:Envelope>
-]]>
-</programlisting>
-</example>
-</callout>
-<callout arearefs="ex.client.invoke">
<para>
- Now we can send our soap call using <function>soap_client_invoke()</function>. The third argument
-is the <emphasis>SoapAction</emphasis> header value. The result is also a SOAP envelope.
-<function>soap_client_invoke()</function> will return always a <type>SoapEnv</type> object. It is
-the result SOAP envelope or a fault object.
+You can also create your own herror_t object with herror_new().
</para>
-</callout>
-<callout arearefs="ex.client.print">
-<para>
- <varname>res->root</varname> is always the root xml element of the result SOAP envelope
- and <varname>res->root->doc</varname> points always to the <type>xmlDocPtr</type>.
- <function>soap_xml_doc_print()</function> is a helper function to print out a xml document.
-</para>
-</callout>
+<synopsis>
+#define MY_ERROR_TEST 5001
-<callout arearefs="ex.client.free">
-<para>Free both envelope objects</para>
-</callout>
+herror_t err = herror_new("my_func()",
+ MY_ERROR_TEST,
+ "Size %d is greater then %d", 17, 13);
+</synopsis>
-</calloutlist>
+<note>
+ User defined error codes must be greater then 5000.
+</note>
-</programlistingco>
+</section>
-</example>
+<section>
+<title>Implementing a simple client</title>
-</section>
+<para>
+ One of the advantages of cSOAP is its simplicity. You can implement
+a client or a server in a few minutes. The steps are always indentical.
+</para>
+
+<synopsis>
+1. Initialize cSOAP client
+ soap_client_init_args()
+2. Create a SoapCtx object
+ soap_ctx_new_with_method()
-<section>
-<title>Implementing a simple SOAP Server</title>
+3. Fill the envelope
+ soap_env_add_item()
+ soap_env_add_itemf()
+ soap_env_add_attachment()
+ soap_env_add_custom()
+ soap_env_push_item()
+ soap_env_pop_item()
+
+4. Invoke
+ soap_client_invoke()
+
+5. Process returned SoapCtx object
+6. Clean up cSOAP client
+</synopsis>
<example>
-<title>A simple SOAP server</title>
+<programlisting><![CDATA[
+#include <libcsoap/soap-client.h>
-<programlistingco>
-<areaspec>
- <area id="ex.server.init" coords="7"/>
- <area id="ex.server.newrouter" coords="11"/>
- <area id="ex.server.regservice" coords="13"/>
- <area id="ex.server.regrouter" coords="14"/>
- <area id="ex.server.run" coords="16"/>
- <area id="ex.server.freerouter" coords="18"/>
- <area id="ex.server.destroy" coords="19"/>
-</areaspec>
+static const char *url = "http://localhost:10000/csoapserver";
+static const char *urn = "urn:examples";
+static const char *method = "sayHello";
-<programlisting>
-/* FILE: simpleserver.c */
int main(int argc, char *argv[])
{
+ SoapCtx *ctx, *ctx2;
+ herror_t err;
+
+ /* 1. Initialize cSOAP client */
+ soap_client_init_args(argc, argv);
+
+ /* 2. Create a SoapCtx object */
+ soap_ctx_new_with_method(urn, method, &ctx);
- SoapRouter *router;
+ /* 3. Fill the envelope */
+ soap_env_add_item(ctx->env, "xsd:string", "name", "Jonny B. Good");
- <callout arearefs="ex.server.init"/> if (!soap_server_init_args(argc, argv)) {
- return 0;
+ /* 4. Invoke */
+ soap_client_invoke(ctx, &ctx2, url, "");
+ if (err != H_OK) {
+
+ log_error4("[%d] %s(): %s ",
+ herror_code(err),
+ herror_func(err),
+ herror_message(err));
+
+ herror_release(err);
+ soap_ctx_free(ctx);
+ return 1;
}
-
- <callout arearefs="ex.server.newrouter"/> router = soap_router_new();
- <callout arearefs="ex.server.regservice"/> soap_router_register_service(router, say_hello, "sayHello", "urn:examples");
- <callout arearefs="ex.server.regrouter"/> soap_server_register_router(router, "/csoapserver");
+ /* 5. Process returned SoapCtx object */
+ soap_xml_doc_print(ctx2->env->root->doc);
- <callout arearefs="ex.server.run"/> soap_server_run();
- <callout arearefs="ex.server.freerouter"/> soap_router_free(router);
- <callout arearefs="ex.server.destroy"/> soap_server_destroy();
+ /* 6. Clean up cSOAP client */
+ soap_ctx_free(ctx2);
+ soap_ctx_free(ctx);
+
+ soap_client_destroy();
return 0;
}
+]]>
</programlisting>
+</example>
+<note>
+ Important: Note that we have omitted error handling. The complete
+code can be found under examples/csoap/simpleclient.c
+</note>
+
+</section>
-<calloutlist>
+<section>
+<title>Implementing a simple server</title>
-<callout arearefs="ex.server.init">
<para>
-Init server with commandline arguments. The init argument at this time is only
-<varname> -NHTTPport <portnum> </varname>.
+ Before you start to implement a SOAP server, you must understand
+the architecture how you publish you web service .
</para>
-</callout>
-<callout arearefs="ex.server.newrouter">
-<para>Create a router</para>
-</callout>
+<synopsis>
+ * Each URL represent a router service.
+ * Each router service contains one or more user services.
+ * Each user service is a C function with the following signature:
+
+ typedef herror_t (*SoapServiceFunc)(SoapCtx*, SoapCtx*);
+</synopsis>
-<callout arearefs="ex.server.regservice">
<para>
- Register the service function <function>say_hello</function> under the methodname <quote>sayHello</quote> a
- and urn <quote>urn:examples</quote> at the router object <varname>router</varname>.
+ The first SoapCtx object is the request, the second SoapCtx object
+is the response, which must be filled by the service function
+"SoapServiceFunc". The function must return H_OK if success.
</para>
-</callout>
-<callout arearefs="ex.server.regrouter">
-<para>Register the router under the context <quote>/csoapserver</quote>.
-Now your service is avaiable at the address <quote>http://localhost:port/csoapserver</quote>.
+<para>
+The steps to implement a SOAP server described below:
</para>
+
+<synopsis>
+1. Init cSOAP server
+2. Create and register a router
+3. Register you service (C function)
+4. Enter server loop
+5. Clean up cSOAP server
+</synopsis>
+
+
+<para>
+The above steps can be shown in the the following example:
+</para>
+
+
+<example>
+<programlisting><![CDATA[
+
+herror_t say_hello(SoapCtx *req, SoapCtx* res)
+{
+ printf("Returning empty envelope\n");
+ soap_env_new_with_response(req->env, &res->env);
+ return H_OK;
+}
+
+
+int main(int argc, char *argv[])
+{
+
+ herror_t err;
+ SoapRouter *router;
+
+ /* 1. Init cSOAP server */
+ soap_server_init_args(argc, argv);
+
+ /* 2. Create and register a router */
+ router = soap_router_new();
+ soap_server_register_router(router, url);
+
+ /* 3. Register you service (C function) */
+ soap_router_register_service(router, say_hello, method, urn);
+
+ /* 4. Enter server loop */
+ soap_server_run();
+
+ /* 5. Clean up cSOAP server */
+ soap_server_destroy();
+
+ return 0;
+}
+]]></programlisting>
+</example>
+
+<para>
+ You can see how to implement a soap server easily!
+</para>
+
<note>
-Default http port is 10000
+ Important: Note that we have omitted error handling. The complete
+code can be found under examples/csoap/simpleserver.c
</note>
-</callout>
-<callout arearefs="ex.server.run">
+</section>
+
+<section>
+<title>Implementing a simple client with attachment</title>
+
<para>
- Enter the http server loop. after calling <function>soap_server_run()</function> ,
- the application will enter the http server (nanohttp) loop.
+ File are added to the context using soap_ctx_add_file().
+ The following example is a little bit modified version of the above
+simpleclient example.
</para>
-</callout>
-<callout arearefs="ex.server.freerouter">
+
+<example>
+<programlisting><![CDATA[
+int main(int argc, char *argv[])
+{
+ SoapCtx *ctx, *ctx2;
+ char href[MAX_HREF_SIZE];
+ xmlNodePtr fault;
+
+ /* Initialize soap client */
+ soap_client_init_args(argc, argv);
+
+ /* Create a context object */
+ soap_ctx_new_with_method(urn, method, &ctx);
+
+ /* Add file to the context */
+ soap_ctx_add_file(ctx, argv[1], "application/octet-stream", href);
+
+ /* Add file reference to the envelope */
+ soap_env_add_attachment(ctx->env,"source", href);
+
+ /* Send soap request to the server */
+ soap_client_invoke(ctx, &ctx2, url, "");
+
+ /* Handle response (just print to the screen) */
+ fault = soap_env_get_fault(ctx2->env);
+ if (fault) {
+ ...
+ } else {
+ ...
+ }
+
+ /* Clean up */
+ soap_ctx_free(ctx2);
+ soap_ctx_free(ctx);
+
+ soap_client_destroy();
+
+ return 0;
+}
+
+]]></programlisting>
+</example>
+
<para>
- Free the router.
+The difference between soap_ctx_add_file() and soap_env_add_attachment()
+is, that soap_ctx_add_file() adds the file to the context. In our case,
+this is a MIME message. soap_ctx_add_file() fills the "href" field with
+a generated reference id. (Content-ID: [href]) This id can be used to
+point to the added file from a SOAP message using soap_env_add_attachment().
</para>
-</callout>
-<callout arearefs="ex.server.destroy">
<para>
- Destroy and free soap server stuff.
+Here a simple example to understand. Look at the following MIME message:
</para>
-</callout>
-</calloutlist>
+<example>
+<programlisting><![CDATA[
+
+POST /csoapsever HTTP/1.1
+Content-type: multipart/related; boundary="--.Part1234" ...
+
+----.Part1234
+<SOAP-ENV:Envelope ...>
+ <SOAP-ENV:Body ...>
+ <m:echo xmlns:m="urn:example">
+ <source href="cid:12345abcdef/>
+ </m:echo>
+ </SOAP-ENV:Body>
+</SOAP-ENV:Envelope>
+
+----.Part1234
+Content-type: apptication/octet-stream
+Content-ID: <12345abcdef>
-</programlistingco>
+binary data ...
+
+----.Part1234--
+
+]]></programlisting>
</example>
+<para>
+soap_env_add_attachment() will produce the following xml tag:
+</para>
+
+<synopsis>
+<![CDATA[
+ <source href="cid:12345abcdef/>
+]]>
+</synopsis>
+
+
</section>
<section>
-<title>Compiling SOAP applications</title>
+<title>Implementing a simple server with attachment</title>
+
<para>
- <emphasis>csoap</emphasis> has <emphasis>pkg-config</emphasis> support. So you can can use
-<emphasis>pkg-config</emphasis> with <quote>libcsoap</quote> parameter.
+ Attachments are represented as an "attachments_t" object. An
+"attachments_t" object is a list of parts. A part is the physical file
+on the filesystem.
</para>
-<example>
-<title>An example Makefile</title>
+<synopsis>
+typedef struct _attachments
+{
+ part_t *parts;
+ part_t *last;
+ part_t *root_part;
+}attachments_t;
+</synopsis>
-<programlisting>
-<![CDATA[
-SHELL = bash
-CFLAGS = `pkg-config --cflags libcsoap`
-LDFLAGS = `pkg-config --libs libcsoap`
-
-CLIENTOBJECTS = simpleclient.o
-SERVEROBJECTS = simpleserver.o
-
-simpleclient: $(CLIENTOBJECTS)
- $(CC) -o $@ $< $(LDFLAGS)
+<para>
+ You don't have to care about this object becaus it is a part of
+SoapCtx.
+</para>
-simpleserver: $(SERVEROBJECTS)
- $(CC) -o $@ $< $(LDFLAGS)
+<synopsis>
+typedef struct _SoapCtx
+{
+ SoapEnv *env;
+ attachments_t *attachments;
+}SoapCtx;
+</synopsis>
-]]>
-</programlisting>
+<para>
+The following example shows how to use attachment in a service function
+(C function).
+</para>
+
+
+<example>
+<programlisting><![CDATA[
+herror_t echo_attachments(SoapCtx *req, SoapCtx* res)
+{
+ herror_t err;
+
+ part_t *part;
+ char href[MAX_HREF_SIZE];
+
+ err = soap_env_new_with_response(req->env, &res->env);
+ if (err != H_OK) {
+ return err;
+ }
+
+ if (req->attachments)
+ {
+ for (part = req->attachments->parts; part != NULL; part = part->next)
+ {
+ soap_ctx_add_file(res, part->filename, part->content_type, href);
+ soap_env_add_attachment(res->env, "echoFile", href);
+ }
+ }
+
+ return H_OK;
+}
+]]></programlisting>
</example>
</section>
-
<section>
-<title>Building XML tree using libxml2 API</title>
+<title>Building an envelope using the libxml2 API</title>
<para>
-One of the ways building a xml tree into an
-SOAP envelope is to use directly the libxml2 API.
-You can obtain the xmlNodePtr of an envelope
-with the SoapEnv structure.
+One of the ways building a xml tree into an SOAP envelope is to use
+directly the libxml2 API. You can obtain the xmlNodePtr of an envelope
+using the SoapEnv structure.
</para>
<synopsis>
@@ -306,13 +510,13 @@ typedef struct _SoapEnv </synopsis>
<para>
-Here is "root" your xml node to <SOAP-ENV:Envelope>.
+Here is "root" your xml node to <![CDATA[ <SOAP-ENV:Envelope> ]]>.
</para>
</section>
<section>
-<title>Building XML tree using csoap</title>
+<title>Building an envelope using envelope functions</title>
<para>
You can build a xml tree using following functions
@@ -322,26 +526,32 @@ You can build a xml tree using following functions xmlNodePtr
soap_env_add_item(SoapEnv* env, const char *type,
const char *name, const char *value);
+
xmlNodePtr
soap_env_add_itemf(SoapEnv* env, const char *type,
const char *name, const char *value, ...);
+
xmlNodePtr
soap_env_push_item(SoapEnv *env, const char *type,
const char *name);
+
void
soap_env_pop_item(SoapEnv* env);
</synopsis>
<para>
-soap_env_add_itemf() does the same thing like soap_env_add_item()
+soap_env_add_itemf() does the same thing like soap_env_add_item()
but with a C style argument list. (Max buffer for value is 1054)
</para>
+<para>
+The next example shows, how to use the stack pattern of cSOAP.
+</para>
+
<example>
-<title>Building xml using csoap stack pattern</title>
-<programlisting>
-<![CDATA[
-SoapEnv *env = soap_env_new_with_method("urn:examples", "CreateUser");
+<programlisting><![CDATA[
+
+SoapEnv *env = ctx->env;
soap_env_push_item(env, "my:user", "User");
soap_env_add_item(env, "xsd:string", "id", "09189");
@@ -352,19 +562,18 @@ soap_env_push_item(env, "my:user", "User"); soap_env_add_item(env, "xsd:string", "name", "snowdrop");
soap_env_add_item(env, "xsd:string", "passwd", "passphrase64");
soap_env_pop_item(env);
-]]>
-</programlisting>
+
+]]></programlisting>
</example>
+
<para>
This will create the following xml structure
</para>
-<example>
-<title>Generated SOAP envelope</title>
-<programlisting>
-<![CDATA[
+<example>
+<programlisting><![CDATA[
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema"
@@ -386,13 +595,9 @@ This will create the following xml structure </SOAP-ENV:Envelope>
-]]>
-</programlisting>
-
+]]></programlisting>
</example>
-
</section>
-
</article>
|