Julian wrote:
are ther some documentation for constructing cherokee modules ?, for trying to rewrite mod_jk for Cherokee ?

There is not yet any fully written documentation on writing modules; but I wrote handler_example and posted this on the cherokee development mailinglist.

I hope it is a bit useful to you. In order to use your module inside the admin there is some more work to do :) But this will give you a global idea what is possible.


Stefan
--- Begin Message ---
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

Dear Alvaro,


> Comment #5 by alobbs:
> Try to include "common-internal.h" on the very top of all your source files  
> (it MUST be the first include).

Thank you very, very, much. Your suggestion was valid and I think the
place it mattered most, the header file of the main code, I forgot to
add it.

I hope I will be able to follow your instructions better, but surely you
are doing a great job in helping people and writing good software. I
hope you can review the two attached documents to help users building
their own code.


Yours Sincerely,

Stefan
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEAREKAAYFAkj35vMACgkQYH1+F2Rqwn3NugCfd4EBIiGJ2gxGkg8qn8ZJcUa7
R8kAn3yXk4BwXa+DUVrs/5Q7bJZeBryY
=8Ryy
-----END PGP SIGNATURE-----
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */

/* Cherokee
 *
 * Authors:
 *      Alvaro Lopez Ortega <[EMAIL PROTECTED]>
 *      Stefan de Konink <[EMAIL PROTECTED]>
 *
 * Copyright (C) 2001-2008 Alvaro Lopez Ortega
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of version 2 of the GNU General Public
 * License as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 */

/* Make sure common-internal.h is always the first include!
 * Otherwise you will get bad things on 32bit platforms.
 */
#include <cherokee/common-internal.h>

/* The header of our handler */
#include "handler_example.h"

/* The general Cherokee include */
#include <cherokee/cherokee.h>

/* Plug-in initialization
 *
 * In this function you can use any of these:
 * http_delete | http_get | http_post | http_put
 *
 * For a full list: cherokee_http_method_t
 *
 * It is what your handler to be implements.
 *
 */
PLUGIN_INFO_HANDLER_EASIEST_INIT (example, http_get);


/* Methods implementation
 */

/* Props_free is registered to free our properties
 * after the handler is removed by the webserver.
 * If you put any variables in your props that need
 * to be freed, here is the place. Be smart and check
 * for NULL :)
 */
static ret_t 
props_free (cherokee_handler_example_props_t *props)
{
        return cherokee_module_props_free_base (MODULE_PROPS(props));
}


/* A _configure function will be executed by the webserver
 * at the moment of 'first' initialisation. Here you do the
 * start of memory management. The processing of the configuration
 * parameters.
 */
ret_t 
cherokee_handler_example_configure (cherokee_config_node_t *conf, 
cherokee_server_t *srv, cherokee_module_props_t **_props)
{
        cherokee_list_t                      *i;
        cherokee_handler_example_props_t *props;

        if (*_props == NULL) {
                CHEROKEE_NEW_STRUCT (n, handler_example_props);

                cherokee_module_props_init_base (MODULE_PROPS(n), 
                                                 
MODULE_PROPS_FREE(props_free));                
        
        /* Look at handler_example.h
         * This is an example of configuration.
         */
                n->example_config = false;

                *_props = MODULE_PROPS(n);
        }

        props = PROP_EXAMPLE(*_props);

        /* processing of the parameters, we only know about example_config
         * it might be a good thing to abort if we found a wrong key, understand
         * the consequences: your handler will prevent the server startup upon
         * a wrong configuration.
         *
         * You see the for each method is rather creative. Read more code
         * to see with what nice things Cherokee extended the C syntax.
         */
        cherokee_config_node_foreach (i, conf) {
                cherokee_config_node_t *subconf = CONFIG_NODE(i);

                /* Cherokee has a nifty string equal function that allows
                 * lazy programmers to do strcmp without the == 0.
                 */
                if (equal_buf_str (&subconf->key, "example_config")) {
                        props->example_config = atoi(subconf->val.buf);
                } else {
                        PRINT_MSG ("ERROR: Handler file: Unknown key: '%s'\n", 
subconf->key.buf);
                        return ret_error;
                }
        }

        return ret_ok;
}

/* The new method is called when something connects to the handler.
 * It is basically the place where the webserver is going to meet your
 * functions, and you will take care that the webserver remembers where
 * you implemented your methods.
 * You can see that there is an abstract class, MODULE(n) and HANDLER(n) these
 * allow you to 'implement' a specific function within your own code. Cherokee
 * will just know where to find a pointer to it the init, free, step, 
add_headers
 * in this example.
 */
ret_t
cherokee_handler_example_new  (cherokee_handler_t **hdl, cherokee_connection_t 
*cnt, cherokee_module_props_t *props)
{
        ret_t ret;
        CHEROKEE_NEW_STRUCT (n, handler_example);
        
        /* Init the base class object
         */
        cherokee_handler_init_base(HANDLER(n), cnt, HANDLER_PROPS(props), 
PLUGIN_INFO_HANDLER_PTR(example));
           
        MODULE(n)->init         = (handler_func_init_t) 
cherokee_handler_example_init;
        MODULE(n)->free         = (module_func_free_t) 
cherokee_handler_example_free;
        HANDLER(n)->step        = (handler_func_step_t) 
cherokee_handler_example_step;
        HANDLER(n)->add_headers = (handler_func_add_headers_t) 
cherokee_handler_example_add_headers;

        HANDLER(n)->support = hsupport_length | hsupport_range;

        /* Initialisation of our output buffer
         */
        ret = cherokee_buffer_init (&n->buffer);
        if (unlikely(ret != ret_ok)) 
                return ret;

        /* We make sure we can fit at least 4k in this buffer
         * overkill, yes we know.
         */
        ret = cherokee_buffer_ensure_size (&n->buffer, 4*1024);
        if (unlikely(ret != ret_ok)) 
                return ret;

        *hdl = HANDLER(n);
        return ret_ok;
}


/* When your handler is thanked for his efforts after a request
 * we must clean up the mess we have made. In our case you might
 * remember the output buffer of 4k. We need to get rid of it
 */
ret_t 
cherokee_handler_example_free (cherokee_handler_example_t *hdl)
{
        /* remember it by: make-REAL-proper */
        cherokee_buffer_mrproper (&hdl->buffer);
        return ret_ok;
}

static void
example_build_page (cherokee_handler_example_t *hdl)
{
    /* We will make it ourselves easy, by having a
     * variable for these difficult memory locations.
     */ 
    /* cherokee_server_t *srv = HANDLER_SRV(hdl); */
    cherokee_connection_t *conn = HANDLER_CONN(hdl);

    /* We will implement double buffering
     * so we always have the complete data
     * available when we are _stepping
     */
    cherokee_buffer_t buf = CHEROKEE_BUF_INIT;

    /* Useful output to the user. */
    cherokee_buffer_add_str (&buf, "Hello World\n");
    cherokee_buffer_add_va (&buf, "Used method: %s", (conn->header.method == 1 
? "GET" : "Other") );

    /* But we did configure something! */
    if (HDL_EXAMPLE_PROPS(hdl)->example_config) {
        cherokee_buffer_add_str (&buf, "!!!");
    }

    /* We are now finished and will need to copy one
     * buffer to the other. Performance wise you are
     * copying data, that is suboptimal.
     */
    cherokee_buffer_add_buffer (&hdl->buffer, &buf);

    /* What is used, should be freed */
    cherokee_buffer_mrproper (&buf);
}

ret_t 
cherokee_handler_example_init (cherokee_handler_example_t *hdl)
{
        /* An idea is to implement a state machine to allow different
         * types of content to be build */ 
        
        hdl->action = send_page;
        example_build_page (hdl);

        return ret_ok;
}

/* The _step function is called by the webserver when your handler
 * should provide content. Important to realise is that this method
 * can be called multiple times, and not all data has to be present
 * when this function is first called.
 * You could argue that this code is overkill for the current purpose
 * and it is :)
 */
ret_t 
cherokee_handler_example_step (cherokee_handler_example_t *hdl, 
cherokee_buffer_t *buffer)
{
        cuint_t tosend;

        /* Check if we have actually something to send,
         * if there is nothing, we have reached the end of
         * the contents and thus should mention an end-of-file.
         *
         * We advise you to always use *double* buffering in
         * the build_page function for things that are known to
         * grow and take more time. If directly is written
         * into the buffer, the handler might kill the request
         * while still data is comming in.
         */
        if (cherokee_buffer_is_empty (&hdl->buffer))
                return ret_eof;
        
        /* We will send up to 1k chunks each time the _step function is called 
*/
        tosend = (hdl->buffer.len > 1024 ? 1024 : hdl->buffer.len);

        /* To the send buffer, we copy 'tosend' amount of bytes */
        cherokee_buffer_add (buffer, hdl->buffer.buf, tosend);

        /* We don't want to send this the next time, therefore we
         * remove what we have send from the output buffer.
         */
        cherokee_buffer_move_to_begin (&hdl->buffer, tosend);

        /* A minor optimalisation is to check if the buffer were
         * processing is now empty, if it is, we can inform the
         * webserver that the data is all outputed to the send buffer
         */
        if (cherokee_buffer_is_empty (&hdl->buffer))
                return ret_eof_have_data;

        /* Otherwise we will inform that we are not done _stepping.
         * As you can see, if we didn't implement the previous
         * ret_eof_have_data, the next time the _step method is called
         * it would ask the same question. Hence we save one time of
         * stepping. (Remember Cherokee is a High Performance webserver
         * your handler should be HP too ;)
         */
        return ret_ok;
}

/* The _add_headers function is typically a moment in your code that
 * everything has been done. You know something about your buffers,
 * and want to make the webserver happy.
 */
ret_t 
cherokee_handler_example_add_headers (cherokee_handler_example_t *hdl, 
cherokee_buffer_t *buffer)
{
        /* This makes sending and receiving faster, because we provide the 
length
         * thus the client knows exactly what to expect.
         */
        cherokee_buffer_add_va (buffer, "Content-Length: %d"CRLF, 
hdl->buffer.len);

        /* A possible implementation of a state machine */
        switch (hdl->action) {
        case send_page:
        default:
                /* This will make everyone happy, and tell what kind of thing
                 * we are transmitting to the client and how the client should
                 * open it.
                 */
                cherokee_buffer_add_str (buffer, "Content-Type: 
text/plain"CRLF);
                    break;
        }

        return ret_ok;
}
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */

/* Cherokee
 *
 * Authors:
 *      Alvaro Lopez Ortega <[EMAIL PROTECTED]>
 *      Stefan de Konink <[EMAIL PROTECTED]>
 *
 * Copyright (C) 2001-2008 Alvaro Lopez Ortega
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of version 2 of the GNU General Public
 * License as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 */

#ifndef CHEROKEE_HANDLER_EXAMPLE_H
#define CHEROKEE_HANDLER_EXAMPLE_H

/* Always start with common-internal.h */
#include <cherokee/common-internal.h>
/* The the more general things */
#include <cherokee/cherokee.h>

/* Data types
 */
typedef struct {
        /* The foundation of the handler is here */
        cherokee_module_props_t  base;

        /* Our own configuration parameters */
        cherokee_boolean_t       example_config;
} cherokee_handler_example_props_t;

typedef struct {
    /* Shared structures */
        cherokee_handler_t       handler;

    /* A buffer is your output 'to be' */
        cherokee_buffer_t        buffer;

    /* Our state machine */
    enum {
        send_page,
        send_yourmother /* not advised but possible */
    } action;
} cherokee_handler_example_t;

/* Easy access methods, ALWAYS implement them for your own handler! */
#define HDL_EXAMPLE(x)       ((cherokee_handler_example_t *)(x))
#define PROP_EXAMPLE(x)      ((cherokee_handler_example_props_t *)(x))
#define HDL_EXAMPLE_PROPS(x) (PROP_EXAMPLE(MODULE(x)->props))


/* Library init function
 */
void  PLUGIN_INIT_NAME(example)      (cherokee_plugin_loader_t *loader);
ret_t cherokee_handler_example_new   (cherokee_handler_t **hdl, 
cherokee_connection_t *cnt, cherokee_module_props_t *props);

/* virtual methods implementation
 */
ret_t cherokee_handler_example_init        (cherokee_handler_example_t *hdl);
ret_t cherokee_handler_example_free        (cherokee_handler_example_t *hdl);
ret_t cherokee_handler_example_step        (cherokee_handler_example_t *hdl, 
cherokee_buffer_t *buffer);
ret_t cherokee_handler_example_add_headers (cherokee_handler_example_t *hdl, 
cherokee_buffer_t *buffer);

#endif /* CHEROKEE_HANDLER_EXAMPLE_H */

--- End Message ---
_______________________________________________
Cherokee mailing list
[email protected]
http://lists.octality.com/listinfo/cherokee

Reply via email to