Gateways are very simple to add to plexus. In the simplest case, you need
only add a map line in local.conf
and make sure your
gateway calls &main'MIME_header('ok',
'content/type');
(where content/type
is one of the MIME
content types) before doing any output. MIME_header does all the work dealing with
HTTP/1.0 headers.
If your gateway encounters an error it should call &error($status, $msg);
which will
deal with reporting the error back to the user and exiting.
&error
does not return. Fatal errors can also
be reported with the standard perl die
command and
those will be handled by &report_error
which will
send email to webmaster by default so you should only
use in cases where something is broken enough that someone should
look at it.
The fortune gateway is a good example to start with because it's very simple. Note that it is careful to extract only the information it needs from a user query. This is to prevent the users from being able to execute arbitrary commands on your server. Any data that comes from the user must be carefully screened in this way to prevent security holes.
With this in mind I added a few new routines to make creating secure
gateways easier. &safeopen($FH,
$file);
will safely open a file for reading and should be
used in all cases where client data is involved. @fields = &main'splitquery($query);
will split a user query into fields and convert any %## escapes it contains.
Most gateways can simply use something like $query = join(" ", &main'splitquery($query));
.
Also, there is $pstring = &main'printable($string);
which will convert a string of binary data into something that is printable
using the %## notation for non-printable characters.
Principle #2: Complex things should be possible
There are many support routines provided in the
base code for making your life easier. The search module makes use of several. First,
it uses &main'clear_timeout;
to
clear the default timeout since it is about to do a search operation that
may take a little longer than normal operations and we are pretty sure
that it isn't going to hang unless there are major system problems. The
main reason for the timeout is when you are doing I/O on the socket to
the client which might hang and we don't want a bunch of processes hanging
around not doing anything, so always make sure the timer is running when
you do I/O with the client. You can use &main'set_timeout
to restart
the timer if you have stopped it.
Principle #3: A configurable command is a usable command
It's best to make things configurable. You can use the set command
in local.conf
which sets
the value in the associtive array %plexus so you can extract
values from it. But it's even better to simply pass the data directly
into your command as arguments to map (this allows the data to be
configurable on a per map basis). For some examples see
the sample finger and search gateway configurations
in local.conf.
Principle #4: Thou shall not scrunge others variables
Perl uses dynamic scoping (the value of a variable is inherited down
the call tree). Unfortunatly, Plexus makes use of this in a couple of
different cases. The good news is that most servers need only concern
themselves with a small number of variables because they are actually run
in a seperate process from the main server (so each invocation gets a
fresh environment). Mainly, watch out for $version,
%in_headers, and %out_headers which are all used
in the HTTP/1.0 handling code in &MIME_header
.
%in_headers is the list of HTTP/1.0 headers (if any) we got
with the request and %out_headers is used by
&MIME_header
to create the outgoing reply, it can be appended
to using &add_header(*out_headers, "Sample:
header")
(which must be called before &MIME_header)
for gateways that need to augment the standard reply headers.
Another side effect of dynamic scoping is that subroutines you call can
modify your variables. I've tried to carefully local()
all variables in the support routines. An easy way to avoid conflict is
to run in your own package
as do all the sample gateways.
Users writing new methods must be more careful as they run in the main server thread and cannot use package to good effect. You will probably be ok if you just prepend the method name to all variable names, and be careful.