<!-- ** http server and client functions

     $Id: sect_http_client_server.docbook 801 2005-07-17 12:56:42Z ewald-arnold $
-->

<sect1 id="http-client-server">
<title>Talking &http;</title>

<para>Another, more flexible possibility is it, to set up a simple web server,
that handles complete &http; transactions. As a side effect it does not only
handle XML-RPC requests but also passes data to or from a web browser or deletes
files which is also part of the HTTP standard.</para>

<sect2 id="http-server">
<title>The Server</title>

<para>

<programlisting>

  TcpIpConnection conn (0x7f000001, 80);  <co id="http-server-co" linkends="http-server-link" />
  HttpProtocol prot(&amp;conn, conn);
  HttpServer http_server (&amp;prot);

  Dispatcher rpc_server(&amp;conn); <co id="http-server-rpc-co" linkends="http-server-rpc-link" />
  http_server.setRpcDispatcher(&amp;rpc_server); <co id="http-server-rpc2-co" linkends="http-server-rpc2-link" />
  http_server.setHttpRoot("/http-directory/public_html");  <co id="http-server-root-co" linkends="http-server-root-link" />

  rpc_server.addMethod(&amp;testcall,  <co id="http-server-method-co" linkends="http-server-method-link" />
                        "struct",
                        "testcall",
                        "int, int"
                        "Testcase with a c-function");

  http_server.runPicoHttpd(); <co id="http-server-run-co" linkends="http-server-run-link" />

</programlisting>

<calloutlist>

 <callout arearefs="http-server-co" id="http-server-link">
  <para>Accept connections to <emphasis>localhost</emphasis> on port
  80 (web browser access).</para>
 </callout>

 <callout arearefs="http-server-rpc-co" id="http-server-rpc-link">
  <para>Set up an &xmlrpc; dispatcher.</para>
 </callout>

 <callout arearefs="http-server-rpc2-co" id="http-server-rpc2-link">
  <para>Let the &http; server know about the rpc-dispatcher.</para>
 </callout>

 <callout arearefs="http-server-root-co" id="http-server-root-link">
  <para>This the internal root of the &http; server.</para>
 </callout>

 <callout arearefs="http-server-method-co" id="http-server-method-link">
  <para>Add a method including signature for parameters and description.</para>
 </callout>

 <callout arearefs="http-server-run-co" id="http-server-run-link">
  <para>Run forever ...</para>
 </callout>

</calloutlist>

</para>

</sect2>

<sect2 id="http-client">
<title>The Client</title>

<para>The client finally may access the server via the &http; protocol to store,
retrieve and delete files. At the same time it might of course send &xmlrpc;
requests.

<programlisting>

  TcpIpConnection conn ("localhost", 32000); <co id="http-client-co" linkends="http-client-link" />
  HttpProtocol prot(&amp;conn);
  HttpClient client(&amp;prot);

  string s = client.msgGET("/index.html"); <co id="http-client-get-co" linkends="http-client-get-link" />
  client.msgPUT("hello put", "text/plain", "/putmsg.txt");  <co id="http-client-put-co" linkends="http-client-put-link" />
  client.doDELETE("/putmsg.txt");  <co id="http-client-delete-co" linkends="http-client-delete-link" />

</programlisting>

<calloutlist>

 <callout arearefs="http-client-co" id="http-client-link">
  <para>Create a connection to <emphasis>localhost</emphasis> on port
  32000.</para>
 </callout>

 <callout arearefs="http-client-get-co" id="http-client-get-link">
  <para>Simulate a web browser and get an html file.</para>
 </callout>

 <callout arearefs="http-client-put-co" id="http-client-put-link">
  <para>Store a string as a file on the server.</para>
 </callout>

 <callout arearefs="http-client-delete-co" id="http-client-delete-link">
  <para>Delete a remote file.</para>
 </callout>

</calloutlist>

</para>

</sect2>

<sect2 id="processing-html">
<title>Processing HTML Requests</title>

<para>The default implementation of the &http; server class only handles requests
to existing files below the &http; root directory. This means that only static
content on the hard disk can be processed.</para>

<para>But often you must process virtual content which is derived from volatile
data in the memory of some application. You can extend the functionality in
several ways. One of them might be to derive a new class and handle everything
"manually".</para>

<para>But instead of this you should use the helper classes that come with
&ulxmlrpcpp;: handlers for &http; requests and for processing form data and
html content.</para>

</sect2>handbook/index.html

<sect2 id="http-handlers">
<title>HTTP Handlers</title>

<para>There are several types of requests you can send to a &http; server. The
most common ones are the following.

<variablelist>
 <varlistentry>
  <term>PUT</term>
  <listitem>send some data to a server</listitem>
 </varlistentry>

 <varlistentry>
  <term>GET</term>
  <listitem>query data from a server</listitem>
 </varlistentry>

 <varlistentry>
  <term>POST</term>
  <listitem>a requests that modifies and afterwards returns data
  (more or less a combination of PUT and GET)</listitem>
 </varlistentry>

 <varlistentry>
  <term>DELETE</term>
  <listitem>delete some remote data</listitem>
 </varlistentry>

</variablelist>

</para>

<para>You can add handlers for each of these methods to a &http; server object.
Each handler is usually responsible for a master resource. You can think of a
master resource as some sort of directory. Each master resource contains one
or more subresources which are similar to files.

<programlisting>

  class RpcInfoHandler : public HtmlFormHandler
  {
     RpcInfoHandler()
       : HtmlFormHandler("/rpc-info/") <co id="handler-co" linkends="handler-link" />
     {
       addSubResource("",           this, &amp;RpcInfoHandler::handle_index); <co id="handler-subres-co" linkends="handler-subres-link" />
       addSubResource("index.html", this, &amp;RpcInfoHandler::handle_index);
     }

     CppString handle_index(const HtmlFormData &amp;formdata,
                            CppString &amp;mimetype)
     {
       mimetype = "text/html";  <co id="handler-mime-co" linkends="handler-mime-link" />

       return data_for_index;   <co id="handler-return-co" linkends="handler-return-link" />
     }
  };

 ...

 http_server.addHttpHandler("get",   <co id="handler-add-co" linkends="handler-add-link" />
                            make_methodhandler(rpcinfo,
                                               &amp;RpcInfoHandler::handler));

</programlisting>

<calloutlist>

 <callout arearefs="handler-co" id="handler-link">
  <para>Create a handler for resources below "/rpc-info/".</para>
 </callout>

 <callout arearefs="handler-subres-co" id="handler-subres-link">
  <para>Add subresources for several names which are routed to member
  methods.</para>
 </callout>

 <callout arearefs="handler-mime-co" id="handler-mime-link">
  <para>Set mime type for returned data.</para>
 </callout>

 <callout arearefs="handler-return-co" id="handler-return-link">
  <para>Return the data that belongs to this resource.</para>
 </callout>

 <callout arearefs="handler-add-co" id="handler-add-link">
  <para>Add a handler for requests to the above html resource.</para>
 </callout>

</calloutlist>

</para>

</sect2>

<sect2 id="cached-resources">
<title>Cached Resources</title>

<para>Sometimes a &http; server provides resources which are not actually
real files but only a represenation of an internal state. In case such a resource
does not change often you may use <classname>CachedResource</classname>. The data is
accessed in a fashion similar to streams.</para>

<para>There is an extension of this caching class called <classname>FileResource</classname>.
This class reads a file when creating
the cache object and writes the potentially changed data back to the file when
the object is destroyed.</para>

</sect2>


<sect2 id="processing-html-data">
<title>Processing HTML Data</title>

<para>Dealing with html files is often an error prone task. The helper class
contains methods to generate the most common html sequences for anchors, forms
and more.

<programlisting>

  resp = getHeader("Index"); <co id="processing-co" linkends="processing-link" />
  resp += makeCheckBox(makeIdent("method_enable_", i), <co id="processing-append-co" linkends="processing-append-link" />
                       "on",
                       meth-&gt;isEnabled());
  resp += getTail(); <co id="processing-tail-co" linkends="processing-tail-link" />

</programlisting>

<calloutlist>

 <callout arearefs="processing-co" id="processing-link">
  <para>Create a standard html start sequence.</para>
 </callout>

 <callout arearefs="processing-append-co" id="processing-append-link">
  <para>Append a check box with unique name and according value.</para>
 </callout>

 <callout arearefs="processing-tail-co" id="processing-tail-link">
  <para>Append the standard html tail sequence.</para>
 </callout>

</calloutlist>

</para>

<para>
When you process the form data you have to extract the according values.
This may happen in the following manner:

<programlisting>

  CppString handle_calc(const HtmlFormData &amp;formdata,
                        CppString &amp;mimetype)
  {
    mimetype = "text/html";

    if (   formdata.size() != 0
        &amp;&amp; formdata.hasElement("lhs")  <co id="handling-co" linkends="handling-link" />
        &amp;&amp; formdata.hasElement("rhs")
        &amp;&amp; formdata.hasElement("operator")
       )
    {
      int l = getLong(formdata.getElement("lhs")[0]); <co id="handling-extract-co" linkends="handling-extract-link" />
      int r = getLong(formdata.getElement("rhs")[0]);

      ...
    }

    return calc_response(); <co id="handling-reponse-co" linkends="handling-reponse-link" />
  }

</programlisting>

<calloutlist>

 <callout arearefs="handling-co" id="handling-link">
  <para>Check for existing and complete form data.</para>
 </callout>

 <callout arearefs="handling-extract-co" id="handling-extract-link">
  <para>Extract the values and process them as required.</para>
 </callout>

 <callout arearefs="handling-reponse-co" id="handling-reponse-link">
  <para>Generate the response based on the current data.</para>
 </callout>

</calloutlist>

</para>

</sect2>

</sect1>

