--- 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 ---