diff options
Diffstat (limited to 'libs/sgi-webuci/boa-patches/200-plugin_api.patch')
-rw-r--r-- | libs/sgi-webuci/boa-patches/200-plugin_api.patch | 1089 |
1 files changed, 1089 insertions, 0 deletions
diff --git a/libs/sgi-webuci/boa-patches/200-plugin_api.patch b/libs/sgi-webuci/boa-patches/200-plugin_api.patch new file mode 100644 index 000000000..de7999159 --- /dev/null +++ b/libs/sgi-webuci/boa-patches/200-plugin_api.patch @@ -0,0 +1,1089 @@ +Index: boa-0.94.13/src/list.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ boa-0.94.13/src/list.h 2008-05-27 19:28:21.000000000 +0200 +@@ -0,0 +1,601 @@ ++#ifndef _LINUX_LIST_H ++#define _LINUX_LIST_H ++ ++#include <stddef.h> ++/** ++ * container_of - cast a member of a structure out to the containing structure ++ * @ptr: the pointer to the member. ++ * @type: the type of the container struct this is embedded in. ++ * @member: the name of the member within the struct. ++ * ++ */ ++#ifndef container_of ++#define container_of(ptr, type, member) ( \ ++ (type *)( (char *)ptr - offsetof(type,member) )) ++#endif ++ ++ ++/* ++ * Simple doubly linked list implementation. ++ * ++ * Some of the internal functions ("__xxx") are useful when ++ * manipulating whole lists rather than single entries, as ++ * sometimes we already know the next/prev entries and we can ++ * generate better code by using them directly rather than ++ * using the generic single-entry routines. ++ */ ++ ++struct list_head { ++ struct list_head *next, *prev; ++}; ++ ++#define LIST_HEAD_INIT(name) { &(name), &(name) } ++ ++#define LIST_HEAD(name) \ ++ struct list_head name = LIST_HEAD_INIT(name) ++ ++static inline void INIT_LIST_HEAD(struct list_head *list) ++{ ++ list->next = list; ++ list->prev = list; ++} ++ ++/* ++ * Insert a new entry between two known consecutive entries. ++ * ++ * This is only for internal list manipulation where we know ++ * the prev/next entries already! ++ */ ++static inline void __list_add(struct list_head *new, ++ struct list_head *prev, ++ struct list_head *next) ++{ ++ next->prev = new; ++ new->next = next; ++ new->prev = prev; ++ prev->next = new; ++} ++ ++/** ++ * list_add - add a new entry ++ * @new: new entry to be added ++ * @head: list head to add it after ++ * ++ * Insert a new entry after the specified head. ++ * This is good for implementing stacks. ++ */ ++static inline void list_add(struct list_head *new, struct list_head *head) ++{ ++ __list_add(new, head, head->next); ++} ++ ++ ++/** ++ * list_add_tail - add a new entry ++ * @new: new entry to be added ++ * @head: list head to add it before ++ * ++ * Insert a new entry before the specified head. ++ * This is useful for implementing queues. ++ */ ++static inline void list_add_tail(struct list_head *new, struct list_head *head) ++{ ++ __list_add(new, head->prev, head); ++} ++ ++ ++/* ++ * Delete a list entry by making the prev/next entries ++ * point to each other. ++ * ++ * This is only for internal list manipulation where we know ++ * the prev/next entries already! ++ */ ++static inline void __list_del(struct list_head * prev, struct list_head * next) ++{ ++ next->prev = prev; ++ prev->next = next; ++} ++ ++/** ++ * list_del - deletes entry from list. ++ * @entry: the element to delete from the list. ++ * Note: list_empty() on entry does not return true after this, the entry is ++ * in an undefined state. ++ */ ++static inline void list_del(struct list_head *entry) ++{ ++ __list_del(entry->prev, entry->next); ++ entry->next = NULL; ++ entry->prev = NULL; ++} ++ ++/** ++ * list_replace - replace old entry by new one ++ * @old : the element to be replaced ++ * @new : the new element to insert ++ * ++ * If @old was empty, it will be overwritten. ++ */ ++static inline void list_replace(struct list_head *old, ++ struct list_head *new) ++{ ++ new->next = old->next; ++ new->next->prev = new; ++ new->prev = old->prev; ++ new->prev->next = new; ++} ++ ++static inline void list_replace_init(struct list_head *old, ++ struct list_head *new) ++{ ++ list_replace(old, new); ++ INIT_LIST_HEAD(old); ++} ++ ++/** ++ * list_del_init - deletes entry from list and reinitialize it. ++ * @entry: the element to delete from the list. ++ */ ++static inline void list_del_init(struct list_head *entry) ++{ ++ __list_del(entry->prev, entry->next); ++ INIT_LIST_HEAD(entry); ++} ++ ++/** ++ * list_move - delete from one list and add as another's head ++ * @list: the entry to move ++ * @head: the head that will precede our entry ++ */ ++static inline void list_move(struct list_head *list, struct list_head *head) ++{ ++ __list_del(list->prev, list->next); ++ list_add(list, head); ++} ++ ++/** ++ * list_move_tail - delete from one list and add as another's tail ++ * @list: the entry to move ++ * @head: the head that will follow our entry ++ */ ++static inline void list_move_tail(struct list_head *list, ++ struct list_head *head) ++{ ++ __list_del(list->prev, list->next); ++ list_add_tail(list, head); ++} ++ ++/** ++ * list_is_last - tests whether @list is the last entry in list @head ++ * @list: the entry to test ++ * @head: the head of the list ++ */ ++static inline int list_is_last(const struct list_head *list, ++ const struct list_head *head) ++{ ++ return list->next == head; ++} ++ ++/** ++ * list_empty - tests whether a list is empty ++ * @head: the list to test. ++ */ ++static inline int list_empty(const struct list_head *head) ++{ ++ return head->next == head; ++} ++ ++/** ++ * list_empty_careful - tests whether a list is empty and not being modified ++ * @head: the list to test ++ * ++ * Description: ++ * tests whether a list is empty _and_ checks that no other CPU might be ++ * in the process of modifying either member (next or prev) ++ * ++ * NOTE: using list_empty_careful() without synchronization ++ * can only be safe if the only activity that can happen ++ * to the list entry is list_del_init(). Eg. it cannot be used ++ * if another CPU could re-list_add() it. ++ */ ++static inline int list_empty_careful(const struct list_head *head) ++{ ++ struct list_head *next = head->next; ++ return (next == head) && (next == head->prev); ++} ++ ++static inline void __list_splice(struct list_head *list, ++ struct list_head *head) ++{ ++ struct list_head *first = list->next; ++ struct list_head *last = list->prev; ++ struct list_head *at = head->next; ++ ++ first->prev = head; ++ head->next = first; ++ ++ last->next = at; ++ at->prev = last; ++} ++ ++/** ++ * list_splice - join two lists ++ * @list: the new list to add. ++ * @head: the place to add it in the first list. ++ */ ++static inline void list_splice(struct list_head *list, struct list_head *head) ++{ ++ if (!list_empty(list)) ++ __list_splice(list, head); ++} ++ ++/** ++ * list_splice_init - join two lists and reinitialise the emptied list. ++ * @list: the new list to add. ++ * @head: the place to add it in the first list. ++ * ++ * The list at @list is reinitialised ++ */ ++static inline void list_splice_init(struct list_head *list, ++ struct list_head *head) ++{ ++ if (!list_empty(list)) { ++ __list_splice(list, head); ++ INIT_LIST_HEAD(list); ++ } ++} ++ ++/** ++ * list_entry - get the struct for this entry ++ * @ptr: the &struct list_head pointer. ++ * @type: the type of the struct this is embedded in. ++ * @member: the name of the list_struct within the struct. ++ */ ++#define list_entry(ptr, type, member) \ ++ container_of(ptr, type, member) ++ ++/** ++ * list_first_entry - get the first element from a list ++ * @ptr: the list head to take the element from. ++ * @type: the type of the struct this is embedded in. ++ * @member: the name of the list_struct within the struct. ++ * ++ * Note, that list is expected to be not empty. ++ */ ++#define list_first_entry(ptr, type, member) \ ++ list_entry((ptr)->next, type, member) ++ ++/** ++ * list_for_each - iterate over a list ++ * @pos: the &struct list_head to use as a loop cursor. ++ * @head: the head for your list. ++ */ ++#define list_for_each(pos, head) \ ++ for (pos = (head)->next; pos != (head); \ ++ pos = pos->next) ++ ++/** ++ * __list_for_each - iterate over a list ++ * @pos: the &struct list_head to use as a loop cursor. ++ * @head: the head for your list. ++ * ++ * This variant differs from list_for_each() in that it's the ++ * simplest possible list iteration code, no prefetching is done. ++ * Use this for code that knows the list to be very short (empty ++ * or 1 entry) most of the time. ++ */ ++#define __list_for_each(pos, head) \ ++ for (pos = (head)->next; pos != (head); pos = pos->next) ++ ++/** ++ * list_for_each_prev - iterate over a list backwards ++ * @pos: the &struct list_head to use as a loop cursor. ++ * @head: the head for your list. ++ */ ++#define list_for_each_prev(pos, head) \ ++ for (pos = (head)->prev; pos != (head); \ ++ pos = pos->prev) ++ ++/** ++ * list_for_each_safe - iterate over a list safe against removal of list entry ++ * @pos: the &struct list_head to use as a loop cursor. ++ * @n: another &struct list_head to use as temporary storage ++ * @head: the head for your list. ++ */ ++#define list_for_each_safe(pos, n, head) \ ++ for (pos = (head)->next, n = pos->next; pos != (head); \ ++ pos = n, n = pos->next) ++ ++/** ++ * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry ++ * @pos: the &struct list_head to use as a loop cursor. ++ * @n: another &struct list_head to use as temporary storage ++ * @head: the head for your list. ++ */ ++#define list_for_each_prev_safe(pos, n, head) \ ++ for (pos = (head)->prev, n = pos->prev; \ ++ pos != (head); \ ++ pos = n, n = pos->prev) ++ ++/** ++ * list_for_each_entry - iterate over list of given type ++ * @pos: the type * to use as a loop cursor. ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. ++ */ ++#define list_for_each_entry(pos, head, member) \ ++ for (pos = list_entry((head)->next, typeof(*pos), member); \ ++ &pos->member != (head); \ ++ pos = list_entry(pos->member.next, typeof(*pos), member)) ++ ++/** ++ * list_for_each_entry_reverse - iterate backwards over list of given type. ++ * @pos: the type * to use as a loop cursor. ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. ++ */ ++#define list_for_each_entry_reverse(pos, head, member) \ ++ for (pos = list_entry((head)->prev, typeof(*pos), member); \ ++ &pos->member != (head); \ ++ pos = list_entry(pos->member.prev, typeof(*pos), member)) ++ ++/** ++ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() ++ * @pos: the type * to use as a start point ++ * @head: the head of the list ++ * @member: the name of the list_struct within the struct. ++ * ++ * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). ++ */ ++#define list_prepare_entry(pos, head, member) \ ++ ((pos) ? : list_entry(head, typeof(*pos), member)) ++ ++/** ++ * list_for_each_entry_continue - continue iteration over list of given type ++ * @pos: the type * to use as a loop cursor. ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. ++ * ++ * Continue to iterate over list of given type, continuing after ++ * the current position. ++ */ ++#define list_for_each_entry_continue(pos, head, member) \ ++ for (pos = list_entry(pos->member.next, typeof(*pos), member); \ ++ &pos->member != (head); \ ++ pos = list_entry(pos->member.next, typeof(*pos), member)) ++ ++/** ++ * list_for_each_entry_continue_reverse - iterate backwards from the given point ++ * @pos: the type * to use as a loop cursor. ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. ++ * ++ * Start to iterate over list of given type backwards, continuing after ++ * the current position. ++ */ ++#define list_for_each_entry_continue_reverse(pos, head, member) \ ++ for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ ++ &pos->member != (head); \ ++ pos = list_entry(pos->member.prev, typeof(*pos), member)) ++ ++/** ++ * list_for_each_entry_from - iterate over list of given type from the current point ++ * @pos: the type * to use as a loop cursor. ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. ++ * ++ * Iterate over list of given type, continuing from current position. ++ */ ++#define list_for_each_entry_from(pos, head, member) \ ++ for (; &pos->member != (head); \ ++ pos = list_entry(pos->member.next, typeof(*pos), member)) ++ ++/** ++ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry ++ * @pos: the type * to use as a loop cursor. ++ * @n: another type * to use as temporary storage ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. ++ */ ++#define list_for_each_entry_safe(pos, n, head, member) \ ++ for (pos = list_entry((head)->next, typeof(*pos), member), \ ++ n = list_entry(pos->member.next, typeof(*pos), member); \ ++ &pos->member != (head); \ ++ pos = n, n = list_entry(n->member.next, typeof(*n), member)) ++ ++/** ++ * list_for_each_entry_safe_continue ++ * @pos: the type * to use as a loop cursor. ++ * @n: another type * to use as temporary storage ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. ++ * ++ * Iterate over list of given type, continuing after current point, ++ * safe against removal of list entry. ++ */ ++#define list_for_each_entry_safe_continue(pos, n, head, member) \ ++ for (pos = list_entry(pos->member.next, typeof(*pos), member), \ ++ n = list_entry(pos->member.next, typeof(*pos), member); \ ++ &pos->member != (head); \ ++ pos = n, n = list_entry(n->member.next, typeof(*n), member)) ++ ++/** ++ * list_for_each_entry_safe_from ++ * @pos: the type * to use as a loop cursor. ++ * @n: another type * to use as temporary storage ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. ++ * ++ * Iterate over list of given type from current point, safe against ++ * removal of list entry. ++ */ ++#define list_for_each_entry_safe_from(pos, n, head, member) \ ++ for (n = list_entry(pos->member.next, typeof(*pos), member); \ ++ &pos->member != (head); \ ++ pos = n, n = list_entry(n->member.next, typeof(*n), member)) ++ ++/** ++ * list_for_each_entry_safe_reverse ++ * @pos: the type * to use as a loop cursor. ++ * @n: another type * to use as temporary storage ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. ++ * ++ * Iterate backwards over list of given type, safe against removal ++ * of list entry. ++ */ ++#define list_for_each_entry_safe_reverse(pos, n, head, member) \ ++ for (pos = list_entry((head)->prev, typeof(*pos), member), \ ++ n = list_entry(pos->member.prev, typeof(*pos), member); \ ++ &pos->member != (head); \ ++ pos = n, n = list_entry(n->member.prev, typeof(*n), member)) ++ ++/* ++ * Double linked lists with a single pointer list head. ++ * Mostly useful for hash tables where the two pointer list head is ++ * too wasteful. ++ * You lose the ability to access the tail in O(1). ++ */ ++ ++struct hlist_head { ++ struct hlist_node *first; ++}; ++ ++struct hlist_node { ++ struct hlist_node *next, **pprev; ++}; ++ ++#define HLIST_HEAD_INIT { .first = NULL } ++#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } ++#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) ++static inline void INIT_HLIST_NODE(struct hlist_node *h) ++{ ++ h->next = NULL; ++ h->pprev = NULL; ++} ++ ++static inline int hlist_unhashed(const struct hlist_node *h) ++{ ++ return !h->pprev; ++} ++ ++static inline int hlist_empty(const struct hlist_head *h) ++{ ++ return !h->first; ++} ++ ++static inline void __hlist_del(struct hlist_node *n) ++{ ++ struct hlist_node *next = n->next; ++ struct hlist_node **pprev = n->pprev; ++ *pprev = next; ++ if (next) ++ next->pprev = pprev; ++} ++ ++static inline void hlist_del(struct hlist_node *n) ++{ ++ __hlist_del(n); ++ n->next = NULL; ++ n->pprev = NULL; ++} ++ ++static inline void hlist_del_init(struct hlist_node *n) ++{ ++ if (!hlist_unhashed(n)) { ++ __hlist_del(n); ++ INIT_HLIST_NODE(n); ++ } ++} ++ ++ ++static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) ++{ ++ struct hlist_node *first = h->first; ++ n->next = first; ++ if (first) ++ first->pprev = &n->next; ++ h->first = n; ++ n->pprev = &h->first; ++} ++ ++ ++/* next must be != NULL */ ++static inline void hlist_add_before(struct hlist_node *n, ++ struct hlist_node *next) ++{ ++ n->pprev = next->pprev; ++ n->next = next; ++ next->pprev = &n->next; ++ *(n->pprev) = n; ++} ++ ++static inline void hlist_add_after(struct hlist_node *n, ++ struct hlist_node *next) ++{ ++ next->next = n->next; ++ n->next = next; ++ next->pprev = &n->next; ++ ++ if(next->next) ++ next->next->pprev = &next->next; ++} ++ ++#define hlist_entry(ptr, type, member) container_of(ptr,type,member) ++ ++#define hlist_for_each(pos, head) \ ++ for (pos = (head)->first; pos; pos = pos->next) ++ ++#define hlist_for_each_safe(pos, n, head) \ ++ for (pos = (head)->first; pos; pos = n) ++ ++/** ++ * hlist_for_each_entry - iterate over list of given type ++ * @tpos: the type * to use as a loop cursor. ++ * @pos: the &struct hlist_node to use as a loop cursor. ++ * @head: the head for your list. ++ * @member: the name of the hlist_node within the struct. ++ */ ++#define hlist_for_each_entry(tpos, pos, head, member) \ ++ for (pos = (head)->first; pos && \ ++ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ ++ pos = pos->next) ++ ++/** ++ * hlist_for_each_entry_continue - iterate over a hlist continuing after current point ++ * @tpos: the type * to use as a loop cursor. ++ * @pos: the &struct hlist_node to use as a loop cursor. ++ * @member: the name of the hlist_node within the struct. ++ */ ++#define hlist_for_each_entry_continue(tpos, pos, member) \ ++ for (pos = (pos)->next; pos && \ ++ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ ++ pos = pos->next) ++ ++/** ++ * hlist_for_each_entry_from - iterate over a hlist continuing from current point ++ * @tpos: the type * to use as a loop cursor. ++ * @pos: the &struct hlist_node to use as a loop cursor. ++ * @member: the name of the hlist_node within the struct. ++ */ ++#define hlist_for_each_entry_from(tpos, pos, member) \ ++ for (; pos && \ ++ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ ++ pos = pos->next) ++ ++/** ++ * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry ++ * @tpos: the type * to use as a loop cursor. ++ * @pos: the &struct hlist_node to use as a loop cursor. ++ * @n: another &struct hlist_node to use as temporary storage ++ * @head: the head for your list. ++ * @member: the name of the hlist_node within the struct. ++ */ ++#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ ++ for (pos = (head)->first; \ ++ pos && ({ n = pos->next; 1; }) && \ ++ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ ++ pos = n) ++ ++#endif +Index: boa-0.94.13/src/plugin.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ boa-0.94.13/src/plugin.c 2008-05-27 19:28:21.000000000 +0200 +@@ -0,0 +1,189 @@ ++/* ++ * Simple plugin API for boa ++ * Copyright (C) 2008 John Crispin <blogic@openwrt.org> ++ * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include "boa.h" ++#include "list.h" ++#include <dlfcn.h> ++#include <glob.h> ++ ++static LIST_HEAD(plugins); ++ ++struct httpd_plugin *plugin_lookup(request *req) ++{ ++ struct list_head *l; ++ list_for_each(l, &plugins) ++ { ++ struct httpd_plugin *p = ++ container_of(l, struct httpd_plugin, list); ++ ++ if (!strncmp(req->request_uri, p->prefix, strlen(p->prefix))) ++ return p; ++ } ++ return NULL; ++} ++ ++static int plugin_run(request *req, struct httpd_plugin *p) ++{ ++ struct http_context ctx; ++ int child_pid; ++ ++ SQUASH_KA(req); ++ ++ memset(&ctx, 0, sizeof(ctx)); ++ ctx.uri = req->request_uri; ++ switch(req->method) { ++ case M_POST: ++ ctx.request_method = "POST"; ++ break; ++ case M_HEAD: ++ ctx.request_method = "HEAD"; ++ break; ++ case M_GET: ++ ctx.request_method = "GET"; ++ break; ++ } ++ ctx.server_addr = req->local_ip_addr; ++ ctx.server_proto = req->http_version; ++ ctx.query_string = req->query_string; ++ ctx.remote_addr = req->remote_ip_addr; ++ ctx.remote_port = req->remote_port; ++ if (req->method == M_POST) { ++ if (req->content_type) ++ ctx.content_type = req->content_type; ++ else ++ ctx.content_type = default_type; ++ ctx.content_length = req->content_length; ++ } ++#ifdef ACCEPT_ON ++ if (req->accept[0]) ++ ctx.http_accept = req->accept; ++#endif ++ ++ p->prepare_req(p, &ctx); ++ child_pid = fork(); ++ ++ switch(child_pid) { ++ case -1: ++ log_error_time(); ++ perror("fork"); ++ send_r_error(req); ++ return 0; ++ ++ case 0: ++ if (dup2(req->fd, STDOUT_FILENO) == -1) { ++ log_error_time(); ++ perror("dup2 - fd"); ++ _exit(1); ++ } ++ if (set_block_fd(req->fd) == -1) { ++ log_error_time(); ++ perror("cgi-fcntl"); ++ _exit(1); ++ } ++ if (req->method == M_POST) { ++ dup2(req->read_data_fd, STDIN_FILENO); ++ close(req->read_data_fd); ++ close(req->post_data_fd); ++ set_block_fd(STDIN_FILENO); ++ } ++ close_access_log(); ++ ++ if (cgi_log_fd) ++ dup2(cgi_log_fd, STDERR_FILENO); ++ ++ p->handle_req(p, &ctx); ++ exit(0); ++ break; ++ } ++ ++ return 1; ++} ++ ++int plugin_handle(request * req) ++{ ++ struct httpd_plugin *p; ++ ++ p = plugin_lookup(req); ++ if (!p) ++ return 0; ++ ++ return plugin_run(req, p); ++} ++ ++static void plugin_load(const char *p, const char *dir) ++{ ++ struct httpd_plugin *plugin; ++ void *dl; ++ ++ /* ignore directories */ ++ if (p[strlen(p) - 1] == '/') ++ return; ++ ++ dl = dlopen(p, RTLD_NOW); ++ if (!dl) { ++ fprintf(stderr, "Unable to load plugin '%s': %d\n", p, dlerror()); ++ return; ++ } ++ ++ plugin = dlsym(dl, "httpd_plugin"); ++ if (!plugin) ++ goto error; ++ ++ INIT_LIST_HEAD(&plugin->list); ++ plugin->dir = dir; ++ ++ if (plugin->init(plugin) != 1) ++ goto error; ++ ++ if (!plugin->prefix) ++ goto error_init; ++ ++ list_add(&plugin->list, &plugins); ++ return; ++ ++error_init: ++ plugin->done(plugin); ++error: ++ fprintf(stderr, "Plugin '%s' failed to initialize\n", p); ++ dlclose(dl); ++} ++ ++#define WILDCARD_SUFFIX "/*.so" ++ ++int plugin_init(char *path) ++{ ++ int buflen = 128; ++ char *plugindir; ++ glob_t g; ++ char *s; ++ int i; ++ ++ s = malloc(strlen(path) + sizeof(WILDCARD_SUFFIX) + 1); ++ strcpy(s, path); ++ strcat(s, WILDCARD_SUFFIX); ++ glob(s, GLOB_MARK, NULL, &g); ++ free(s); ++ ++ for (i = 0; i < g.gl_pathc; i++) ++ plugin_load(g.gl_pathv[i], path); ++ ++ globfree(&g); ++} ++ ++ +Index: boa-0.94.13/src/request.c +=================================================================== +--- boa-0.94.13.orig/src/request.c 2002-07-24 05:03:59.000000000 +0200 ++++ boa-0.94.13/src/request.c 2008-05-27 19:28:21.000000000 +0200 +@@ -50,6 +50,7 @@ + dequeue(&request_free, request_free); /* dequeue the head */ + } else { + req = (request *) malloc(sizeof (request)); ++ memset(req, 0, sizeof(request)); + if (!req) { + log_error_time(); + perror("malloc for new request"); +@@ -603,6 +604,8 @@ + + int process_header_end(request * req) + { ++ int ret; ++ + if (!req->logline) { + send_r_error(req); + return 0; +@@ -630,11 +633,26 @@ + } + + if (req->method == M_POST) { +- req->post_data_fd = create_temporary_file(1, NULL, 0); +- if (req->post_data_fd == 0) +- return(0); +- return(1); /* success */ +- } ++ if (!req->plugin) { ++ req->post_data_fd = create_temporary_file(1, NULL, 0); ++ } else { ++ int fd[2]; ++ if (pipe(&fd[0]) != -1) { ++ req->post_data_fd = fd[1]; ++ req->read_data_fd = fd[0]; ++ set_nonblock_fd(req->post_data_fd); ++ } ++ } ++ if (req->post_data_fd == 0) { ++ return(0); ++ } ++ if (!req->plugin) ++ return(1); /* success */ ++ } ++ ++ ret = plugin_handle(req); ++ if (ret) ++ return ret; + + if (req->is_cgi) { + return init_cgi(req); +Index: boa-0.94.13/src/Makefile.in +=================================================================== +--- boa-0.94.13.orig/src/Makefile.in 2002-03-24 23:20:19.000000000 +0100 ++++ boa-0.94.13/src/Makefile.in 2008-05-27 19:28:21.000000000 +0200 +@@ -20,7 +20,7 @@ + srcdir = @srcdir@ + VPATH = @srcdir@:@srcdir@/../extras + LDFLAGS = @LDFLAGS@ +-LIBS = @LIBS@ ++LIBS = @LIBS@ -ldl + CFLAGS = @CFLAGS@ -I. + + # Change these if necessary +@@ -32,7 +32,8 @@ + + SOURCES = alias.c boa.c buffer.c cgi.c cgi_header.c config.c escape.c \ + get.c hash.c ip.c log.c mmap_cache.c pipe.c queue.c read.c \ +- request.c response.c select.c signals.c util.c sublog.c ++ request.c response.c select.c signals.c util.c sublog.c \ ++ plugin.c + + OBJS = y.tab.o lex.yy.o $(SOURCES:.c=.o) timestamp.o @STRUTIL@ + +Index: boa-0.94.13/src/boa.h +=================================================================== +--- boa-0.94.13.orig/src/boa.h 2002-07-26 05:03:44.000000000 +0200 ++++ boa-0.94.13/src/boa.h 2008-05-27 19:28:21.000000000 +0200 +@@ -37,6 +37,7 @@ + #include <fcntl.h> + #include <limits.h> /* OPEN_MAX */ + #include <setjmp.h> ++#include <stdbool.h> + + #include <netdb.h> + #include <netinet/in.h> +@@ -50,6 +51,7 @@ + #include "compat.h" /* oh what fun is porting */ + #include "defines.h" + #include "globals.h" ++#include "boa-plugin.h" + + /* alias */ + void add_alias(char *fakename, char *realname, int script); +@@ -192,4 +194,9 @@ + /* select */ + void select_loop(int server_s); + ++/* plugins */ ++int plugin_init(char *path); ++int plugin_handle(request * req); ++struct httpd_plugin *plugin_lookup(request *req); ++ + #endif +Index: boa-0.94.13/src/config.c +=================================================================== +--- boa-0.94.13.orig/src/config.c 2002-07-26 05:04:29.000000000 +0200 ++++ boa-0.94.13/src/config.c 2008-05-27 19:28:21.000000000 +0200 +@@ -61,6 +61,7 @@ + char *error_log_name; + char *access_log_name; + char *cgi_log_name; ++char *plugin_root = NULL; + + int use_localtime; + +@@ -116,6 +117,7 @@ + {"SinglePostLimit", S1A, c_set_int, &single_post_limit}, + {"CGIPath", S1A, c_set_string, &cgi_path}, + {"MaxConnections", S1A, c_set_int, &max_connections}, ++ {"PluginRoot", S1A, c_set_string, &plugin_root}, + }; + + static void c_set_user(char *v1, char *v2, void *t) +@@ -323,6 +325,22 @@ + free(dirmaker); + dirmaker = temp; + } ++ if (plugin_root) { ++ char *plugin_path = plugin_root; ++ char *next; ++ ++ do { ++ next = strchr(plugin_path, ':'); ++ if (next) { ++ *next = 0; ++ next++; ++ } ++ ++ plugin_init(normalize_path(plugin_path)); ++ plugin_path = next; ++ } while (plugin_path); ++ free(plugin_root); ++ } + + #if 0 + if (mime_types) { +Index: boa-0.94.13/src/alias.c +=================================================================== +--- boa-0.94.13.orig/src/alias.c 2002-07-28 04:46:52.000000000 +0200 ++++ boa-0.94.13/src/alias.c 2008-05-27 19:28:21.000000000 +0200 +@@ -213,6 +213,7 @@ + uri_len = strlen(req->request_uri); + + current = find_alias(req->request_uri, uri_len); ++ req->plugin = !!plugin_lookup(req); + if (current) { + + if (current->type == SCRIPTALIAS) /* Script */ +@@ -237,7 +238,7 @@ + } + + if (current->type == REDIRECT) { /* Redirect */ +- if (req->method == M_POST) { /* POST to non-script */ ++ if ((req->method == M_POST) && !req->plugin) { /* POST to non-script */ + /* it's not a cgi, but we try to POST??? */ + send_r_bad_request(req); + return 0; /* not a script alias, therefore begin filling in data */ +@@ -361,7 +362,7 @@ + else + req->is_cgi = CGI; + return 1; +- } else if (req->method == M_POST) { /* POST to non-script */ ++ } else if ((req->method == M_POST) && !req->plugin) { /* POST to non-script */ + /* it's not a cgi, but we try to POST??? */ + send_r_bad_request(req); + return 0; +Index: boa-0.94.13/src/globals.h +=================================================================== +--- boa-0.94.13.orig/src/globals.h 2002-07-24 05:03:59.000000000 +0200 ++++ boa-0.94.13/src/globals.h 2008-05-27 19:28:21.000000000 +0200 +@@ -47,6 +47,7 @@ + struct request { /* pending requests */ + int fd; /* client's socket fd */ + int status; /* see #defines.h */ ++ bool plugin; + time_t time_last; /* time of last succ. op. */ + char *pathname; /* pathname of requested file */ + int simple; /* simple request? */ +@@ -92,6 +93,7 @@ + char *header_referer; + + int post_data_fd; /* fd for post data tmpfile */ ++ int read_data_fd; /* fd for post data input (plugin) */ + + char *path_info; /* env variable */ + char *path_translated; /* env variable */ +Index: boa-0.94.13/src/read.c +=================================================================== +--- boa-0.94.13.orig/src/read.c 2002-03-18 02:53:48.000000000 +0100 ++++ boa-0.94.13/src/read.c 2008-05-27 19:28:21.000000000 +0200 +@@ -338,8 +338,11 @@ + + if (bytes_to_write == 0) { /* nothing left in buffer to write */ + req->header_line = req->header_end = req->buffer; +- if (req->filepos >= req->filesize) +- return init_cgi(req); ++ if (req->filepos >= req->filesize) { ++ if (req->post_data_fd > 0) ++ close(req->post_data_fd); ++ return init_cgi(req); ++ } + /* if here, we can safely assume that there is more to read */ + req->status = BODY_READ; + return 1; +Index: boa-0.94.13/src/boa-plugin.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ boa-0.94.13/src/boa-plugin.h 2008-05-27 19:28:21.000000000 +0200 +@@ -0,0 +1,67 @@ ++#ifndef _HTTPD_PLUGIN_H__ ++#define _HTTPD_PLUGIN_H__ ++ ++#include "list.h" ++ ++/* ++ * Definition for HTTP server plugins ++ * ++ * The context that the plugin is called with for ++ * a single http request. It gets allocated in the ++ * persistent context before prepare_req and freed ++ * there afterwards (still active in the forked ++ * context at handle_req time) ++ */ ++struct http_context ++{ ++ char *uri; ++ char *request_method; ++ char *server_addr; ++ char *server_proto; ++ char *query_string; ++ char *remote_addr; ++ unsigned int remote_port; ++ char *content_type; ++ char *content_length; ++ char *http_accept; ++ ++ void *priv; ++}; ++ ++/* ++ * the main data structure of httpd plugins. ++ */ ++struct httpd_plugin ++{ ++ /* used by the web server */ ++ struct list_head list; ++ ++ /* only page requests matching 'prefix' are passed ++ * to prepare_req and handle_req */ ++ const char *prefix; ++ ++ /* directory that the plugin was found in */ ++ const char *dir; ++ ++ /* initialize the plugin, if the return value is nonzero, ++ * the plugin will not be used */ ++ int (*init)(struct httpd_plugin *); ++ ++ /* free all memory associated with the plugin */ ++ void (*done)(struct httpd_plugin *); ++ ++ /* prepare a page request. this is executed in the main context, ++ * so pay attention to memory usage. should not print any data ++ * to stdout */ ++ int (*prepare_req)(struct httpd_plugin *, struct http_context *); ++ ++ /* handle the request. can print output data to stdout */ ++ int (*handle_req)(struct httpd_plugin *, struct http_context *); ++ ++ /* pointer for private data structures of the plugin */ ++ void *priv; ++}; ++ ++#define HTTPD_PLUGIN struct httpd_plugin httpd_plugin = ++ ++#endif |