Readded unfindes Boa 0.94.14rc21
[project/luci.git] / libs / sgi-webuci / boa-patches / 200-plugin_api.patch
1 Index: boa-0.94.14rc21/src/list.h
2 ===================================================================
3 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
4 +++ boa-0.94.14rc21/src/list.h  2008-06-11 10:25:04.000000000 +0200
5 @@ -0,0 +1,601 @@
6 +#ifndef _LINUX_LIST_H
7 +#define _LINUX_LIST_H
8 +
9 +#include <stddef.h>
10 +/**
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.
15 + *
16 + */
17 +#ifndef container_of
18 +#define container_of(ptr, type, member) (                      \
19 +       (type *)( (char *)ptr - offsetof(type,member) ))
20 +#endif
21 +
22 +
23 +/*
24 + * Simple doubly linked list implementation.
25 + *
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.
31 + */
32 +
33 +struct list_head {
34 +       struct list_head *next, *prev;
35 +};
36 +
37 +#define LIST_HEAD_INIT(name) { &(name), &(name) }
38 +
39 +#define LIST_HEAD(name) \
40 +       struct list_head name = LIST_HEAD_INIT(name)
41 +
42 +static inline void INIT_LIST_HEAD(struct list_head *list)
43 +{
44 +       list->next = list;
45 +       list->prev = list;
46 +}
47 +
48 +/*
49 + * Insert a new entry between two known consecutive entries.
50 + *
51 + * This is only for internal list manipulation where we know
52 + * the prev/next entries already!
53 + */
54 +static inline void __list_add(struct list_head *new,
55 +                             struct list_head *prev,
56 +                             struct list_head *next)
57 +{
58 +       next->prev = new;
59 +       new->next = next;
60 +       new->prev = prev;
61 +       prev->next = new;
62 +}
63 +
64 +/**
65 + * list_add - add a new entry
66 + * @new: new entry to be added
67 + * @head: list head to add it after
68 + *
69 + * Insert a new entry after the specified head.
70 + * This is good for implementing stacks.
71 + */
72 +static inline void list_add(struct list_head *new, struct list_head *head)
73 +{
74 +       __list_add(new, head, head->next);
75 +}
76 +
77 +
78 +/**
79 + * list_add_tail - add a new entry
80 + * @new: new entry to be added
81 + * @head: list head to add it before
82 + *
83 + * Insert a new entry before the specified head.
84 + * This is useful for implementing queues.
85 + */
86 +static inline void list_add_tail(struct list_head *new, struct list_head *head)
87 +{
88 +       __list_add(new, head->prev, head);
89 +}
90 +
91 +
92 +/*
93 + * Delete a list entry by making the prev/next entries
94 + * point to each other.
95 + *
96 + * This is only for internal list manipulation where we know
97 + * the prev/next entries already!
98 + */
99 +static inline void __list_del(struct list_head * prev, struct list_head * next)
100 +{
101 +       next->prev = prev;
102 +       prev->next = next;
103 +}
104 +
105 +/**
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.
110 + */
111 +static inline void list_del(struct list_head *entry)
112 +{
113 +       __list_del(entry->prev, entry->next);
114 +       entry->next = NULL;
115 +       entry->prev = NULL;
116 +}
117 +
118 +/**
119 + * list_replace - replace old entry by new one
120 + * @old : the element to be replaced
121 + * @new : the new element to insert
122 + *
123 + * If @old was empty, it will be overwritten.
124 + */
125 +static inline void list_replace(struct list_head *old,
126 +                               struct list_head *new)
127 +{
128 +       new->next = old->next;
129 +       new->next->prev = new;
130 +       new->prev = old->prev;
131 +       new->prev->next = new;
132 +}
133 +
134 +static inline void list_replace_init(struct list_head *old,
135 +                                       struct list_head *new)
136 +{
137 +       list_replace(old, new);
138 +       INIT_LIST_HEAD(old);
139 +}
140 +
141 +/**
142 + * list_del_init - deletes entry from list and reinitialize it.
143 + * @entry: the element to delete from the list.
144 + */
145 +static inline void list_del_init(struct list_head *entry)
146 +{
147 +       __list_del(entry->prev, entry->next);
148 +       INIT_LIST_HEAD(entry);
149 +}
150 +
151 +/**
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
155 + */
156 +static inline void list_move(struct list_head *list, struct list_head *head)
157 +{
158 +       __list_del(list->prev, list->next);
159 +       list_add(list, head);
160 +}
161 +
162 +/**
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
166 + */
167 +static inline void list_move_tail(struct list_head *list,
168 +                                 struct list_head *head)
169 +{
170 +       __list_del(list->prev, list->next);
171 +       list_add_tail(list, head);
172 +}
173 +
174 +/**
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
178 + */
179 +static inline int list_is_last(const struct list_head *list,
180 +                               const struct list_head *head)
181 +{
182 +       return list->next == head;
183 +}
184 +
185 +/**
186 + * list_empty - tests whether a list is empty
187 + * @head: the list to test.
188 + */
189 +static inline int list_empty(const struct list_head *head)
190 +{
191 +       return head->next == head;
192 +}
193 +
194 +/**
195 + * list_empty_careful - tests whether a list is empty and not being modified
196 + * @head: the list to test
197 + *
198 + * Description:
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)
201 + *
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.
206 + */
207 +static inline int list_empty_careful(const struct list_head *head)
208 +{
209 +       struct list_head *next = head->next;
210 +       return (next == head) && (next == head->prev);
211 +}
212 +
213 +static inline void __list_splice(struct list_head *list,
214 +                                struct list_head *head)
215 +{
216 +       struct list_head *first = list->next;
217 +       struct list_head *last = list->prev;
218 +       struct list_head *at = head->next;
219 +
220 +       first->prev = head;
221 +       head->next = first;
222 +
223 +       last->next = at;
224 +       at->prev = last;
225 +}
226 +
227 +/**
228 + * list_splice - join two lists
229 + * @list: the new list to add.
230 + * @head: the place to add it in the first list.
231 + */
232 +static inline void list_splice(struct list_head *list, struct list_head *head)
233 +{
234 +       if (!list_empty(list))
235 +               __list_splice(list, head);
236 +}
237 +
238 +/**
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.
242 + *
243 + * The list at @list is reinitialised
244 + */
245 +static inline void list_splice_init(struct list_head *list,
246 +                                   struct list_head *head)
247 +{
248 +       if (!list_empty(list)) {
249 +               __list_splice(list, head);
250 +               INIT_LIST_HEAD(list);
251 +       }
252 +}
253 +
254 +/**
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.
259 + */
260 +#define list_entry(ptr, type, member) \
261 +       container_of(ptr, type, member)
262 +
263 +/**
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.
268 + *
269 + * Note, that list is expected to be not empty.
270 + */
271 +#define list_first_entry(ptr, type, member) \
272 +       list_entry((ptr)->next, type, member)
273 +
274 +/**
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.
278 + */
279 +#define list_for_each(pos, head) \
280 +       for (pos = (head)->next; pos != (head); \
281 +               pos = pos->next)
282 +
283 +/**
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.
287 + *
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.
292 + */
293 +#define __list_for_each(pos, head) \
294 +       for (pos = (head)->next; pos != (head); pos = pos->next)
295 +
296 +/**
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.
300 + */
301 +#define list_for_each_prev(pos, head) \
302 +       for (pos = (head)->prev; pos != (head); \
303 +               pos = pos->prev)
304 +
305 +/**
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.
310 + */
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)
314 +
315 +/**
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.
320 + */
321 +#define list_for_each_prev_safe(pos, n, head) \
322 +       for (pos = (head)->prev, n = pos->prev; \
323 +            pos != (head); \
324 +            pos = n, n = pos->prev)
325 +
326 +/**
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.
331 + */
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))
336 +
337 +/**
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.
342 + */
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))
347 +
348 +/**
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.
353 + *
354 + * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
355 + */
356 +#define list_prepare_entry(pos, head, member) \
357 +       ((pos) ? : list_entry(head, typeof(*pos), member))
358 +
359 +/**
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.
364 + *
365 + * Continue to iterate over list of given type, continuing after
366 + * the current position.
367 + */
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))
372 +
373 +/**
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.
378 + *
379 + * Start to iterate over list of given type backwards, continuing after
380 + * the current position.
381 + */
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))
386 +
387 +/**
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.
392 + *
393 + * Iterate over list of given type, continuing from current position.
394 + */
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))
398 +
399 +/**
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.
405 + */
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))
411 +
412 +/**
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.
418 + *
419 + * Iterate over list of given type, continuing after current point,
420 + * safe against removal of list entry.
421 + */
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))
427 +
428 +/**
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.
434 + *
435 + * Iterate over list of given type from current point, safe against
436 + * removal of list entry.
437 + */
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))
442 +
443 +/**
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.
449 + *
450 + * Iterate backwards over list of given type, safe against removal
451 + * of list entry.
452 + */
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))
458 +
459 +/*
460 + * Double linked lists with a single pointer list head.
461 + * Mostly useful for hash tables where the two pointer list head is
462 + * too wasteful.
463 + * You lose the ability to access the tail in O(1).
464 + */
465 +
466 +struct hlist_head {
467 +       struct hlist_node *first;
468 +};
469 +
470 +struct hlist_node {
471 +       struct hlist_node *next, **pprev;
472 +};
473 +
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)
478 +{
479 +       h->next = NULL;
480 +       h->pprev = NULL;
481 +}
482 +
483 +static inline int hlist_unhashed(const struct hlist_node *h)
484 +{
485 +       return !h->pprev;
486 +}
487 +
488 +static inline int hlist_empty(const struct hlist_head *h)
489 +{
490 +       return !h->first;
491 +}
492 +
493 +static inline void __hlist_del(struct hlist_node *n)
494 +{
495 +       struct hlist_node *next = n->next;
496 +       struct hlist_node **pprev = n->pprev;
497 +       *pprev = next;
498 +       if (next)
499 +               next->pprev = pprev;
500 +}
501 +
502 +static inline void hlist_del(struct hlist_node *n)
503 +{
504 +       __hlist_del(n);
505 +       n->next = NULL;
506 +       n->pprev = NULL;
507 +}
508 +
509 +static inline void hlist_del_init(struct hlist_node *n)
510 +{
511 +       if (!hlist_unhashed(n)) {
512 +               __hlist_del(n);
513 +               INIT_HLIST_NODE(n);
514 +       }
515 +}
516 +
517 +
518 +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
519 +{
520 +       struct hlist_node *first = h->first;
521 +       n->next = first;
522 +       if (first)
523 +               first->pprev = &n->next;
524 +       h->first = n;
525 +       n->pprev = &h->first;
526 +}
527 +
528 +
529 +/* next must be != NULL */
530 +static inline void hlist_add_before(struct hlist_node *n,
531 +                                       struct hlist_node *next)
532 +{
533 +       n->pprev = next->pprev;
534 +       n->next = next;
535 +       next->pprev = &n->next;
536 +       *(n->pprev) = n;
537 +}
538 +
539 +static inline void hlist_add_after(struct hlist_node *n,
540 +                                       struct hlist_node *next)
541 +{
542 +       next->next = n->next;
543 +       n->next = next;
544 +       next->pprev = &n->next;
545 +
546 +       if(next->next)
547 +               next->next->pprev  = &next->next;
548 +}
549 +
550 +#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
551 +
552 +#define hlist_for_each(pos, head) \
553 +       for (pos = (head)->first; pos; pos = pos->next)
554 +
555 +#define hlist_for_each_safe(pos, n, head) \
556 +       for (pos = (head)->first; pos; pos = n)
557 +
558 +/**
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.
564 + */
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;}); \
568 +            pos = pos->next)
569 +
570 +/**
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.
575 + */
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;});   \
579 +            pos = pos->next)
580 +
581 +/**
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.
586 + */
587 +#define hlist_for_each_entry_from(tpos, pos, member)                    \
588 +       for (; pos &&                    \
589 +               ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
590 +            pos = pos->next)
591 +
592 +/**
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.
599 + */
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;}); \
604 +            pos = n)
605 +
606 +#endif
607 Index: boa-0.94.14rc21/src/plugin.c
608 ===================================================================
609 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
610 +++ boa-0.94.14rc21/src/plugin.c        2008-06-11 10:25:04.000000000 +0200
611 @@ -0,0 +1,198 @@
612 +/*
613 + * Simple plugin API for boa
614 + * Copyright (C) 2008 John Crispin <blogic@openwrt.org>
615 + * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
616 + *
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.
620 + *
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.
625 + *
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.
629 + */
630 +
631 +#include "boa.h"
632 +#include "list.h"
633 +#include <dlfcn.h>
634 +#include <glob.h>
635 +
636 +static LIST_HEAD(plugins);
637 +
638 +struct httpd_plugin *plugin_lookup(request *req)
639 +{
640 +       struct list_head *l;
641 +       list_for_each(l, &plugins)
642 +       {
643 +               struct httpd_plugin *p =
644 +                       container_of(l, struct httpd_plugin, list);
645 +
646 +               if (!strncmp(req->request_uri, p->prefix, strlen(p->prefix)))
647 +                       return p;
648 +       }
649 +       return NULL;
650 +}
651 +
652 +static int plugin_run(request *req, struct httpd_plugin *p)
653 +{
654 +       struct http_context ctx;
655 +    int child_pid;
656 +
657 +       SQUASH_KA(req);
658 +
659 +       memset(&ctx, 0, sizeof(ctx));
660 +       ctx.uri = req->request_uri;
661 +       switch(req->method) {
662 +               case M_POST:
663 +                       ctx.request_method = "POST";
664 +                       break;
665 +               case M_HEAD:
666 +                       ctx.request_method = "HEAD";
667 +                       break;
668 +               case M_GET:
669 +                       ctx.request_method = "GET";
670 +                       break;
671 +       }
672 +       ctx.server_addr = req->local_ip_addr;
673 +       switch (req->http_version) {
674 +               case HTTP09:
675 +                       ctx.server_proto = "HTTP/0.9";
676 +                       break;
677 +               case HTTP10:
678 +                       ctx.server_proto = "HTTP/1.0";
679 +                       break;
680 +               case HTTP11:
681 +                       ctx.server_proto = "HTTP/1.1";
682 +                       break;
683 +       }
684 +       ctx.query_string = req->query_string;
685 +       ctx.remote_addr = req->remote_ip_addr;
686 +       ctx.remote_port = req->remote_port;
687 +       if (req->method == M_POST) {
688 +               if (req->content_type)
689 +                       ctx.content_type = req->content_type;
690 +               else
691 +                       ctx.content_type = default_type;
692 +               ctx.content_length = req->content_length;
693 +       }
694 +#ifdef ACCEPT_ON
695 +       if (req->accept[0])
696 +               ctx.http_accept = req->accept;
697 +#endif
698 +
699 +    p->prepare_req(p, &ctx);
700 +       child_pid = fork();
701 +
702 +       switch(child_pid) {
703 +    case -1:
704 +        log_error_doc(req);
705 +        perror("fork");
706 +        send_r_error(req);
707 +        return 0;
708 +
709 +       case 0:
710 +        if (dup2(req->fd, STDOUT_FILENO) == -1) {
711 +            log_error_doc(req);
712 +            perror("dup2 - fd");
713 +            _exit(1);
714 +        }
715 +        if (set_block_fd(req->fd) == -1) {
716 +            log_error_doc(req);
717 +            perror("cgi-fcntl");
718 +            _exit(1);
719 +        }
720 +        if (req->method == M_POST) {
721 +            dup2(req->read_data_fd, STDIN_FILENO);
722 +            close(req->read_data_fd);
723 +            close(req->post_data_fd);
724 +                       set_block_fd(STDIN_FILENO);
725 +        }
726 +
727 +        if (cgi_log_fd)
728 +            dup2(cgi_log_fd, STDERR_FILENO);
729 +
730 +           p->handle_req(p, &ctx);
731 +               exit(0);
732 +        break;
733 +    }
734 +
735 +    return 1;
736 +}
737 +
738 +int plugin_handle(request * req)
739 +{
740 +       struct httpd_plugin *p;
741 +
742 +       p = plugin_lookup(req);
743 +       if (!p)
744 +               return 0;
745 +
746 +       return plugin_run(req, p);
747 +}
748 +
749 +static void plugin_load(const char *p, const char *dir)
750 +{
751 +       struct httpd_plugin *plugin;
752 +       void *dl;
753 +
754 +       /* ignore directories */
755 +       if (p[strlen(p) - 1] == '/')
756 +               return;
757 +
758 +       dl = dlopen(p, RTLD_NOW);
759 +       if (!dl) {
760 +               fprintf(stderr, "Unable to load plugin '%s': %d\n", p, dlerror());
761 +               return;
762 +       }
763 +
764 +       plugin = dlsym(dl, "httpd_plugin");
765 +       if (!plugin)
766 +               goto error;
767 +
768 +       INIT_LIST_HEAD(&plugin->list);
769 +       plugin->dir = dir;
770 +
771 +       if (plugin->init(plugin) != 1)
772 +               goto error;
773 +
774 +       if (!plugin->prefix)
775 +               goto error_init;
776 +
777 +       list_add(&plugin->list, &plugins);
778 +       return;
779 +
780 +error_init:
781 +       plugin->done(plugin);
782 +error:
783 +       fprintf(stderr, "Plugin '%s' failed to initialize\n", p);
784 +       dlclose(dl);
785 +}
786 +
787 +#define WILDCARD_SUFFIX "/*.so"
788 +
789 +int plugin_init(char *path)
790 +{
791 +       int buflen = 128;
792 +       char *plugindir;
793 +       glob_t g;
794 +       char *s;
795 +       int i;
796 +
797 +       s = malloc(strlen(path) + sizeof(WILDCARD_SUFFIX) + 1);
798 +       strcpy(s, path);
799 +       strcat(s, WILDCARD_SUFFIX);
800 +       glob(s, GLOB_MARK, NULL, &g);
801 +       free(s);
802 +
803 +       for (i = 0; i < g.gl_pathc; i++)
804 +               plugin_load(g.gl_pathv[i], path);
805 +
806 +       globfree(&g);
807 +}
808 +
809 +
810 Index: boa-0.94.14rc21/src/request.c
811 ===================================================================
812 --- boa-0.94.14rc21.orig/src/request.c  2005-02-22 15:11:29.000000000 +0100
813 +++ boa-0.94.14rc21/src/request.c       2008-06-11 10:25:04.000000000 +0200
814 @@ -59,6 +59,7 @@
815          dequeue(&request_free, request_free); /* dequeue the head */
816      } else {
817          req = (request *) malloc(sizeof (request));
818 +               memset(req, 0, sizeof(request));
819          if (!req) {
820              log_error_time();
821              perror("malloc for new request");
822 @@ -793,6 +794,8 @@
823  
824  int process_header_end(request * req)
825  {
826 +       int ret;
827 +
828      if (!req->logline) {
829          log_error_doc(req);
830          fputs("No logline in process_header_end\n", stderr);
831 @@ -855,19 +858,35 @@
832      }
833  
834      if (req->method == M_POST) {
835 -        req->post_data_fd = create_temporary_file(1, NULL, 0);
836 +        if (!req->plugin) {
837 +            req->post_data_fd = create_temporary_file(1, NULL, 0);
838 +        } else {
839 +            int fd[2];
840 +            if (pipe(&fd[0]) != -1) {
841 +                req->post_data_fd = fd[1];
842 +                req->read_data_fd = fd[0];
843 +                set_nonblock_fd(req->post_data_fd);
844 +            }
845 +        }
846          if (req->post_data_fd == 0) {
847              /* errors already logged */
848              send_r_error(req);
849              return 0;
850          }
851 -        if (fcntl(req->post_data_fd, F_SETFD, 1) == -1) {
852 -            boa_perror(req, "unable to set close-on-exec for req->post_data_fd!");
853 -            close(req->post_data_fd);
854 -            req->post_data_fd = 0;
855 -            return 0;
856 +        if (!req->plugin) {
857 +            if (fcntl(req->post_data_fd, F_SETFD, 1) == -1) {
858 +                boa_perror(req, "unable to set close-on-exec for req->post_data_fd!");
859 +                close(req->post_data_fd);
860 +                req->post_data_fd = 0;
861 +                return 0;
862 +            }
863 +            return(1); /* success */
864          }
865 -        return 1;             /* success */
866 +    }
867 +
868 +    ret = plugin_handle(req);
869 +    if (ret) {
870 +        return ret;
871      }
872  
873      if (req->cgi_type) {
874 Index: boa-0.94.14rc21/src/Makefile.in
875 ===================================================================
876 --- boa-0.94.14rc21.orig/src/Makefile.in        2005-02-22 04:02:40.000000000 +0100
877 +++ boa-0.94.14rc21/src/Makefile.in     2008-06-11 10:25:04.000000000 +0200
878 @@ -15,7 +15,7 @@
879  srcdir = @srcdir@
880  VPATH = @srcdir@:@srcdir@/../extras
881  LDFLAGS = @LDFLAGS@
882 -LIBS = @LIBS@
883 +LIBS = @LIBS@ -ldl
884  CFLAGS = @CFLAGS@
885  CPPFLAGS = @CPPFLAGS@ -I@srcdir@ -I.
886  @ifGNUmake@DEPEND = .depend
887 @@ -26,6 +26,7 @@
888  SOURCES = alias.c boa.c buffer.c cgi.c cgi_header.c config.c escape.c \
889         get.c hash.c ip.c log.c mmap_cache.c pipe.c queue.c range.c \
890         read.c request.c response.c signals.c util.c sublog.c \
891 +       plugin.c \
892         @ASYNCIO_SOURCE@ @ACCESSCONTROL_SOURCE@
893  
894  OBJS = $(SOURCES:.c=.o) timestamp.o @STRUTIL@
895 Index: boa-0.94.14rc21/src/boa.h
896 ===================================================================
897 --- boa-0.94.14rc21.orig/src/boa.h      2005-02-22 15:11:29.000000000 +0100
898 +++ boa-0.94.14rc21/src/boa.h   2008-06-11 10:25:04.000000000 +0200
899 @@ -38,6 +38,7 @@
900  #include <fcntl.h>
901  #include <limits.h>             /* OPEN_MAX */
902  #include <setjmp.h>
903 +#include <stdbool.h>
904  
905  #include <netinet/in.h>
906  
907 @@ -49,6 +50,7 @@
908  #include "compat.h"             /* oh what fun is porting */
909  #include "defines.h"
910  #include "globals.h"
911 +#include "boa-plugin.h"
912  
913  /* alias */
914  void add_alias(const char *fakename, const char *realname, enum ALIAS type);
915 @@ -225,5 +227,10 @@
916  void range_pool_push(Range * r);
917  int ranges_fixup(request * req);
918  int range_parse(request * req, const char *str);
919
920 +
921 +/* plugins */
922 +int plugin_init(char *path);
923 +int plugin_handle(request * req);
924 +struct httpd_plugin *plugin_lookup(request *req);
925 +
926  #endif
927 Index: boa-0.94.14rc21/src/config.c
928 ===================================================================
929 --- boa-0.94.14rc21.orig/src/config.c   2005-02-22 15:11:29.000000000 +0100
930 +++ boa-0.94.14rc21/src/config.c        2008-06-11 10:25:04.000000000 +0200
931 @@ -64,6 +64,7 @@
932  char *error_log_name;
933  char *access_log_name;
934  char *cgi_log_name;
935 +char *plugin_root = NULL;
936  
937  int use_localtime;
938  
939 @@ -165,6 +166,7 @@
940      {"CGINice", S2A, c_set_int, &cgi_nice},
941  #endif
942      {"CGIEnv", S2A, c_add_cgi_env, NULL},
943 +    {"PluginRoot", S1A, c_set_string, &plugin_root},
944  };
945  
946  static void c_add_cgi_env(char *v1, char *v2, void *t)
947 @@ -544,6 +546,22 @@
948                  single_post_limit);
949          exit(EXIT_FAILURE);
950      }
951 +       if (plugin_root) {
952 +               char *plugin_path = plugin_root;
953 +               char *next;
954 +
955 +               do {
956 +                       next = strchr(plugin_path, ':');
957 +                       if (next) {
958 +                               *next = 0;
959 +                               next++;
960 +                       }
961 +
962 +                       plugin_init(plugin_path);
963 +                       plugin_path = next;
964 +               } while (plugin_path);
965 +               free(plugin_root);
966 +       }
967  
968      if (vhost_root && virtualhost) {
969          fprintf(stderr, "Both VHostRoot and VirtualHost were enabled, and "
970 Index: boa-0.94.14rc21/src/alias.c
971 ===================================================================
972 --- boa-0.94.14rc21.orig/src/alias.c    2005-02-22 15:11:29.000000000 +0100
973 +++ boa-0.94.14rc21/src/alias.c 2008-06-11 10:25:04.000000000 +0200
974 @@ -246,6 +246,7 @@
975  
976      uri_len = strlen(req->request_uri);
977      current = find_alias(req->request_uri, uri_len);
978 +       req->plugin = !!plugin_lookup(req);
979      if (current) {
980          if (current->type == SCRIPTALIAS) /* Script */
981              return init_script_alias(req, current, uri_len);
982 @@ -263,7 +264,7 @@
983                 uri_len - current->fake_len + 1);
984  
985          if (current->type == REDIRECT) { /* Redirect */
986 -            if (req->method == M_POST) { /* POST to non-script */
987 +            if ((req->method == M_POST) && !req->plugin) { /* POST to non-script */
988                  /* it's not a cgi, but we try to POST??? */
989                  log_error_doc(req);
990                  fputs("POST to non-script is disallowed.\n", stderr);
991 @@ -432,7 +433,7 @@
992          else
993              req->cgi_type = CGI;
994          return 1;
995 -    } else if (req->method == M_POST) { /* POST to non-script */
996 +    } else if ((req->method == M_POST) && !req->plugin) { /* POST to non-script */
997          /* it's not a cgi, but we try to POST??? */
998          log_error_doc(req);
999          fputs("POST to non-script disallowed.\n", stderr);
1000 Index: boa-0.94.14rc21/src/globals.h
1001 ===================================================================
1002 --- boa-0.94.14rc21.orig/src/globals.h  2005-02-22 15:11:29.000000000 +0100
1003 +++ boa-0.94.14rc21/src/globals.h       2008-06-11 10:25:04.000000000 +0200
1004 @@ -158,6 +158,7 @@
1005      char *host;                 /* what we end up using for 'host', no matter the contents of header_host */
1006  
1007      int post_data_fd;           /* fd for post data tmpfile */
1008 +    int read_data_fd;           /* fd for post data input (plugin) */
1009  
1010      char *path_info;            /* env variable */
1011      char *path_translated;      /* env variable */
1012 @@ -193,6 +194,8 @@
1013      char accept[MAX_ACCEPT_LENGTH]; /* Accept: fields */
1014  #endif
1015  
1016 +    bool plugin;
1017 +
1018      struct request *next;       /* next */
1019      struct request *prev;       /* previous */
1020  };
1021 Index: boa-0.94.14rc21/src/read.c
1022 ===================================================================
1023 --- boa-0.94.14rc21.orig/src/read.c     2005-02-23 16:41:55.000000000 +0100
1024 +++ boa-0.94.14rc21/src/read.c  2008-06-11 10:25:04.000000000 +0200
1025 @@ -375,8 +375,11 @@
1026  
1027      if (bytes_to_write == 0) {  /* nothing left in buffer to write */
1028          req->header_line = req->header_end = req->buffer;
1029 -        if (req->filepos >= req->filesize)
1030 -            return init_cgi(req);
1031 +        if (req->filepos >= req->filesize) {
1032 +                       if (req->post_data_fd > 0)
1033 +                               close(req->post_data_fd);
1034 +               return init_cgi(req);
1035 +               }
1036          /* if here, we can safely assume that there is more to read */
1037          req->status = BODY_READ;
1038          return 1;
1039 Index: boa-0.94.14rc21/src/boa-plugin.h
1040 ===================================================================
1041 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
1042 +++ boa-0.94.14rc21/src/boa-plugin.h    2008-06-11 10:25:04.000000000 +0200
1043 @@ -0,0 +1,67 @@
1044 +#ifndef _HTTPD_PLUGIN_H__
1045 +#define _HTTPD_PLUGIN_H__
1046 +
1047 +#include "list.h"
1048 +
1049 +/*
1050 + * Definition for HTTP server plugins
1051 + *
1052 + * The context that the plugin is called with for
1053 + * a single http request. It gets allocated in the
1054 + * persistent context before prepare_req and freed
1055 + * there afterwards (still active in the forked
1056 + * context at handle_req time)
1057 + */
1058 +struct http_context
1059 +{
1060 +       char *uri;
1061 +       char *request_method;
1062 +       char *server_addr;
1063 +       char *server_proto;
1064 +       char *query_string;
1065 +       char *remote_addr;
1066 +       unsigned int remote_port;
1067 +       char *content_type;
1068 +       char *content_length;
1069 +       char *http_accept;
1070 +
1071 +       void *priv;
1072 +};
1073 +
1074 +/*
1075 + * the main data structure of httpd plugins.
1076 + */
1077 +struct httpd_plugin
1078 +{
1079 +       /* used by the web server */
1080 +       struct list_head list;
1081 +
1082 +       /* only page requests matching 'prefix' are passed
1083 +        * to prepare_req and handle_req */
1084 +       const char *prefix;
1085 +
1086 +       /* directory that the plugin was found in */
1087 +       const char *dir;
1088 +
1089 +       /* initialize the plugin, if the return value is nonzero,
1090 +        * the plugin will not be used */
1091 +       int (*init)(struct httpd_plugin *);
1092 +
1093 +       /* free all memory associated with the plugin */
1094 +       void (*done)(struct httpd_plugin *);
1095 +
1096 +       /* prepare a page request. this is executed in the main context,
1097 +        * so pay attention to memory usage. should not print any data
1098 +        * to stdout */
1099 +       int (*prepare_req)(struct httpd_plugin *, struct http_context *);
1100 +
1101 +       /* handle the request. can print output data to stdout */
1102 +       int (*handle_req)(struct httpd_plugin *, struct http_context *);
1103 +
1104 +       /* pointer for private data structures of the plugin */
1105 +       void *priv;
1106 +};
1107 +
1108 +#define HTTPD_PLUGIN struct httpd_plugin httpd_plugin =
1109 +
1110 +#endif