Introduction ------------ This documents gives detailed information of the steps involved in adding support for a new Apache module in Comanche (like PHP3, mod_ldap, etc.) or adding support for new directives. Comanche is a framework to build management modules (plugins). There are plugins for Apache, Samba, etc. Since Apache is a complex program the plugin itself is modular and support for directives and modules is done via an extension mechanism. The process is relatively simple. You have to write a few XML files following certain simple rules and that's about it :) What the Apache plugin needs to know from you --------------------------------------------- In order to add support for your module or directive the Apache plugin needs to know a few things. * Where is your module located? At plugins/apache/modules you can find current supported modules each one of them has a subdirectory which contains the necessary files * Which files are necessary to support your module? moduleDescription.xml: Describes the module and gives pointers for the other files directives.xml: Describes the directives that we are configuring propertyPages.xml: Arrange the directives for presentation to the user specialCases.tcl: For parsing complex directives back and forth between the XML format and httpd.conf format moduleDescription.xml --------------------- * Description of module: name, where to find directive and property pages definition, special cases definition and description of the module * Nodes in which we are interested: Which nodes (main server, virtual hosts, etc) we want our property pages to appear in * Description of special cases: Apache uses httpd.conf format and Comanche uses XML format. If the directives are simple, the mapping will be automagically done by Comanche, if not we specify the name of the procedures here specialCases.tcl ---------------- * Actual Tcl code used to convert from XML format to httpd.conf directives.xml -------------- * Description of the directives that belong to this module propertyPages.xml ----------------- * Description of the property pages for this modules. They are presented to the user during configuration. They arrange the directives on the screen logically. It is possible to have different versions for beginners and for advanced users. messages -------- In the subdirectory messages/ the texts corresponding to the messages are stored there so they can easily be translated by other people. The messages are stored with a suffix corresponding to the language: messages.en messages.es etc. Step by step guide to create a module from scratch -------------------------------------------------- The following is a detailed description of the necessary steps to add support for a module. We will add support for the PHP scripting language (http://www.php.net). Planning -------- We take a look at the configuration information for PHP: http://www.php.net/manual/configuration.php3 As it turns out PHP can be configured in different ways, either inside the Apache httpd.conf file or in a separate file. The syntax varies too from PHP3 to PHP4. Since this is just an example, we will configure PHP3 for httpd.conf syntax. The user interface will remain unchanged among all of them, so to support the other versions we just need to change the translating functions since as can reuse the directive and property pages definitions. One thing to remember is that we do not need to support all directives at once. Directives not known to Comanche are safely ignored and restored when writing the output configuration file. We can provide support for the most commonly used directives and then go for the more obscure parameters. Before doing any coding we need to plan what the user interface is going to look like. We plan on having the following property pages: PHP3 (Enable/disable and tags) | \__ Resources (Limit use if resources CPU/Time) | \__ Error Handling (Error logs, display, etc.) | \__ Data Handling (POST variables, prepend, autopend...) | \__ Paths (auto include directories) Next step is to actually define the directives. The XML language used here is described in the programmer guide. It is really easy so you probably can pick it up just by taking a look at how the other modules are described. Most directives have a one to one correspondence, others will need more elaborated XML directives. * asp_tags In the docs we find "asp_tags boolean Enables the use of ASP-like <% %> tags in addition to the usual tags. This includes the variable-value printing shorthand of <%=$value %>. For more information, see Escaping from HTML." It is clear that this maps directly into the XML boolean type so we write: 0 Name is php3_asp_tags because this is how it will appear on Apache config files. This way Apache already nows which httpd.conf directives match to which XML directives. Instead of writting the description of the directive directly on the label we store the description in the messages/ subdirectory. The contents of the messages.en file: php_asp_tags {Enable ASP (<% %>) style tags?} If we want an additional Spanish version, we write (lenguage can be later on selected by the user) messages.es: php_asp_tags {Permitir tags como las de ASP (<% %>)?} * max_execution_time This one, which accepts a number as an argument gets turned into 30 with messages.en php_max_execution_time {Limit in execution time (seconds)} * doc_root This one sets the document root for safe mode. This is a string, more precisely a directory, so the corresponding entry: (note the classes attribute, it hints the gui to provide a directory selector button and to write back quoted directories with blank spaces) with messages.en: php_doc_root {PHP root directory (for safe mode)} * gpc_order This one could have been modeled in a different way, but this ones works just fine at it is clear GPC messages.en: php_gpc_order {Order of GET/POST/COOKIE variable parsing} So far the mapping between httpd.conf and XML directives has been pretty straightforward. For the previous entries the conversion is handled automatically by Comanche and we do not need to do anything else! Now comes the interesting part. It requires a little bit more of work but it pays off in a more easy to use interface for the user. There are some directives that could be better expressed in some other way. Take for example the directive auto_append_file (File to always parse after processing the main file). It can have a special value of 'none' to disable this feature. Instead of mapping it to a string and have the user know that piece of information we make it a little bit easier and provide a pair of radiobuttons. First one is simply 'none' the other is the name of the file. This, translated to XML gets us: none You get the idea. By default the 'none' element is selected. We need a way to convert from httpd.conf to this XML format and the other way around. This involves a little bit of programming, which is shown below # This procedure is called whenever the php3_auto_append_file is encountered # in httpd.conf proc ::apache1.3::parse_php3_auto_append_file {text parser dirDef xmlConf currentContainer} { # Create a new instance of this directive or overwrite the existing one set xuiObj [apacheparserutils::getOrCreateIfNotExists php3_auto_append_file \ $dirDef $xmlConf $currentContainer] # Depending on the value (none or a filename), select the appropriate component and store the value set value [lindex $text 1] switch [string tolower $value] { none { $xuiObj selectComponentByName none } default { $xuiObj selectComponentByName file $xuiObj.file setValue $value } } } # Procedure called to dump the contents to httpd.conf proc ::apache1.3::dump_php3_auto_append_file {xuiObj} { set value [[$xuiObj getSelectedComponent] getValue] return "php3_auto_append_file $value" } Similar goes for php3_auto_prepend directive or php3_error_log php3_include_path ----------------- This is another directive that would benefit of special treatment is php3_include_path (and php3_open_basedir) From the PHP docs: include_path string Specifies a list of directories where the require(), include() and fopen_with_path() functions look for files. The format is like the system's PATH environment variable: a list of directories separated with a colon in UNIX or semicolon in Windows. Example 3-1. UNIX include_path include_path=.:/home/httpd/php-lib Example 3-2. Windows include_path include_path=".;c:\www\phplib" The default value for this directive is . (only the current directory). - Now we could map this directive to a string directive and hvae the user enter a string of directories separated by : or ; Instead we make it a little bit easier for them by abstracting it and presenting them with a list of directories. The XML description: . We need now a couple of functions for converting from : or ; format (httpd.conf) to XML and viceversa. proc ::apache1.3::parse_php3_include_path {text parser dirDef xmlConf currentContainer} { set xuiObj [apacheparserutils::getOrCreateIfNotExists php3_include_path \ $dirDef $xmlConf $currentContainer] global tcl_platform switch $tcl_platform(platform) { windows { set separator {;} } default { set separator : } } foreach element [split [lrange $text 1 end] $separator] { set child [$xuiObj newChild] # Split fscks up quoted filenames, so this is required regsub {\\\"} $element {"} result $child setValue $result $xuiObj insertChild $child } } proc ::apache1.3::dump_php3_include_path {xuiObj} { global tcl_platform switch $tcl_platform(platform) { windows { set separator {;} } default { set separator : } } set values {} foreach child [$xuiObj getChildren] { lappend values [$child getValue] } set result [join $values $separator] if [llength $result] { return "php3_include_path $result" } return {} } Once we have described all the directives (take a look at plugins/apache/modules/php3/directives.xml for a complete listing) We need to tell Comanche how do we want them organized in property pages (like in the tree described at the beginning) In plugins/apache/modules/php3/propertyPages.xml As an example, the main page: Finally, the moduleDescription.xml puts everything together: [...] [...]