Project

General

Profile

Actions

HowToWriteALighttpdPlugin » History » Revision 2

« Previous | Revision 2/23 (diff) | Next »
jan, 2005-08-22 16:39
how to add the plugin to the build system


Basic

Before you start with writing your own plugin, should feel comfortable with the two basic datatypes in lighttpd and the main headers:

Next read the server internals:

the skeleton

A good starting point for writing your own plugin is the shipped mod_skeleton.c which just contains a basic skeleton and a semi-working copy of the mod_access module. mod_access is really simple and whould be taken as a basic guide how the modules work.

requirements

you need

  • automake 1.8.x or higher
  • autoconf 2.57 or higher
  • libtool 1.5.x or higher

To turn mod_skeleton into a usefull plugin take your favorite editor and replace all occurances of the work 'skeleton' by the name of you plugin:

{{{
$ cd src/
$ cp mod_skeleton.c mod_counter.c
$ vi mod_counter.c
:%s/skeleton/counter/g
}}}

and add some lines to the src/Makefile.am to tell the build system about your new plugin:

{{{
lib_LTLIBRARIES += mod_counter.la
mod_counter_la_SOURCES = mod_counter.c
mod_counter_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_counter_la_LIBADD = $(common_libadd)
}}}

By default the build system will assume that you are a user and only want to compile the existing code. Changes to the Makefile.am files will
not result in a update to the Makefiles. You have to tell 'configure' that you are a brave developer:

{{{
$ ./configure --enable-maintainer-mode ...
}}}

This will automaticly result in a rebuild of the Makefile.am for you and when ever you update the Makefile.am like adding new dependency libs
the Makefile will be rebuilt and everything is fine.

While you are developing you might use a prefix to install all files too as you don't want to interfere with the real installation:

{{{
$ ./configure --enable-maintainer-mode --prefix=${HOME}/testbed/lighttpd-1.4.x/ ...
}}}

This also removes the burden to install everything as root. Just change your config to use a port greter than 1024 and root-privileges aren't needed to run lighttpd.

=== plugin_config ===

Every plugin can opt-in to handle conditionals from the global configfile and stores the different settings in a by-condition plugin_config. This struct in linked in the next plugin-wide struct: plugin_data

=== plugin_data ===

Each plugin has some local data which only belongs to the plugin like the config and some temporary buffers.

=== handler_ctx ===

If a plugin has to store connection specific information you need another structure which one entry per connection. Take a look at mod_rewrite as an example.

=== neccesary functions ===

  • _init
  • _free
  • _set_defaults
  • _plugin_init

==== _plugin_init ====

Each plugin has to have a ..._plugin_init function which is called when the plugin is called. It should only set p->name to a buffer containing the name of the plugin (human readable) and should fill the hooks (init, set_defaults, cleanup) and return with 0;

==== _init ====

The ..._init function is called the initialize the plugin itself and return the plugin_data struct with some usefull defaults.

==== _free ====

..._free is called at the end of the life of a plugin and is used to tell the plugin to release all allocated memory. Keep in mind that it is preferred not to let the program termination clean up memory for you. Free what ever you have malloced. Use valgrind or something else to verify your work.

==== _set_defaults ====

As soon as the configfile is parsed each plugin gets the chance the fetch its config-values from the config and verify it internally. A config_values_t struct contains the config-key and the type you expect. Don't forget that the last entry of the struct should be NULL the mark the end.

If you don't care about conditionals the set_defaults function is quite simple:

  • set the destinations of the config_values_t
  • call config_insert_values_global()

==== conditionals ====

If you are interested in conditonals you need some more work as you have to call config_insert_values_global() once per condition. See mod_access.c how this works.

You need a config_storage for all the conditionals and a patch/setup function.

The setup function set the basic defaults, the patch function applies the necessary modifications for the currently valid conditionals.

Don't forget to check if the patched config make sense when you use it.

The setup and patch functions have to be called as soon one of the work-handlers is called like _uri_handler and friends.

{{{
#!c
mod_access_setup_connection(srv, con, p);

for (i = 0; i < srv->config_patches->used; i++) {
buffer *patch = srv->config_patches->ptr[i];

mod_access_patch_connection(srv, con, p, CONST_BUF_LEN(patch));
}
}}}

=== return values ===

HANDLER_GO_ON is return in most of the cases when you want another plugin to have a change to touch the request too. If you know that this request is not for you, just return HANDLER_GO_ON and you are done.

HANDLER_ERROR should only be called if something fatal happends as it terminates the current connection if called in one of the handlers or terminates lighttpd if called in _set_defaults.

HANDLER_WAIT_FOR_EVENT and HANDLER_WAIT_FOR_FD should be returned you are not finished yet and have the wait for and fd-event or if you ran out of FDs.

HANDLER_FINISHED is the final return-code use to signal that everything is prepared to serve the request like

  • a non-200 status-code has been set
  • content has been generated you everything is in place

HANDLER_COMEBACK is useful if you want to re-check the request-structure. This is used in mod_rewrite to handle the rewritten URI.

Updated by jan about 19 years ago · 2 revisions