1 Index: boa-0.94.13/src/list.h
2 ===================================================================
3 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
4 +++ boa-0.94.13/src/list.h 2008-06-29 01:12:36.000000000 +0200
11 + * container_of - cast a member of a structure out to the containing structure
12 + * @ptr: the pointer to the member.
13 + * @type: the type of the container struct this is embedded in.
14 + * @member: the name of the member within the struct.
18 +#define container_of(ptr, type, member) ( \
19 + (type *)( (char *)ptr - offsetof(type,member) ))
24 + * Simple doubly linked list implementation.
26 + * Some of the internal functions ("__xxx") are useful when
27 + * manipulating whole lists rather than single entries, as
28 + * sometimes we already know the next/prev entries and we can
29 + * generate better code by using them directly rather than
30 + * using the generic single-entry routines.
34 + struct list_head *next, *prev;
37 +#define LIST_HEAD_INIT(name) { &(name), &(name) }
39 +#define LIST_HEAD(name) \
40 + struct list_head name = LIST_HEAD_INIT(name)
42 +static inline void INIT_LIST_HEAD(struct list_head *list)
49 + * Insert a new entry between two known consecutive entries.
51 + * This is only for internal list manipulation where we know
52 + * the prev/next entries already!
54 +static inline void __list_add(struct list_head *new,
55 + struct list_head *prev,
56 + struct list_head *next)
65 + * list_add - add a new entry
66 + * @new: new entry to be added
67 + * @head: list head to add it after
69 + * Insert a new entry after the specified head.
70 + * This is good for implementing stacks.
72 +static inline void list_add(struct list_head *new, struct list_head *head)
74 + __list_add(new, head, head->next);
79 + * list_add_tail - add a new entry
80 + * @new: new entry to be added
81 + * @head: list head to add it before
83 + * Insert a new entry before the specified head.
84 + * This is useful for implementing queues.
86 +static inline void list_add_tail(struct list_head *new, struct list_head *head)
88 + __list_add(new, head->prev, head);
93 + * Delete a list entry by making the prev/next entries
94 + * point to each other.
96 + * This is only for internal list manipulation where we know
97 + * the prev/next entries already!
99 +static inline void __list_del(struct list_head * prev, struct list_head * next)
106 + * list_del - deletes entry from list.
107 + * @entry: the element to delete from the list.
108 + * Note: list_empty() on entry does not return true after this, the entry is
109 + * in an undefined state.
111 +static inline void list_del(struct list_head *entry)
113 + __list_del(entry->prev, entry->next);
114 + entry->next = NULL;
115 + entry->prev = NULL;
119 + * list_replace - replace old entry by new one
120 + * @old : the element to be replaced
121 + * @new : the new element to insert
123 + * If @old was empty, it will be overwritten.
125 +static inline void list_replace(struct list_head *old,
126 + struct list_head *new)
128 + new->next = old->next;
129 + new->next->prev = new;
130 + new->prev = old->prev;
131 + new->prev->next = new;
134 +static inline void list_replace_init(struct list_head *old,
135 + struct list_head *new)
137 + list_replace(old, new);
138 + INIT_LIST_HEAD(old);
142 + * list_del_init - deletes entry from list and reinitialize it.
143 + * @entry: the element to delete from the list.
145 +static inline void list_del_init(struct list_head *entry)
147 + __list_del(entry->prev, entry->next);
148 + INIT_LIST_HEAD(entry);
152 + * list_move - delete from one list and add as another's head
153 + * @list: the entry to move
154 + * @head: the head that will precede our entry
156 +static inline void list_move(struct list_head *list, struct list_head *head)
158 + __list_del(list->prev, list->next);
159 + list_add(list, head);
163 + * list_move_tail - delete from one list and add as another's tail
164 + * @list: the entry to move
165 + * @head: the head that will follow our entry
167 +static inline void list_move_tail(struct list_head *list,
168 + struct list_head *head)
170 + __list_del(list->prev, list->next);
171 + list_add_tail(list, head);
175 + * list_is_last - tests whether @list is the last entry in list @head
176 + * @list: the entry to test
177 + * @head: the head of the list
179 +static inline int list_is_last(const struct list_head *list,
180 + const struct list_head *head)
182 + return list->next == head;
186 + * list_empty - tests whether a list is empty
187 + * @head: the list to test.
189 +static inline int list_empty(const struct list_head *head)
191 + return head->next == head;
195 + * list_empty_careful - tests whether a list is empty and not being modified
196 + * @head: the list to test
199 + * tests whether a list is empty _and_ checks that no other CPU might be
200 + * in the process of modifying either member (next or prev)
202 + * NOTE: using list_empty_careful() without synchronization
203 + * can only be safe if the only activity that can happen
204 + * to the list entry is list_del_init(). Eg. it cannot be used
205 + * if another CPU could re-list_add() it.
207 +static inline int list_empty_careful(const struct list_head *head)
209 + struct list_head *next = head->next;
210 + return (next == head) && (next == head->prev);
213 +static inline void __list_splice(struct list_head *list,
214 + struct list_head *head)
216 + struct list_head *first = list->next;
217 + struct list_head *last = list->prev;
218 + struct list_head *at = head->next;
220 + first->prev = head;
221 + head->next = first;
228 + * list_splice - join two lists
229 + * @list: the new list to add.
230 + * @head: the place to add it in the first list.
232 +static inline void list_splice(struct list_head *list, struct list_head *head)
234 + if (!list_empty(list))
235 + __list_splice(list, head);
239 + * list_splice_init - join two lists and reinitialise the emptied list.
240 + * @list: the new list to add.
241 + * @head: the place to add it in the first list.
243 + * The list at @list is reinitialised
245 +static inline void list_splice_init(struct list_head *list,
246 + struct list_head *head)
248 + if (!list_empty(list)) {
249 + __list_splice(list, head);
250 + INIT_LIST_HEAD(list);
255 + * list_entry - get the struct for this entry
256 + * @ptr: the &struct list_head pointer.
257 + * @type: the type of the struct this is embedded in.
258 + * @member: the name of the list_struct within the struct.
260 +#define list_entry(ptr, type, member) \
261 + container_of(ptr, type, member)
264 + * list_first_entry - get the first element from a list
265 + * @ptr: the list head to take the element from.
266 + * @type: the type of the struct this is embedded in.
267 + * @member: the name of the list_struct within the struct.
269 + * Note, that list is expected to be not empty.
271 +#define list_first_entry(ptr, type, member) \
272 + list_entry((ptr)->next, type, member)
275 + * list_for_each - iterate over a list
276 + * @pos: the &struct list_head to use as a loop cursor.
277 + * @head: the head for your list.
279 +#define list_for_each(pos, head) \
280 + for (pos = (head)->next; pos != (head); \
284 + * __list_for_each - iterate over a list
285 + * @pos: the &struct list_head to use as a loop cursor.
286 + * @head: the head for your list.
288 + * This variant differs from list_for_each() in that it's the
289 + * simplest possible list iteration code, no prefetching is done.
290 + * Use this for code that knows the list to be very short (empty
291 + * or 1 entry) most of the time.
293 +#define __list_for_each(pos, head) \
294 + for (pos = (head)->next; pos != (head); pos = pos->next)
297 + * list_for_each_prev - iterate over a list backwards
298 + * @pos: the &struct list_head to use as a loop cursor.
299 + * @head: the head for your list.
301 +#define list_for_each_prev(pos, head) \
302 + for (pos = (head)->prev; pos != (head); \
306 + * list_for_each_safe - iterate over a list safe against removal of list entry
307 + * @pos: the &struct list_head to use as a loop cursor.
308 + * @n: another &struct list_head to use as temporary storage
309 + * @head: the head for your list.
311 +#define list_for_each_safe(pos, n, head) \
312 + for (pos = (head)->next, n = pos->next; pos != (head); \
313 + pos = n, n = pos->next)
316 + * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
317 + * @pos: the &struct list_head to use as a loop cursor.
318 + * @n: another &struct list_head to use as temporary storage
319 + * @head: the head for your list.
321 +#define list_for_each_prev_safe(pos, n, head) \
322 + for (pos = (head)->prev, n = pos->prev; \
324 + pos = n, n = pos->prev)
327 + * list_for_each_entry - iterate over list of given type
328 + * @pos: the type * to use as a loop cursor.
329 + * @head: the head for your list.
330 + * @member: the name of the list_struct within the struct.
332 +#define list_for_each_entry(pos, head, member) \
333 + for (pos = list_entry((head)->next, typeof(*pos), member); \
334 + &pos->member != (head); \
335 + pos = list_entry(pos->member.next, typeof(*pos), member))
338 + * list_for_each_entry_reverse - iterate backwards over list of given type.
339 + * @pos: the type * to use as a loop cursor.
340 + * @head: the head for your list.
341 + * @member: the name of the list_struct within the struct.
343 +#define list_for_each_entry_reverse(pos, head, member) \
344 + for (pos = list_entry((head)->prev, typeof(*pos), member); \
345 + &pos->member != (head); \
346 + pos = list_entry(pos->member.prev, typeof(*pos), member))
349 + * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
350 + * @pos: the type * to use as a start point
351 + * @head: the head of the list
352 + * @member: the name of the list_struct within the struct.
354 + * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
356 +#define list_prepare_entry(pos, head, member) \
357 + ((pos) ? : list_entry(head, typeof(*pos), member))
360 + * list_for_each_entry_continue - continue iteration over list of given type
361 + * @pos: the type * to use as a loop cursor.
362 + * @head: the head for your list.
363 + * @member: the name of the list_struct within the struct.
365 + * Continue to iterate over list of given type, continuing after
366 + * the current position.
368 +#define list_for_each_entry_continue(pos, head, member) \
369 + for (pos = list_entry(pos->member.next, typeof(*pos), member); \
370 + &pos->member != (head); \
371 + pos = list_entry(pos->member.next, typeof(*pos), member))
374 + * list_for_each_entry_continue_reverse - iterate backwards from the given point
375 + * @pos: the type * to use as a loop cursor.
376 + * @head: the head for your list.
377 + * @member: the name of the list_struct within the struct.
379 + * Start to iterate over list of given type backwards, continuing after
380 + * the current position.
382 +#define list_for_each_entry_continue_reverse(pos, head, member) \
383 + for (pos = list_entry(pos->member.prev, typeof(*pos), member); \
384 + &pos->member != (head); \
385 + pos = list_entry(pos->member.prev, typeof(*pos), member))
388 + * list_for_each_entry_from - iterate over list of given type from the current point
389 + * @pos: the type * to use as a loop cursor.
390 + * @head: the head for your list.
391 + * @member: the name of the list_struct within the struct.
393 + * Iterate over list of given type, continuing from current position.
395 +#define list_for_each_entry_from(pos, head, member) \
396 + for (; &pos->member != (head); \
397 + pos = list_entry(pos->member.next, typeof(*pos), member))
400 + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
401 + * @pos: the type * to use as a loop cursor.
402 + * @n: another type * to use as temporary storage
403 + * @head: the head for your list.
404 + * @member: the name of the list_struct within the struct.
406 +#define list_for_each_entry_safe(pos, n, head, member) \
407 + for (pos = list_entry((head)->next, typeof(*pos), member), \
408 + n = list_entry(pos->member.next, typeof(*pos), member); \
409 + &pos->member != (head); \
410 + pos = n, n = list_entry(n->member.next, typeof(*n), member))
413 + * list_for_each_entry_safe_continue
414 + * @pos: the type * to use as a loop cursor.
415 + * @n: another type * to use as temporary storage
416 + * @head: the head for your list.
417 + * @member: the name of the list_struct within the struct.
419 + * Iterate over list of given type, continuing after current point,
420 + * safe against removal of list entry.
422 +#define list_for_each_entry_safe_continue(pos, n, head, member) \
423 + for (pos = list_entry(pos->member.next, typeof(*pos), member), \
424 + n = list_entry(pos->member.next, typeof(*pos), member); \
425 + &pos->member != (head); \
426 + pos = n, n = list_entry(n->member.next, typeof(*n), member))
429 + * list_for_each_entry_safe_from
430 + * @pos: the type * to use as a loop cursor.
431 + * @n: another type * to use as temporary storage
432 + * @head: the head for your list.
433 + * @member: the name of the list_struct within the struct.
435 + * Iterate over list of given type from current point, safe against
436 + * removal of list entry.
438 +#define list_for_each_entry_safe_from(pos, n, head, member) \
439 + for (n = list_entry(pos->member.next, typeof(*pos), member); \
440 + &pos->member != (head); \
441 + pos = n, n = list_entry(n->member.next, typeof(*n), member))
444 + * list_for_each_entry_safe_reverse
445 + * @pos: the type * to use as a loop cursor.
446 + * @n: another type * to use as temporary storage
447 + * @head: the head for your list.
448 + * @member: the name of the list_struct within the struct.
450 + * Iterate backwards over list of given type, safe against removal
453 +#define list_for_each_entry_safe_reverse(pos, n, head, member) \
454 + for (pos = list_entry((head)->prev, typeof(*pos), member), \
455 + n = list_entry(pos->member.prev, typeof(*pos), member); \
456 + &pos->member != (head); \
457 + pos = n, n = list_entry(n->member.prev, typeof(*n), member))
460 + * Double linked lists with a single pointer list head.
461 + * Mostly useful for hash tables where the two pointer list head is
463 + * You lose the ability to access the tail in O(1).
467 + struct hlist_node *first;
471 + struct hlist_node *next, **pprev;
474 +#define HLIST_HEAD_INIT { .first = NULL }
475 +#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
476 +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
477 +static inline void INIT_HLIST_NODE(struct hlist_node *h)
483 +static inline int hlist_unhashed(const struct hlist_node *h)
488 +static inline int hlist_empty(const struct hlist_head *h)
493 +static inline void __hlist_del(struct hlist_node *n)
495 + struct hlist_node *next = n->next;
496 + struct hlist_node **pprev = n->pprev;
499 + next->pprev = pprev;
502 +static inline void hlist_del(struct hlist_node *n)
509 +static inline void hlist_del_init(struct hlist_node *n)
511 + if (!hlist_unhashed(n)) {
513 + INIT_HLIST_NODE(n);
518 +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
520 + struct hlist_node *first = h->first;
523 + first->pprev = &n->next;
525 + n->pprev = &h->first;
529 +/* next must be != NULL */
530 +static inline void hlist_add_before(struct hlist_node *n,
531 + struct hlist_node *next)
533 + n->pprev = next->pprev;
535 + next->pprev = &n->next;
539 +static inline void hlist_add_after(struct hlist_node *n,
540 + struct hlist_node *next)
542 + next->next = n->next;
544 + next->pprev = &n->next;
547 + next->next->pprev = &next->next;
550 +#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
552 +#define hlist_for_each(pos, head) \
553 + for (pos = (head)->first; pos; pos = pos->next)
555 +#define hlist_for_each_safe(pos, n, head) \
556 + for (pos = (head)->first; pos; pos = n)
559 + * hlist_for_each_entry - iterate over list of given type
560 + * @tpos: the type * to use as a loop cursor.
561 + * @pos: the &struct hlist_node to use as a loop cursor.
562 + * @head: the head for your list.
563 + * @member: the name of the hlist_node within the struct.
565 +#define hlist_for_each_entry(tpos, pos, head, member) \
566 + for (pos = (head)->first; pos && \
567 + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
571 + * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
572 + * @tpos: the type * to use as a loop cursor.
573 + * @pos: the &struct hlist_node to use as a loop cursor.
574 + * @member: the name of the hlist_node within the struct.
576 +#define hlist_for_each_entry_continue(tpos, pos, member) \
577 + for (pos = (pos)->next; pos && \
578 + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
582 + * hlist_for_each_entry_from - iterate over a hlist continuing from current point
583 + * @tpos: the type * to use as a loop cursor.
584 + * @pos: the &struct hlist_node to use as a loop cursor.
585 + * @member: the name of the hlist_node within the struct.
587 +#define hlist_for_each_entry_from(tpos, pos, member) \
589 + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
593 + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
594 + * @tpos: the type * to use as a loop cursor.
595 + * @pos: the &struct hlist_node to use as a loop cursor.
596 + * @n: another &struct hlist_node to use as temporary storage
597 + * @head: the head for your list.
598 + * @member: the name of the hlist_node within the struct.
600 +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
601 + for (pos = (head)->first; \
602 + pos && ({ n = pos->next; 1; }) && \
603 + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
607 Index: boa-0.94.13/src/plugin.c
608 ===================================================================
609 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
610 +++ boa-0.94.13/src/plugin.c 2008-06-29 01:22:01.000000000 +0200
613 + * Simple plugin API for boa
614 + * Copyright (C) 2008 John Crispin <blogic@openwrt.org>
615 + * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
617 + * This program is free software; you can redistribute it and/or modify
618 + * it under the terms of the GNU General Public License version 2
619 + * as published by the Free Software Foundation.
621 + * This program is distributed in the hope that it will be useful,
622 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
623 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
624 + * GNU General Public License for more details.
626 + * You should have received a copy of the GNU General Public License
627 + * along with this program; if not, write to the Free Software
628 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
636 +static LIST_HEAD(plugins);
638 +struct httpd_plugin *plugin_lookup(request *req)
640 + struct list_head *l;
641 + list_for_each(l, &plugins)
643 + struct httpd_plugin *p =
644 + container_of(l, struct httpd_plugin, list);
646 + if (!strncmp(req->request_uri, p->prefix, strlen(p->prefix)))
652 +static int plugin_run(request *req, struct httpd_plugin *p)
654 + struct http_context ctx;
659 + memset(&ctx, 0, sizeof(ctx));
660 + ctx.uri = req->request_uri;
661 + switch(req->method) {
663 + ctx.request_method = "POST";
666 + ctx.request_method = "HEAD";
669 + ctx.request_method = "GET";
672 + ctx.server_addr = req->local_ip_addr;
673 + ctx.server_proto = req->http_version;
674 + ctx.query_string = req->query_string;
675 + ctx.remote_addr = req->remote_ip_addr;
676 + ctx.remote_port = req->remote_port;
677 + if (req->method == M_POST) {
678 + if (req->content_type)
679 + ctx.content_type = req->content_type;
681 + ctx.content_type = default_type;
682 + ctx.content_length = req->content_length;
685 + if (req->accept[0])
686 + ctx.http_accept = req->accept;
689 + p->prepare_req(p, &ctx);
690 + child_pid = fork();
692 + switch(child_pid) {
700 + if (dup2(req->fd, STDOUT_FILENO) == -1) {
702 + perror("dup2 - fd");
705 + if (set_block_fd(req->fd) == -1) {
707 + perror("cgi-fcntl");
710 + if (req->method == M_POST) {
711 + dup2(req->read_data_fd, STDIN_FILENO);
712 + close(req->read_data_fd);
713 + close(req->post_data_fd);
714 + set_block_fd(STDIN_FILENO);
716 + close_access_log();
719 + dup2(cgi_log_fd, STDERR_FILENO);
721 + p->handle_req(p, &ctx);
729 +int plugin_handle(request * req)
731 + struct httpd_plugin *p;
733 + p = plugin_lookup(req);
737 + return plugin_run(req, p);
740 +static void plugin_load(const char *p, const char *dir)
742 + struct httpd_plugin *plugin;
745 + /* ignore directories */
746 + if (p[strlen(p) - 1] == '/')
749 + dl = dlopen(p, RTLD_NOW | RTLD_GLOBAL);
751 + fprintf(stderr, "Unable to load plugin '%s': %d\n", p, dlerror());
755 + plugin = dlsym(dl, "httpd_plugin");
759 + INIT_LIST_HEAD(&plugin->list);
762 + if (plugin->init(plugin) != 1)
765 + if (!plugin->prefix)
768 + list_add(&plugin->list, &plugins);
772 + plugin->done(plugin);
774 + fprintf(stderr, "Plugin '%s' failed to initialize\n", p);
778 +#define WILDCARD_SUFFIX "/*.so"
780 +int plugin_init(char *path)
788 + s = malloc(strlen(path) + sizeof(WILDCARD_SUFFIX) + 1);
790 + strcat(s, WILDCARD_SUFFIX);
791 + glob(s, GLOB_MARK, NULL, &g);
794 + for (i = 0; i < g.gl_pathc; i++)
795 + plugin_load(g.gl_pathv[i], path);
802 Index: boa-0.94.13/src/request.c
803 ===================================================================
804 --- boa-0.94.13.orig/src/request.c 2008-06-29 01:11:52.000000000 +0200
805 +++ boa-0.94.13/src/request.c 2008-06-29 01:12:36.000000000 +0200
807 dequeue(&request_free, request_free); /* dequeue the head */
809 req = (request *) malloc(sizeof (request));
810 + memset(req, 0, sizeof(request));
813 perror("malloc for new request");
816 int process_header_end(request * req)
823 @@ -630,11 +633,26 @@
826 if (req->method == M_POST) {
827 - req->post_data_fd = create_temporary_file(1, NULL, 0);
828 - if (req->post_data_fd == 0)
830 - return(1); /* success */
832 + if (!req->plugin) {
833 + req->post_data_fd = create_temporary_file(1, NULL, 0);
836 + if (pipe(&fd[0]) != -1) {
837 + req->post_data_fd = fd[1];
838 + req->read_data_fd = fd[0];
839 + set_nonblock_fd(req->post_data_fd);
842 + if (req->post_data_fd == 0) {
846 + return(1); /* success */
849 + ret = plugin_handle(req);
854 return init_cgi(req);
855 Index: boa-0.94.13/src/Makefile.in
856 ===================================================================
857 --- boa-0.94.13.orig/src/Makefile.in 2008-06-29 01:11:52.000000000 +0200
858 +++ boa-0.94.13/src/Makefile.in 2008-06-29 01:12:36.000000000 +0200
861 VPATH = @srcdir@:@srcdir@/../extras
865 CFLAGS = @CFLAGS@ -I.
867 # Change these if necessary
870 SOURCES = alias.c boa.c buffer.c cgi.c cgi_header.c config.c escape.c \
871 get.c hash.c ip.c log.c mmap_cache.c pipe.c queue.c read.c \
872 - request.c response.c select.c signals.c util.c sublog.c
873 + request.c response.c select.c signals.c util.c sublog.c \
876 OBJS = y.tab.o lex.yy.o $(SOURCES:.c=.o) timestamp.o @STRUTIL@
878 Index: boa-0.94.13/src/boa.h
879 ===================================================================
880 --- boa-0.94.13.orig/src/boa.h 2008-06-29 01:11:52.000000000 +0200
881 +++ boa-0.94.13/src/boa.h 2008-06-29 01:12:36.000000000 +0200
884 #include <limits.h> /* OPEN_MAX */
886 +#include <stdbool.h>
889 #include <netinet/in.h>
891 #include "compat.h" /* oh what fun is porting */
894 +#include "boa-plugin.h"
897 void add_alias(char *fakename, char *realname, int script);
900 void select_loop(int server_s);
903 +int plugin_init(char *path);
904 +int plugin_handle(request * req);
905 +struct httpd_plugin *plugin_lookup(request *req);
908 Index: boa-0.94.13/src/config.c
909 ===================================================================
910 --- boa-0.94.13.orig/src/config.c 2008-06-29 01:11:52.000000000 +0200
911 +++ boa-0.94.13/src/config.c 2008-06-29 01:12:36.000000000 +0200
913 char *error_log_name;
914 char *access_log_name;
916 +char *plugin_root = NULL;
921 {"SinglePostLimit", S1A, c_set_int, &single_post_limit},
922 {"CGIPath", S1A, c_set_string, &cgi_path},
923 {"MaxConnections", S1A, c_set_int, &max_connections},
924 + {"PluginRoot", S1A, c_set_string, &plugin_root},
927 static void c_set_user(char *v1, char *v2, void *t)
933 + char *plugin_path = plugin_root;
937 + next = strchr(plugin_path, ':');
943 + plugin_init(normalize_path(plugin_path));
944 + plugin_path = next;
945 + } while (plugin_path);
951 Index: boa-0.94.13/src/alias.c
952 ===================================================================
953 --- boa-0.94.13.orig/src/alias.c 2008-06-29 01:11:52.000000000 +0200
954 +++ boa-0.94.13/src/alias.c 2008-06-29 01:12:36.000000000 +0200
956 uri_len = strlen(req->request_uri);
958 current = find_alias(req->request_uri, uri_len);
959 + req->plugin = !!plugin_lookup(req);
962 if (current->type == SCRIPTALIAS) /* Script */
966 if (current->type == REDIRECT) { /* Redirect */
967 - if (req->method == M_POST) { /* POST to non-script */
968 + if ((req->method == M_POST) && !req->plugin) { /* POST to non-script */
969 /* it's not a cgi, but we try to POST??? */
970 send_r_bad_request(req);
971 return 0; /* not a script alias, therefore begin filling in data */
976 - } else if (req->method == M_POST) { /* POST to non-script */
977 + } else if ((req->method == M_POST) && !req->plugin) { /* POST to non-script */
978 /* it's not a cgi, but we try to POST??? */
979 send_r_bad_request(req);
981 Index: boa-0.94.13/src/globals.h
982 ===================================================================
983 --- boa-0.94.13.orig/src/globals.h 2008-06-29 01:11:52.000000000 +0200
984 +++ boa-0.94.13/src/globals.h 2008-06-29 01:12:36.000000000 +0200
986 struct request { /* pending requests */
987 int fd; /* client's socket fd */
988 int status; /* see #defines.h */
990 time_t time_last; /* time of last succ. op. */
991 char *pathname; /* pathname of requested file */
992 int simple; /* simple request? */
994 char *header_referer;
996 int post_data_fd; /* fd for post data tmpfile */
997 + int read_data_fd; /* fd for post data input (plugin) */
999 char *path_info; /* env variable */
1000 char *path_translated; /* env variable */
1001 Index: boa-0.94.13/src/read.c
1002 ===================================================================
1003 --- boa-0.94.13.orig/src/read.c 2008-06-29 01:11:52.000000000 +0200
1004 +++ boa-0.94.13/src/read.c 2008-06-29 01:12:36.000000000 +0200
1005 @@ -338,8 +338,11 @@
1007 if (bytes_to_write == 0) { /* nothing left in buffer to write */
1008 req->header_line = req->header_end = req->buffer;
1009 - if (req->filepos >= req->filesize)
1010 - return init_cgi(req);
1011 + if (req->filepos >= req->filesize) {
1012 + if (req->post_data_fd > 0)
1013 + close(req->post_data_fd);
1014 + return init_cgi(req);
1016 /* if here, we can safely assume that there is more to read */
1017 req->status = BODY_READ;
1019 Index: boa-0.94.13/src/boa-plugin.h
1020 ===================================================================
1021 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
1022 +++ boa-0.94.13/src/boa-plugin.h 2008-06-29 01:12:36.000000000 +0200
1024 +#ifndef _HTTPD_PLUGIN_H__
1025 +#define _HTTPD_PLUGIN_H__
1030 + * Definition for HTTP server plugins
1032 + * The context that the plugin is called with for
1033 + * a single http request. It gets allocated in the
1034 + * persistent context before prepare_req and freed
1035 + * there afterwards (still active in the forked
1036 + * context at handle_req time)
1038 +struct http_context
1041 + char *request_method;
1042 + char *server_addr;
1043 + char *server_proto;
1044 + char *query_string;
1045 + char *remote_addr;
1046 + unsigned int remote_port;
1047 + char *content_type;
1048 + char *content_length;
1049 + char *http_accept;
1055 + * the main data structure of httpd plugins.
1057 +struct httpd_plugin
1059 + /* used by the web server */
1060 + struct list_head list;
1062 + /* only page requests matching 'prefix' are passed
1063 + * to prepare_req and handle_req */
1064 + const char *prefix;
1066 + /* directory that the plugin was found in */
1069 + /* initialize the plugin, if the return value is nonzero,
1070 + * the plugin will not be used */
1071 + int (*init)(struct httpd_plugin *);
1073 + /* free all memory associated with the plugin */
1074 + void (*done)(struct httpd_plugin *);
1076 + /* prepare a page request. this is executed in the main context,
1077 + * so pay attention to memory usage. should not print any data
1079 + int (*prepare_req)(struct httpd_plugin *, struct http_context *);
1081 + /* handle the request. can print output data to stdout */
1082 + int (*handle_req)(struct httpd_plugin *, struct http_context *);
1084 + /* pointer for private data structures of the plugin */
1088 +#define HTTPD_PLUGIN struct httpd_plugin httpd_plugin =