Next Previous Contents

3. CSA basic features

3.1 Our first example CSA application.

Prior to start developing a new CSA application, the very first thing you need to do is to create the proper structure of files and directories where your application will be located on the Web server. The following explanation will show how to setup and play with an application that we will call "example", consisting of just a few programs (or methods), one of which is the classical "hello-world". As you will see in the rest of this manual, CSA makes use of a number of naming conventions to identify its files and objects. One of such convention is to identify a single program by its file-name, prefixed by the name of the application it belongs to. In our example, the application is example, and the program will be hello-world. So the fully-qualified name of our program will be example.hello-world. The purpose of our program is to display the usual "Hello World" message on a Web page, whenever it is called by the user through a Web browser, or through some other Web client program.

3.2 Basic Application Setup.

Let's assume that the non-privileged system account under which our application will run is goofy, and that its HOME directory (that we will usually refer to as $HOME) is /home/goofy/.

First, you need to copy the CSA shell script from /usr/local/csa/bin/CSA into $HOME/cgi-bin/. Then edit $HOME/cgi-bin/CSA and change "logname = jsmith" into "logname = goofy". As already stated, your knowledge of rc shell syntax is assumed here. For better security, you should also create the directory that CSA will use to store temporary workfiles, /tmp/goofy-csa/, and set it owned by goofy and with mode 700. If this is not done, the CSA will try and create that directory upon the first invocation, but it is more secure to do it beforehand. If you decide to use a non-publicly writable directory (probably a sensible thing), say /home/goofy/tmp/, simply create it and change the "TMPDIR" definition in $HOME/cgi-bin/CSA accordingly.

By default, our CSA example application will go in $HOME/.csa/example/ and a few subdirectories thereof. Should you prefer to place it in a different location, edit the "libstem =" definition in $HOME/cgi-bin/CSA accordingly. Finally, if your system stores commands and utilities in non-standard locations, you may want to edit also the "PATH =" definition in the same script. Note, however, that the PATH defined here is necessary only to find what CSA needs to start-up and load the proper per-application configuration file, namely test and mawk, so you sould not normally need to change it. The application-specific PATH setting is done in the actual per-application profile, as shown later. The application-specific path "$HOME/.csa/example" will often be identified simply as $CSA_ROOT throughout this Programming Guide.

Next, we MUST create all what is needed under $CSA_ROOT. To make your life a bit easier, I have provided a file that does this. First, create directory /home/goofy/.csa/, cd into it and un-tar the "example-app.tar.gz" file contained in the "extra/" subdirectory of the CSA distribution tarball. As with anything else that comes with CSA, I take no responsibility if a given script or component causes you troubles, drills holes in your server or sets your house on fire. If you are a security-consciuos person you may want to first have a look at things beforehand, prior to blindly do whatever someone else tells you to do with them, including un-tarring an object on the file-system before having at least taken a look at it by simply listing its contents. Anyway, I've been running CSA for some time now, and my house is still up and my Web servers are still working, so I think you sould be sort of safe too :-)

Why did I choose a hidden directory name, such as .csa/, for the user-level components of CSA ? Well, for no particular reason really, but I see CSA as an extension of the shell command-line to the Web, a way of taking to the Web common shell-level UNIX commands and applications. It seems therefore logical to me to consider such enablement a per-user configuration matter, and user profiling stuff is usually written into hidden files and folders in one's $HOME directory.

3.3 The classical Hello World.

Back to our "example.hello-world" (note the loosely Object-Oriented naming scheme here, see further down), the actual script can be found in /home/goofy/.csa/example/rpclib/. This is where all the Web "methods" that will make up our example application will have to be. "rpclib" means "Remote Procedure Call Library", as calling a program over the Web is a form of RPC operation, at least this is the way I see it. Before things are really ready to run, you still need to set up a few local definitions in the "example" application main configuration file, /home/goofy/.csa/example/csa.rc. Here you will probably only need to set CSA_ALLOW_USER to your UNIX account ("goofy" in our example, yours will almost certainly be different and equal to your Unix login account), and define the correct values for CSA_URL, CSA_RPC_URL and CSA_DOCROOT. The example settings in the supplied csa.rc assume that your CGI setuid wrapper is "cgiwrap". Adapting those values to suEXEC should be trivial.

For the rest of this document I will often call an application a "class", and its individual scripts "methods". Although CSA isn't Object Oriented Programming in any true sense, I like naming things in this way. So let's call our first example script the "hello-world" method in class "example". Note that the "csa" class SHOULD be considered reserved for CSA own use, and SHOULD NOT be used to identify a CSA user-level appication.

First, take a look at the actual "rpclib/hello-world" script. Well, there isn't eally much to it; all it contans is:


 # Sample "hello-world" CSA application.

 csaPrintMsg 1000 $CSA_PGM
 csaTemplate csaOk.html
 csaExit

 # End of program.
 

Just three lines of code, plus comments. Of course real-world scripts will usually be more than that, but even such a simple script can already show us how the CSA basics work. Open your Web browser and type the script URL (replace the relevant parts with your local values):

 http://www.example.com/cgi-bin/cgiwrap/goofy/CSA?0=example.hello-world
 

Tell your browser to load that URL, and if everything was set up as explained you should see a response page with an "Hello World!" message on it. If that didn't work, please double-check all the steps that I have outlined, because it must work, believe me :-)

Some explanations are needed on the URL syntax first. The first part is pretty obvious:

 http://www.example.com
 

The next part is necessary if you use cgiwrap:

 /cgi-bin/cgiwrap/goofy/CSA
 

If you rather use suEXEC this will most likely become

 /cgi-bin/CSA
 

Whatever the case, CSA is the CGI program that you copied to your $HOME/cgi-bin/CSA. What comes after the "?" are CGI parameters, as usual, and they are passed to CSA:

 ?0=example.hello-world
 

Since the CGI specs do not mandate that argument names use letters, I decided to use numbers for CSA own purposes, to make the syntax recall the familiar C-style argv[] argument list, where argv[0] is the program name, and argv[1] through to argv[n] are arguments. The adopted style is similar to the one suggested by spec n. 6 of the MIME-RPC proposed protocol.

Our "example.hello-world" script does not take arguments, but if it did they would therefore extend the above URL to become something like:

 ?0=example.hello-world&1=value1&2=value2&a=abc&b=123&...
 

I like to see this remote program invocation style ar a kind of Web Command Line Interface, which I dubbed CSA-RPC.

Back to "example.hello-world", let's examine it a bit more in depth. All our program does is to call three CSA library functions: csaPrintMsg, csaTemplate and csaExit. Here are the gory details:

  1. csaPrintMsg is the message processor. It is passed two arguments:
    1. 1000 is the number of the response message to be printed
    2. $CSA_PGM contains the program name, hello-world in this case. Message code and severity are always mandatory, while additional arguments depend on the spcific message that is requested. See section Message Processing for details.
  2. csaTemplate is the actual response processor. It is passed the name of the template page to use to display the response to the client. The requested template, csaOk.html in this case, is sought for by csaTemplate in the $CSA_ROOT/forms/ directory. See section Template Processing for details.
  3. csaExit. This function always ends a CSA program, and is necessary to perform return-code processing and garbage-collection upon program termination. It can optionally be passed a numerical error code. If the code is not specified it defaults to zero (i.e.: it is equivalent to call csaExit 0).

Although our "example.hello-world" script was specially crafted for tutoring purposes, its function can be more elegantly performed by "collapsing" its code into one single line, like this:


 # Sample "hello-world" CSA application ("squeezed" version).

 csaExit.ok 1000 $CSA_PGM

 # End of program.
 

The csaExit.ok statement is CSA generic "positive completion" exit function. When called as shown, it will first call csaPrintMsg with the passed arguments, then call csaTemplate against the generic csaOk.html template (that MUST always be present in the template directory), and then csaExit 0 will be called and the program terminates.

Likewise, the csaExit.fault function can be used to display the generic csaError.html template to the client and then quit the program. For detailed usage info on CSA library functions, please refer to the relevant library source files in the CSA installation directory, usually /usr/local/csa/lib. I will eventually provide detailed documentation for them, but it will probably take time. In the meantime, the best source of documentation remains the code itself, and the relevant comment lines.

3.4 An improved example.

Our example application contains a second script, "hello-folks". To call it from your Web browser type:

  http://www.example.com/cgi-bin/cgiwrap/goofy/CSA?0=example.hello-folks
 

replacing the relevant parts with your local values, as usual. The "hello-folks" script source code, from $CSA_ROOT/rpclib/hello-folks is:


 # Sample "hello-folks" CSA application.

 csaPrintMsg 1000 $CSA_PGM
 csaExit.ok hello-link.html

 # End of program.
 

This time a template other than the default csaOk.html is displayed, namely hello-link.html, also stored in the HTML template directory $CSA_ROOT/forms/en_US/. Since the template name is a custom one, it cannot be implied by csaExit.ok and MUST be passed to the function as an argument. Beside the message-capture tag $[ISO_CSA_MSG_TEXT], the template now has also the additional URL tag $[CSA_RPC_URL], that is used to "resolve" the clickable hyperlink on the page. The value associated with CSA_RPC_URL is a local configuration parameter, defined in the application profile $CSA_ROOT/csa.rc. The $[CSA_URL] tag, which value is also defined in $CSA_ROOT/csa.rc, is useful to resolve relative URL's to images or other external HTML obiects, in spite of the fact that the page was served through the path of the CSA CGI driver, and not directly as a static object by the Web server.

By clicking on the relevant anchor-point on the response page, the "example.hello-folks" script can be re-run over and over.

3.5 Message processing.

Let's see how program messages are handled. In general, when either the application program or a shell library function need to produce a message, they call the csaPrintMsg CSA primitive. Messages are identified by a message number (the "1000" of the "hello-world" example), an associated explanatory text, and some of them can be passed optional arguments (the $CSA_PGM in said example). Message numbers are always a four-digit code. Codes beginning with "0" (0000, 0001, ... 0999) are reserved for basic CSA messages. They can be used by both CSA library functions and application programs, and refer to generic error or informational conditions (such as errors reading/writing files, generic error messages, generic positive completion messages, etc.). Messages from 1000 to 9999 are available to application programmers, and can be re-defined differently for each specific CSA application. Messages are organized in flat-file tables, composed by fields (or columns) which are separated from each other by an horizontal TAB character. This is an example entry for message 0008:

 0008<TAB>ERR_SYSTEM<TAB>could not read from file '%s'
 

In the example I have represented with "<TAB>" the otherwise non-printable horizontal TAB character. The message code uniquely identifies the message table entry, and further down I'll explain the meaning of the ERR_SYSTEM field. The sample message shown takes one parameter, the name of the file that the program failed to read, so to actually use the message a program would do:

 csaPrintMsg 0008 /path/to/my/file
 

The ERR_SYSTEM field in the message table is the message group identifier. This is a symbolic string, all upper-case, that identifies the class of messages that a particular message belongs to.

The class string is actually made up by two substrings, separated by an underscore: class_subclass. The class part can be one of:

  1. CSA (reserved for CSA use)
  2. ERR
  3. INFO
  4. WARN

The CSA class is reserved for CSA use, and MUST NOT be used by application-defined messages. The subclass part can be one of:

  1. ARGS
  2. AUTH
  3. CREATED
  4. DATABASE
  5. DENIED
  6. INPUT
  7. LOCAL (reserved for use by the application)
  8. MOVED
  9. NOTFOUND
  10. OK
  11. PEER
  12. PROMPT
  13. REFUSED
  14. SYSTEM (reserved for CSA use)

The generic SYSTEM subclass is reserved for CSA use, and MUST NOT be used by application-defined messages. If an application needs to define a general subclass, it can use the LOCAL one.

Therefore, a message group of ERR_REFUSED belongs to the ERR class, and its subclass (REFUSED) indicates that it is related to something that the issuer refused to do, for some reason. An ERR_SYSTEM string means that an error occured in a generic component of the CSA stack, while ERR_LOCAL indicates a generic error at the application level.

To get an idea of how message groups are used, have a look at $CSA_INSTALL/message.d/0/en_US.data

The purpose of this classification scheme is to identify, in a machine-readable format, the general condition that caused a message to be issued.

If an application program wants to issue a certain message, but it is not satisfied with the default message group associated with that message, it may override that value by passing the new group name to csaPrintMsg. For instance, the default group associated with message 0008 is ERR_SYSTEM, since it is usually an indication that an error occurred and that the program SHOULD stop. However, a particular application may consider that condition just a warning, and continue processing. In that case it SHOULD override the original message group with a new value indicating a less severe condition, like WARN_SYSTEM, for example. Choosing the appropriate message group is not mandatory, but will help when reading message logs and debugging applications.

Back to the previous example, to issue message 0008 with a message group of WARN_SYSTEM instead of the default ERR_SYSTEM, an application would do:

 csaPrintMsg 0008 WARN_SYSTEM /path/to/my/file
 

As previously shown, message 0008 takes a string argument '%s'. Messages are processed with the printf(1) shell utility, so please refer to the relevant man page for more on the parameter substitution rules.

For the complete list of CSA pre-defined messages 0xxx, see the relevant tables in the CSA installation directory, usually /usr/local/csa/message.d/. In the directory there are one message file for each message language supported by CSA. To date, only en_US (US-English) and it (Italian) are provided, but other will follow in the future. The language selection can be done by setting the $CSA_LANG_DEFAULT variable to the desired language code in the $CSA_ROOT/csa.rc application profile. If unset, this variable defaults to en_US. Application programs may specify a different language code through variable $CSA_LANG. The language code is used to identify not only the correct message table, but also the associated template subdirectory of forms/. For instance, HTML (or XML) templates for the en_US language are expected to be in forms/en_US/. The language code is also used by CSA library routines that handle date values, which will represent dates consistently with the code used (DD/MM/YYYY, MM/DD/YYYY, and so on).

Beside CSA predefined messages, each application will usually need to define its own. Those can be assigned any code between 1000 and 9999, MUST be organized in language-code files as already explained, and are expected to be found in $CSA_ROOT/message.d/. Each message MUST be given a suitable message group, in the form of the symbolic labels previously explained.

You only need to provide message files for those languages that your application actually uses. The message issued by our "example.hello-world" has code 1000, meaning that it is an application-defined message, and it can be found in $CSA_ROOT/message.d/. Beside being grouped into language code tables, messages are further grouped into sub-directories according to the first digit of the message code. The complete path to the file containing our sample message (1000) will therefore be $CSA_ROOT/message.d/1/en_US.data. The reason why I further classified messages in this way was to allow different programmers, working at different parts of an application, to handle their own messages without interefering with each-other. This may or may not be a problem, depending on whether you use other cooperative development tools, like the Concurrent Versioning System (CVS), to coordinate your development team. But anyway the facility is there and, even if you don't need it, it will not hurt. See section Path-Based Clustering for more details on this table-record grouping scheme, as it applies also to other CSA data tables, not just to messages.

Provided that both CSA- and application-defined messages are organized in directories and files as shown, the csaPrintMessage primitive will be able to fetch and process them transparently, removing the associated hassle from the application program.

Whenever csaPrintMsg is called with the proper arguments it does the following main things:

  1. Fetches the message from the proper message table, according to the specified message code and the language which is in effect.
  2. Makes parameter substitutions on the message text if necessary.
  3. Sets the global variable $CSA_MSG_NUM to the message code.
  4. Sets the global variable $CSA_MSG_GRP to the symbolic message group name.
  5. Sets the global variable $CSA_MSG_TEXT to the message text (after substitutions).
  6. Logs the message to $CSA_ROOT/var/message.log.

Since csaPrintMsg writes log entries to $CSA_ROOT/var/message.log, that file will eventually grow in size, and on a busy server it will need to be rotated at regular intervals (for instance daily, or weekly), by properly configuring your local logfile rotation facility. On Debian GNU/Linux see /etc/logrotate.conf. Other Linux distributions may provide different rotation facilities.

3.6 Template processing.

Basic template capabilties.

Let's refer back to the Classical Hello World section, in particular to the csaTemplate csaOk.html line of the "example.hello-world" program. The specified template, csaOk.html, is fetched by csaTemplate from $CSA_ROOT/forms/en_US/csaOk.html and sent to the client browser in response to the original request. Before the template is sent, a number of things occur inside csaTemplate. The most important one is tag substitution. That is, templates may contain special tags, that whenever are met by csaTemplate are replaced by the content of the corresponding environment variables, before the template is sent to the client. Such tags are ordinary names, surrounded by special markers, $[ and ] by default. If you look at the example csaOk.html, you will see that it contains one such tag, $[ISO_CSA_MSG_TEXT]. If no value has been associated with a certain tag, it will be replaced with a null string in the template that is sent to the client. Note that substitutions are done only against the data that travels towards the client, and that no changes occur to the original file on disk.

As an example, let's say the program environment of "example.hello-world" contains the variable $HOME, having the value /home/goofy, and that we want such value to be displayed on the output template. For this to occur, the template must contain a $[HOME] tag, and upon serving the template to the client, csaTemplate will do the proper substitution. Since csaTemplate is meant to work on HTML templates, for every variable in the program environment the function prepares also two extra names, with the ISO and URI encodings of that variable. That is, given our $HOME variable, csaTemplate will also provide $ISO_HOME and $URI_HOME, so that in our template we can refer to any one of the three versions of the same variable, depending on our needs. The point is that for a substitution not to break HTTP and HTML rules, some special characters in the original value need to be encoded. Strings that are to appare in the various HTML elements should be ISO-encoded, while those that are to be included in URL's need to be URI-encoded. It will then be up to the template programmer to refer to the correct encoding, depending on the specific location in the template where the substitution is due to occur. Back to the $HOME example we will then have:

$HOME

/home/goofy

$ISO_HOME

&#47;home&#47;goofy

$URI_HOME

%2Fhome%2Fgoofy

Now it becomes clear why, in our csaOk.html template, the substitution tag is $[ISO_CSA_MSG_TEXT]: it is the ISO-encoded version of the $CSA_MSG_TEXT variable that was set in the environment by csaPrintMsg, containing the message text to be displayed.

Since the rc shell exports every variable to the environment by default, substitution tags may refer to any variable that is known to the program name space. Anything that is present in the program environment can be captured by an equally-named tag on a page template. And every variable will take on two additional names, prefixed by URI_ and ISO_, with the relevant encodings, as already explained. Although rc also axports function definitions to the environment, CSA by design does not make them available to the substitution process.

A note on tag names.

Tag names inside $[...] in templates SHOULD always be simple strings, formed only by those character that are acceptable as shell variable names. That is, tags having names like $[HOME], $[my_tag] and $[goofy_123] are ok, while $[minnie!], $[my.tag] and $[my@tag] are not.

Customizable tags.

As explained, substitution tags are marked by the default "$[" and "]" markers. The advantage of such defaults is that they remain visible on the HTML page while it is being created, for the Web author's convenience. However, such tags can be changed if desired, by setting the relevant CSA environment variables $CSA_TPLTAGO (tag opening marker) and $CSA_TPLTAGC (tag closing marker). For instance, one may want to mark tags in a way that parses correctly with an XML or HTML parser. Back to our $HOME example, if we set $CSA_TPLTAGO to "<csa:" and $CSA_TPLTAGC to "/>", the csaTemplate function will expect the replacement point for HOME in the template to be "<csa:HOME/>". Of course such tag parses as well-formed XML before the substitution occurs. Anyway, whatever tags you choose, the opening and closing markers are always expected to be different, and you MUST NOT use the same string for both.

File tags.

Beside marking a variable substitution point, tags can also cause whole files to be inserted in the template at the point where a tag occurs. For this to happen, a tag must be interpreted as a file path by the substitution engine. For instance, a tag like $[/etc/passwd] would cause csaTemplate to include your password file in the template, before the latter is sent to the client. Not very safe, but it would work :-) So keep on the safe side, files are encoded in Base64 by default before being included at the point where the relevant tag occurrs. If a different encoding, or no encoding at all, is desired, it can be done by suffixing the tag with an appropriate encoding option, separated from the tag name by a colon ":". As an example, we can request our /etc/passwd to be included as-is (that is without any encoding) by using the tag into $[/etc/passwd:c] (here "c" stands for ``CDATA''). The available encoding fleags are:

c

CDATA (character-data). That is, the requested file can be included verbatim in the specified context, with no need for encoding.

p

PCDATA (parsed character-data). The file needs to have a few special characters encoded before the inclusion, or the resulting templatemay be broken.

Here CDATA and PCDATA are taken from the XML terminology, and are used with the same meaning.

Two-pass file tags.

So far, so good. In reality, however, the name of the file to be inserted is not known in advance, and it's name cannot therefore be hard-coded into the tag. Usually, the file name is contained in a program variable, say varname=/path/to/file, and the template will contain the tag $[varname]. But given the standard substitution mechanism, $[varname] would be replaced with the literal value /path/to/file by the substitution process, not by the file contents. To cope with this, the csaTemplate function can be called as follows:

 csaTemplate --eval varname template.html
 

This tells csaTemplate that whenever it encounters a $[varname] tag in template.html, the value associated with varname must be substituted first, as usual, but then a second substitution pass must be done on the resulting tag. Since varname contains /path/to/file, the first pass will turn $[varname] into $[/path/to/file], and this value will then be interpreted by the second pass as a file-inclusion directive.

If multiple file-inclusion tags must be eval'ed in this way, they can be passed to csaTemplate in a comma-separated list:

 csaTemplate --eval varname1,varname2,... template.html
 

Relative file tags.

If a file tag contains a relative file path, that is $[path/to/file], the specified file is considered to be relative to the HTML template directory $CSA_ROOT/forms/$CSA_LANG by default, or to whatever directory is specified with the --file-root option of csaTemplate.

3.7 Output hook.

An important part of the application response process, strictly related to templates, is the possibility for the application programmer to define a local AWK function, or hook, to perform additional complex processing of environment variables before they are used by csaTemplate to make substitutions on the response template.

Prior to doing the substitutions, csaTemplate first looks for a special AWK library file associated with the application program. In the case of our rpclib/hello-world example script, such file is sought for in lib/rpcio/hello-world.awk. Here rpcio stands for "RPC I/O" library. If that file exists, it is expected to be a valid AWK function library, and to contain the AWK function outvar(). Each name/value pair which is present in the program environment is first passed by csaTemplate to the outvar() function, which can process it as desired and then return the modified value (or a null string) to the caller. Since outvar() may need to store status information between one call and the next one, it is allowed to use the global CSA AWK array RPCOBUF[] (RPC Output Buffer) for that purpose. After the function has been called on the last name/value pair available, it is called once more and passed the special name ENOMSG, that signals that there are no more "messages" to process. In this way the function knows that it will receive no more stuff, and that it is time for it to do any closing actions that depend on status information that has been accumulated so far in RPCOBUF[]. Please see section C-like stuff for more on the ENOMSG special name.

3.8 Concurrency and file-locking.

The standard CSA library provides functions that are needed to handle concurrent access to the data by multiple programs, with the objective of preserving file integrity during update operations. Concurrency is handled through the use of lock-files, or semaphores. These can be created/destroyed with the relevant CSA library functions csaLock and csaUnlock. Handling locks is a tricky subject, due to the possibility of race-conditions that may lead to data corruption. These can occur whenever we have a test operation followed by an action based on the result of the test. This test-action sequence is non-atomical, hence the potential for races. The low-level driver used by csaLock to perform locking is lockfile, a utility especially conceived for this purpose and that can safely be used also when the files to be locked leave on NFS-mounts. By calling lockfile with the proper command-line options, the csaLock function tries also to cope gently with stale-locks, i.e. semaphores left in place by processes that died prematurely. Preventing dead-locks is another issue that the library functions try to cope with, although for this to be effective the CSA application program must have been designed sensibly in the first place.

As a rule-of-thumb, semaphores MUST be set whenever any of the following conditions are met:

  1. A program needs to wite/delete data. If the operation is based on a previous read operation, the lock MUST be set before the read (reading+writing is non-atomical): in the CSA parliance this condition is called Non-Atomical Write (NAW).
  2. A program needs to read data from multiple files, for instance as a result of a join operation between two table-files (i.e. a view). If there is a chance that one or more of the involved files can be modified while we are reading them, then all the files SHOULD be locked before we start reading from any of them. I call this condition a Non-Atomical Read (NAR). In common database terminology, we need to make sure that nobody can break the referential integrity between the data that we are about to read from multiple, phisically-indipendent but logically-related, sources.

Whatever the locking policy, it is left entirely up to the CSA application program. The CSA library merely provides the locking primitives, but whether to lock individual files, whole directories, or other application-dependent collection of resources is an application-level affair from the CSA point of view.

Explicitly releasing lock-files is usually not necessary, as they are removed automatically when a program calls csaExit or one of its variants (csaExit.ok, csaExit.fault, etc.). Removing locks with an explicit call to csaUnlock may be necessary only if a program needs to iterate multiple times before exiting, and in general when it is expected to go on for a while before calling csaExit. In such cases we SHOULD release the locks when we no longer need them, or others may time-out while waiting to try and set their own locks on the same resources.

There is a lot more to be said to use lock-files properly. I'll eventually expand this section a bit, to try and make it more useful.

3.9 URL rewriting (REST mapping)

An important REST-related feature of CSA is its capability to expose to clients a "logical representation" of CSA Web applications and resources. This is done through a URL rewriting mechanism, based on AWK regular expressions. For more details see the rest.map file distributed with CSA. Here I will give only a few examples to show what this mechanism can be useful for.

Let's say we have a CSA Web application (let's call it "depot"), that deals with querying a remote repository of items and enter purchase orders. The "depot" application is made up by three "methods":

  1. depot.list-parts
  2. depot.show-part
  3. depot.order-part

According to the non-RESTful CSA-RPC model, the three methods will be invoked through URLs similar to the following:

  1. http://www.example.com/cgi-bin/cgiwrap/goofy/CSA?0=depot.list-parts
  2. http://www.example.com/cgi-bin/cgiwrap/goofy/CSA?0=depot.show-part&partid=00123
  3. http://www.example.com/cgi-bin/cgiwrap/goofy/CSA?0=depot.order-part&partid=00123

By using suitable rewriting rules in the CSA rest.map file, we can present to clients a logical representation of such URLs, in terms of entities (names) rather than methods (verbs). For example:

Issuing a GET request against that URL will be rewritten inside CSA into

 http://www.example.com/cgi-bin/cgiwrap/goofy/CSA?0=depot.list-parts
 

and will produce a response message containing a list of URLs to parts that are available for ordering, for instance:

Then, if a GET request is issued against one of the returned URLs, CSA will internally rewrite it as, say,

 http://www.example.com/cgi-bin/cgiwrap/goofy/CSA?0=depot.show-part&partid=AB450
 

and the relevant catalogue entry (part detail) will be shown to the client. On the part detail page, an order form will be present, with a button to submit it through a POST operation. The URL associated with the POST will still be in RESTful format, for instance

 http://www.example.com/cgi-bin/cgiwrap/goofy/CSA/Parts/AB450/
 

but by using POST against it, instead of GET, the action will be rewritten by CSA as

 http://www.example.com/cgi-bin/cgiwrap/goofy/CSA?0=depot.order-part&partid=AB450
 

and this time it will result in an order for part AB450 to be entered.

The URL rewriting facilities provided by CSA are rather flexible, and it should be possible to rewrite almost anything into anything else.

The part of the URL up to the CGI name, that is http://www.example.com/cgi-bin/cgiwrap/goofy/CSA, cannot be rewritten by CSA, which has no control over it, but only by the Web server program, if the one being used provides URL rewriting facilities (Apache does). That is, if you want a URL like

 http://www.example.com/cgi-bin/cgiwrap/goofy/CSA?0=depot.list-parts
 

to be addressable as http://www.example.com/Depot/ you will need to have the Web server configured to rewrite it into

 http://www.example.com/cgi-bin/cgiwrap/goofy/CSA/Parts/
 

and then CSA will be able to apply its own rewriting rules, as shown.


Next Previous Contents