micro-server/dmbcs-micro-server.texi
Dale Mellor a739007e23 Genesis.
2020-03-23 15:33:18 +00:00

876 lines
33 KiB
Text

\input texinfo
@setfilename dmbcs-micro-server.info
@include version.texi
@settitle The dmbcs-micro-server Library Reference Manual
@syncodeindex tp fn
@syncodeindex pg fn
@copying
This is the reference manual for the dmbcs-micro-server C++ library
(version @value{VERSION}, @value{UPDATED}).
Copyright @copyright{} 2018 Dale Mellor
@quotation
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version. The text of the license can be found in the
section entitled ``Copying''.
@end quotation
@end copying
@dircategory Libraries
@direntry
* dmbcs-micro-server: (dmbcs-micro-server). C++ CGI utility library.
@end direntry
@setchapternewpage odd
@titlepage
@title The DMBCS micro-server Library Reference Manual
@subtitle Version @value{VERSION}
@subtitle @value{UPDATED}
@author Dale Mellor
@page
@vskip 0pt plus 1filll
@insertcopying
@end titlepage
@node Top
@summarycontents
@contents
@page
@ifnottex
@top The micro-server Library
@insertcopying
@end ifnottex
@menu
* Introduction::
* Using the library::
* Reference::
* Examples of Use::
* Hints on how the library might be used in a real application::
@detailmenu
--- The Detailed Node Listing ---
Introduction
* HTTP Web Services::
* Our Choice of Name::
* Your Choice of Library::
* Outline of Library:: An overview of the library's implementation
Using the library
Reference
* The utility functions::
* The Query_String class::
* The Hyper_Tags class::
* The Http_Server class::
The Query_String class
* MACs::
* Constructors::
* Methods::
* Functions::
The Hyper_Tags class
* Constructors_::
* Methods_::
* Functions_::
The Http_Server class
* Constructor__::
* Functions__::
Examples of Use
* Simple example -- Online multiplier:: A simple application of the library
Hints on how the library might be used in a real application
* Web-site skins:: Web sites which provide a user-selected `look-and-feel'
* Other inheritence:: Other ideas
@end detailmenu
@end menu
@node Introduction, Using the library, Top, Top
@chapter Introduction
This document introduces, defines and exemplifies use of the
dmbcs-micro-server C++ library, providing services to applications for
processing and responding to requests from a web browser, including the
possibility of making the application a stand-alone web server in its
own right (a `micro-server').
@menu
* HTTP Web Services:: Introduction to CGI and web servers
* Our Choice of Name:: Use of `DMBCS'
* Your Choice of Library:: Some gentle advice
* Outline of Library:: An overview of the library's implementation
@end menu
@node HTTP Web Services, Our Choice of Name, Introduction, Introduction
@section HTTP Web Services
A CGI program is a program, written in any language, which conforms to
the Common Gateway Interface (CGI). It is a program executed by a web
server (on the server machine), and is passed information about the
request from the user through the UNIX environment. It is left to the
program to interpret the user's requirements and to produce on its
standard output channel a HTML document which the web server will
relay back to the user's browser for display on his console.
CGI programs are thus very flexible and amenable to lots of jobs.
Some of them are very small, amounting to only a couple of lines of an
interpreted language to slurp a file from the local storage and send
it straight back to the browser (which is essentially what a web
server would normally do but this allows the programmer to do so in a
more customized way). On the other hand, some CGI programs are
extremely large consisting of hundreds of thousands of lines of code
which may interact with a database and other third-party systems (such
as payment gateways) and do some real work on behalf of the user,
before sending the results of the transactions along for the user's
perusal.
This project came from a CGI program of the latter description. Because
of its size, complexity and the anticipated load (number of users), it
was decided very early on that it would be written in a proper
programming language which could be compiled optimized to run on the
bare metal of the available computer system, whatever that is. Thus it
would have to be C or C++. While the original implementation had been
in C for political reasons, it has since been ported to the more
convenient C++. As a side-effect of this development, the parts of the
system which deal specifically with the business of being a CGI program
have been abstracted and encapsulated, and then they were syphoned off
into their own separate library; this was further extended to provide
the functions of a self-contained web server. This is now being offered
for general use.
The result is a library which can be used to inject a self-contained web
server into an arbitrary C++ code base, opening up the interface to such
a legacy program to the modern world, without needing to also build the
infrastructure to serve such a program to the public (although in
practice infrastructure needs to be built for other reasons---like
security and virtualization---but the self-contained scheme allows for
greater flexibility and better functional isolation).
@node Our Choice of Name, Your Choice of Library, HTTP Web Services, Introduction
@section Our Choice of Name
The micro-server library was written from scratch since 2004 as part of
a large internet project. The requirement for a C++ framework for
undertaking this task is very common, and thus it is no surprise that
other efforts already exist, notably the GNU cgicc project.
Some consideration was given to the name of this project. At first it
was going to be called cgicc2, but that carries the implication that
it somehow carries on from the GNU cgicc project, and that it is both
a development and enhancement of it. This is definitely not the case,
but a parallel development, completely different but solving the same
problems. Unfortunately appending any number or even letter carries
some implication of sequencing, and if the two projects continue (as
they should) to be developed then some imbalance would occur in the
rivalry. Such is definitely not the intention, but for the two
projects to be seen as separate. Choice of one or other framework for
any particular project should be based on what the framework offers,
not what letters happen to come in its name.
Thus it is decided to mark this particular library with the string
'DMBCS': all code appears inside the namespace 'DMBCS::Micro_Server' and
the include file is called 'dmbcs-micro-server.h'; the project is
formally known as the 'dmbcs-micro-server' C++ library.
@node Your Choice of Library, Outline of Library, Our Choice of Name, Introduction
@section Your Choice of Library
We offer only this advice: look at the API provided by all the available
libraries, and consider the nature of the working framework (paradigm)
that that implies; choose the library that seems most appropriate for
your project: the one that you will feel most comfortable working with.
@node Outline of Library, , Your Choice of Library, Introduction
@section Outline of Library
The library consists of a high-level wrapper and two workhorse classes.
@code{Http_Server} interfaces with multiple clients and delegates
processing of their requests to registered callback functions, which
make direct use of the following workhorses. @code{Query_String} looks
after the part of the CGI interface which passes from the browser to the
CGI program and provides methods specifically for interpreting the
arguments from the browser's query string, and @code{Hyper_Tags} looks
after the part of the CGI interface which passes back from the CGI
program to the browser, and displays the results of the user's request;
this deals with updating template HTML files with some dynamic content
before passing the result to the web server for eventual transmission to
the browser.
@node Using the library
@chapter Using the library
To re-iterate: all code in this library comes in the namespace
'DMBCS::Micro_Server' and the header which introduces all of the
functionality is 'dmbcs-micro-server.h'.
A project would generally consist of a template HTML file with markers
where dynamically-generated content needs to be placed, a .css file
which should be injected into the file or provided by the server as an
inclusion target in the HTML, a .js file containing code that should run
client-side to implement part of the functionality of the web site, and
a (micro-) web server which runs continually, listens for client
connections, and provides generated HTML files and JSON data strings on
demand of the client.
@menu
@end menu
@node Reference, Examples of Use, Using the library, Top
@chapter Reference
@menu
* The utility functions:: Useful functions needed by web applications
* The Query_String class:: For processing the user's arguments
* The Hyper_Tags class:: For substituting dynamic content into HTML
* The Http_Server class:: To implement a micro-server in your own app
@end menu
@node The utility functions, The Query_String class, Reference, Reference
@section The utility functions
Introductory text here.
@deftypefun string slurp_file_with_error (const std::string &@var{file_name}) throw (Slurp_Error)
This function will attempt to open the file named file_name (which may
be a complete path to the file), and read the whole lot into a string.
If any errors occur in the process, a Slurp_Error object will be thrown
(these exception objects do not convey any information back to the
application).
@end deftypefun
@deftypefun string slurp_file (const std::string &@var{file_name})
This function will attempt to open file @var{file_name} (which may be a
full path), and will slurp the entire contents (which are presumably a
hyper-tag'd template file) into a string. If any errors occur, an empty
string will be produced, and a message printed on the standard error
channel to indicate the name of the file which has failed.
In the majority of applications of this function, in the majority of
calls, the error condition thrown from the function above will not
happen; it would be regarded as an infrastructure build problem rather
than a run-time error if a known file were not accessible. Thus it is
wasteful to worry about and deal with the error at global level--outside
the library--, rather let the program carry on and provide a message to
the user's console about the missing file (the fact that the problem
occurred will be obvious!) Once it is known which file has failed, the
remedy will be equally obvious.
@end deftypefun
@deftypefun string htmlize_quotes (string && @var{input})
Any occurrence of `` in @var{input} will be replaced by `@code{&quot};'
@end deftypefun
@deftypefun string htmlize (string && @var{input})
All occurrences of HTML-special characters (<>&") will be replaced with
entity representations.
The main purpose of this method is to alleviate the possibility of
injection attacks into a web-site; if any part of a page is generated
from user-supplied input there is the danger that the user might be
savvy enough to get JavaScript to execute there! But the function is
quite generally useful when it is known that a string needs to appear
verbatim in a web page, regardless of its contents, and thus ought to be
used whenever a string is added to a set of @code{Hyper_Tag}s.
@end deftypefun
@deftypefun string strip_leading_space (string && @var{input})
Replace all sequences of white space at the start of all lines with a
single space character.
HTML recognizes all sequences of white space outside of quotes as a
single space separator. Thus sequences of white space at the
beginning of lines (which are used by web programmers to give a nice
aesthetic indentation) are a waste of bandwidth. This function will
remove all such occurrences from @var{input}.
@end deftypefun
@deftypefun string escape_quotes (string @var{input})
Replace all occurrences of quotation marks and escapes with escaped
versions, where the escape character is the back-slash.
This function will put an escape ('\') in front of ''', '''', or '\'
which occur in @var{input}, and is useful (essential when dealing with
user-supplied input) to ensure that strings do not mess up SQL
statements.
@end deftypefun
@deftypefun string decode_url (string @var{url})
This function will replace '+' with ' ', and any %-escaped character
codes in the @var{url} with the ASCII equivalent.
This will produce a plain string, decoded from strings passed from forms
or EcmaScript on web pages passed through parameter lists in URI's, as
provided within the context of this library by the @code{Query_String}
object.
@end deftypefun
@deftypefun string hexalize (unsigned char const *const @var{buffer}, size_t const @var{buffer_size})
Return an ASCII string containing the hexadecimal representation of the
octets in the given @var{buffer}. The @var{buffer_size} is the number of
octets to decode.
@end deftypefun
@deftypefun string getenv (string const & @var{env})
Return the value of the environment variable called @var{env}, or an
empty string if the variable does not exist in the environment.
This is a convenience wrapper around the system @code{getenv} call,
adapting it to the use of strings.
@end deftypefun
@node The Query_String class
@section The Query_String class
A Query_String object is a std::map<std::string, std::string> object
in which the keys are the variables passed in the URL query string
part and the values are the values from that query string. Methods
are defined which interrogate the class in details more specific to
the CGI problem, and allow for values to be extracted in either string
or a numeric form, as expected by the CGI program.
@menu
* MACs::
* Constructors::
* Methods::
* Functions::
@end menu
@node MACs, Constructors, The Query_String class, The Query_String class
@subsection MACs
@node Constructors
@subsection Constructors
@deftp {Constructor} Query_String ()
The null constructor, only useful if you are intending to build up a
new query string for eventual inclusion into some part of a HTML page.
@end deftp
@deftp {Constructor} Query_String (const char *const *const @var{env})
The real workhorse constructor. The argument @var{env} should be the
environment variable passed to the CGI's main routine as the third
argument. This will create an object which represents the information
passed to the CGI program via the query string, whether it were sent
via the GET or the PUT protocols. The object returned can
subsequently be used to interrogate the user's request string.
@end deftp
@node Methods
@subsection Methods
@deftp {Method} void Query_String::add (const std::string &@var{name}, const T &@var{value})
This method will add an entry into the Query_String with key
@var{name} and value a string representation of @var{value}. The type
T of @var{value} may be anything that can be passed into a
std::ostream object via the << operator.
@end deftp
@deftp {Method} void Query_String::add (const std::string &@var{name}, const Query_String &@var{input}, const T &@var{fallback})
This method will add an entry into the current Query_String which is a
copy of the entry in the @var{input} Query_String, unless such entry
does not exist in which case a key @var{name} with value a std::string
representation of @var{fallback} will be added to the current
Query_String. The type T of @var{fallback} may be anything that can
be passed to the << operator of a std::ostream object.
@end deftp
@deftp {Method} bool Query_String::posted () const
Returns TRUE if the query string had been sent to the CGI program via
the POST protocol, FALSE otherwise (which case would presumably have
been caused by use of the GET protocol).
@end deftp
@deftp {Method} T Query_String::get (const std::string &name, const T &fallback) const
This gets the value associated with the key @var{name} from the query
string, unless no such key was present in which case @var{fallback} is
returned. Note that the type of value returned is the same as that of
@var{fallback}, thus @var{fallback} serves the dual role of defining
the fallback value and determining the return type of the function.
@end deftp
@deftp {Method} std::vector <int> Query_String::get_list (const std::string &name) const
In the case that a query string value corresponds to a multiple choice
selection on the HTML form, it will be a comma-separated string of
selected values. This function will return a vector comprised of
these values, interpreted as integers. If there is no key @var{name}
in the query string, then the returned vector will have no elements
(zero length).
@end deftp
@deftp {Method} std::vector <int> Query_String::get_checked_array (const std::string &NAME) const
@end deftp
@deftp {Method} bool Query_String::has (const std::string &NAME) const
This method returns TRUE if the @var{name} was a variable present in
the query string, FALSE otherwise.
@end deftp
@deftp {Method} bool Query_String::mac_verified () const
This method will return TRUE only if there was a MAC present in the
query string, and the MAC was valid. Otherwise FALSE will be
returned.
@end deftp
@node Functions
@subsection Functions
@deftypefun static string Query_String::add_mac (string @var{input})
This static class member will add a cryptographic MAC onto any string,
but this is only meaningful for composed query strings.
@end deftypefun
@node The Hyper_Tags class
@section The Hyper_Tags class
Whereas a HTML document contains markup tags expressed as labels between
angle brackets (possibly in pairs), so a micro-server template file
contains dynamic content holders expressed as labels between square
brackets. The Hyper_Tags class contains methods for replacing single
tags with some dynamically-generated content, and for selectively
keeping or removing sections of the template bracketed between pairs of
hyper tags.
A Hyper_Tags object should be considered a container of tag
definitions. The CGI program will typically build up a list of such
definitions in the container, until all the work is done when the
template file is read in from local storage and the Hyper_Tags object
is instructed to make all the changes in one go before sending the
result to the server and hence to the user's browser.
@menu
* Constructors_::
* Methods_::
* Functions_::
@end menu
@node Constructors_, , The Hyper_Tags class, The Hyper_Tags class
@subsection Constructors_
@deftp {Constructor} Hyper_Tags ()
The class only has the one, default, constructor, which returns an
empty object waiting to be filled with tag definitions.
@end deftp
@node Methods_, , Constructors_, The Hyper_Tags class
@subsection Methods_
@deftp {Method} void Hyper_Tags::harden_last ()
Normally, a later tag definition would overrule any earlier ones when
substitutions are finally made into a template file. However, if it
is desired that the last tag added should be the final tag definition
on substitution, then it can be `hardened' by calling this method.
@end deftp
@deftp {Method} bool Hyper_Tags::has (const std::string &@var{name}) const
This method returns TRUE if a tag with the given @var{name} has been
registered with the Hyper_Tags object. In all other cases it returns FALSE.
@end deftp
@deftp {Method} Hyper_Tags &Hyper_Tags::add (const Hyper_Tags &@var{registry}, const int @var{harden} = 0)
This method copies all the tag definitions contained in @var{registry}
into the current object, and returns a reference to the current
object. If the optional @var{harden} argument is passed a non-zero
value, then all the incumbent tag definitions will be hardened, as per
the discussion of the harden_last () method above.
@end deftp
@deftp {Method} Hyper_Tags &Hyper_Tags::add (const std::string &@var{name}, string @var{substitution_text})
One of the main methods of the class. Declares that, in the final
substitutions, any parts of the template file which look like
``[@var{name}/]'' should be replaced with @var{substitution_text}.
The return is a reference to the current object.
@end deftp
@deftp {Method} Hyper_Tags &Hyper_Tags::add (const std::string &@var{name}, const int value)
Declares that tags called @var{name} in the template file be replaced
with a string representing the integer @var{value}. The return is a
reference to the current object.
@end deftp
@deftp {Method} Hyper_Tags &Hyper_Tags::add (const std::string &@var{name}, const double @var{value}, const int @var{precision} = 4)
Declares that tags called @var{name} be replaced with a string
representing the floating-point @var{value}, with at least
@var{precision} significant figures. The return is a reference to the
current object.
@end deftp
@deftp {Method} Hyper_Tags &add (const std::string &@var{name}, Query_String &@var{q_s}, const T &@var{fallback})
Declares that tags called @var{name} be replaced with a value from
@var{q_s} with the same name if this exists, or with @var{fallback}
otherwise. The type T of fallback should be one of std::string, int,
or double. The return is a reference to the current object.
@end deftp
@deftp {Method} void add_int_list (const std::string &@var{name}, I @var{begin}, I @var{end})
Here, I is an iterator type over an STL container of int's. This
method declares that tags named @var{name} be substituted with a
comma-separated list of integer values.
@end deftp
@deftp {Method} void add_date (const std::string &@var{name}, const time_t &@var{time}, const std::string &@var{format})
Specifies that tags named @var{name} be replaced with a string
representing the date indicated by the UNIX @var{time} object. The
conversion takes place according to @var{format}, which is described
in the strftime () libc manual.
@end deftp
@deftp {Method} void add_file (const std::string &@var{name}, const std::string &@var{file_name})
Specifies that tags named @var{name} in the template HTML file be
replaced with the entire contents of the file called @var{file_name}
in the file system.
@end deftp
@deftp{Method} void add_passthrough_tag (const Query_String &@var{query_string}, ...)
The trailing arguments are a list of const char *const, terminated
with a NULL pointer. This method specifies that contents of the HTML
template file which look like ``[pass-through/]'' be replaced with a
set of lines which look like ``<input type=``hidden'' name=``name''
value=``value''/>'' where the @var{names} are taken from the list of
arguments to the function, and the @var{__values__} are taken from the
@var{query_string} variables with the same names. Thus, if the tag in
the template file is contained within ``<form>'' markup elements, the
current values in the query string will be propagated into any query
string that the new form produces.
@end deftp
@deftp{Type} enum Hyper_Tags::Section_Keep @{ KEEP_SECTION, LOSE_SECTION @}
@end deftp
@deftp{Method} Hyper_Tags &section (const std::string &@var{name}, const Section_Keep &@var{keep})
This method declares the action to be taken when a pair of tags like
``[@var{name}]'' and ``[/@var{name}]'' are seen in a template file.
If @var{keep} is KEEP_SECTION, then the tags are simply removed from
the file leaving the contents between the tags intact. If @var{keep}
is LOSE_SECTION then the tags and all the text between them is removed
from the file.
@end deftp
@deftp{Method} string Hyper_Tags::substitute (string @var{html_template}, int @var{repeat} = 1)
One of the main methods of the class. This will go through
@var{html_template} and replace any hyper tags which have been
registered with the substitution text that has been declared as the
replacement. If a tag is seen in the @var{html_template} which has
not been registered with the current object, then this tag will remain
intact in the template.
Additionally, any pairs of tags seen in @var{html_template} which have
been registered as a section will be removed, possibly removing also
all the text between the tags, according to the registered behaviour.
@end deftp
@node Functions_, , Methods_, The Hyper_Tags class
@subsection Functions_
@deftypefun static string Hyper_Tags::strip_loose_tags (string @var{input})
It may happen that, after processing, a HTML template string still
contains some hyper tags which have not been substituted. This static
function will injudiciously remove any such tags, thus eliminating any
ugliness from the page sent back to the user.
@end deftypefun
@node The Http_Server class, , The Hyper_Tags class, Reference
@section The Http_Server class
@menu
* Constructor__::
* Functions__::
@end menu
@node Constructor__, Functions__, The Http_Server class, The Http_Server class
@subsection Constructor__
@deftypefun Http_Server::Http_Server (const int @var{socket}, const
std::map<std::string, std::function<void (Query_String, int)> @var{methods})
Create a HTTP server to listen on the @var{socket}. Processing for
requests will be delegated to the @var{methods}, referenced by the
HTTP-call path name via the @code{map}. When called, the @var{methods}
will be passed a @code{Query_String} object and a socket on which a
response must be sent; methods are provided in the Http_Server namespace
to facilitate with this.
Please see the example application to see how this is used in practice.
@end deftypefun
@node Functions__, , Constructor__, The Http_Server class
@subsection Functions__
@deftypefun bool tick (Http_Server &@var{server}, const long @var{wait_us})
Cause the @var{server} to act on a single instruction from a web client,
waiting up to @var{wait_us} micro-seconds for such a request to appear.
The return is usually @code{TRUE}, but may be @code{FALSE} if the
listening socket goes away (this is a mechanism that could be used by a
request processing function to terminate the server frow within).
In practice this method is called repeatedly, @emph{ad infinitum}.
@end deftypefun
@deftypefun void Http_Server::return_html (const int @var{socket},
const std::string &@var{html})
This method sends the @var{html} to the socket, dressed up as a valid
response to a HTTP request for data.
@end deftypefun
@deftypefun void Http_Server::return_text (const int @var{socket},
const std::string &@var{text})
This method sends the @var{text} to the socket, dressed up as a valid
response to a HTTP request for data.
@end deftypefun
@deftypefun void Http_Server::return_pdf (const int @var{socket},
const std::string &@var{pdf})
This method sends the @var{pdf} to the socket, dressed up as a valid
response to a HTTP request for data. The `string' is actually
understood as a buffer of arbitrary octects here.
@end deftypefun
@deftypefun void Http_Server::return_json (const int @var{socket},
const std::string &@var{json})
This method sends the @var{json} to the socket, dressed up as a valid
response to a HTTP request for data.
@end deftypefun
@deftypefun void Http_Server::return_bad (const int @var{socket})
This method sends an empty payload to the socket, dressed up as a
@emph{valid} response to a HTTP request for data (it would generally be
taken by an Ecmascript application to be a `bad' response to a request
for data).
@end deftypefun
@deftypefun void Http_Server::return_png (const int @var{socket},
const std::string &@var{png})
This method sends the @var{png} to the socket, dressed up as a valid
response to a HTTP request for data. The `string' is actually
understood as a buffer of arbitrary octects here.
@end deftypefun
@deftypefun void Http_Server::return_svg (const int @var{socket},
const std::string &@var{svg})
This method sends the @var{svg} to the socket, dressed up as a valid
response to a HTTP request for data. The `string' is actually
understood as a buffer of arbitrary octects here.
@end deftypefun
@node Examples of Use, Hints on how the library might be used in a real application, Reference, Top
@chapter Examples of Use
We don't start with the tradition hello, world program as this would
not demonstrate in any way the dynamic nature of CGI programming! The
simplest example we can think of allows the user to input two numbers
and returns the product of them, and the full code for this is
provided in the next section.
@menu
* Simple example -- Online multiplier:: A simple application of the library
@end menu
@node Simple example -- Online multiplier
@section Simple example -- Online multiplier
The following is provided as the simplest code to demonstrate use of the
dmbcs-micro-server library, not to inform of any coding style or quality
system approach. We assume a standard GNU system with recent
@code{make}, @code{bash}, @code{gcc}, etc.
Start with the HTML file @code{calc.html}
@verbatim
<html>
<head><title>Multiplier</title></head>
<body><h1>Multiplier</h1>
<form action="compute" method="GET" id="calc">
<input type="text" id="arg_1"/> x <input type="text" id="arg_2"/>
= <input type="text" id="result">[result/]</input>
<br>
<input type="submit">CALCULATE</input>
</form>
</body>
</html>
@end verbatim
And the C++ source file @code{calc.cc}
@verbatim
#include <dmbcs-micro-server.h>
using namespace DMBCS::Micro_Server;
/* This function both serves up the basic HTML page, and
* performs the multiplication and injects the result into the
* HTML. */
void home_page (Query_String const &query, int const socket)
{
auto tags = Hyper_Tags {};
add (tags,
"result",
query.get ("arg_1", 0) * query.get ("arg_2", 0));
Http_Server::return_html (substitute (tags,
slurp_file ("calc.html")));
}
int main ()
{
auto server = Http_Server {2022,
{ {"", home_page},
{"compute", home_page} }};
for (;;) tick (server, 1000000);
return 0;
}
@end verbatim
then the @code{makefile}
@verbatim
CXXFLAGS = `pkg-config --cflags dmbcs-micro-server`
LDFLAGS = `pkg-config --libs dmbcs-micro-server`
@end verbatim
Then at the command line type
@verbatim
make calc
./calc
@end verbatim
then point a browser at @code{http://localhost:2022/} and use the simple
calculator (don't try to do anything funny: the code has been kept
deliberately simple and doesn't do any error checking). Note that an
answer can be obtained directly with a URL like
@code{http://localhost:2022/compute?arg_1=3&arg_2=4}.
@node Hints on how the library might be used in a real application, , Examples of Use, Top
@chapter Hints on how the library might be used in a real application
While the basic library as it is serves perfectly well for small CGI
programs, the library was derived from a larger project. From this
experience, it is seen that many large projects will want to produce
specializations of the classes and utility functions provided by the
library for the particular project. The following are some specific
details about how the library was enhanced in the original project.
@menu
* Web-site skins:: Web sites which provide a user-selected `look-and-feel'
* Other inheritence:: Other ideas
@end menu
@node Web-site skins, Other inheritence, Hints on how the library might be used in a real application, Hints on how the library might be used in a real application
@section Web-site skins
The underlying paradigm promoted by the library is one where the
programmer supplies template HTML files which the CGI program
populates with extra dynamic content. This opens the possibility of
supplying the same dynamic content into different templates, for
example where a web site allows the user to choose a favorite `skin',
or `look-and-feel', then each template file would exist in different
forms to provide all the different skins available. In this case, the
library can be extended by ensuring that whenever a template is
slurped from local storage for use, it is the template appropriate for
the user's choice of skin that is pulled up.
In the original project, this was achieved by placing all templates
for a skin into a single directory to which the CGI program has access
(it was actually a sub-directory underneath the cgi-bin directory, and
the web server was configured to *not* allow direct access from a
browser to these files).
The main modification was to add a new utility function in the
project's namespace
@code{string slurp_file (const std::string &skin,
const std::string &filename)}
which is called by the program in lieu of slurp_file, and
ensures that the file from the correct skin directory is chosen,
calling through to the library function to get the eventual work
done. To complete the effect, it is also necessary to derive a new
class from Hyper_Tags with the following additional methods
@code{blah, blah, blah}
(The Query_String class works completely as is; it may be
convenient to introduce this into the projects own namespace with a
@code{typedef Query_String Query_String;}
line in a project header file.)
@node Other inheritence, , Web-site skins, Hints on how the library might be used in a real application
@section Other inheritence
@bye