aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/include/tipidee/fcgi.h127
-rw-r--r--src/include/tipidee/headers.h1
-rw-r--r--src/include/tipidee/tipidee.h1
-rw-r--r--src/libtipidee/deps-lib/tipidee24
-rw-r--r--src/libtipidee/tipidee_fcgi_addenv.c41
-rw-r--r--src/libtipidee/tipidee_fcgi_beginrequest.c9
-rw-r--r--src/libtipidee/tipidee_fcgi_beginrequest_body_pack.c14
-rw-r--r--src/libtipidee/tipidee_fcgi_beginrequest_body_unpack.c14
-rw-r--r--src/libtipidee/tipidee_fcgi_beginrequest_record_pack.c9
-rw-r--r--src/libtipidee/tipidee_fcgi_beginrequest_record_unpack.c9
-rw-r--r--src/libtipidee/tipidee_fcgi_endrequest_body_pack.c14
-rw-r--r--src/libtipidee/tipidee_fcgi_endrequest_body_unpack.c14
-rw-r--r--src/libtipidee/tipidee_fcgi_endrequest_record_pack.c9
-rw-r--r--src/libtipidee/tipidee_fcgi_endrequest_record_unpack.c9
-rw-r--r--src/libtipidee/tipidee_fcgi_flush.c10
-rw-r--r--src/libtipidee/tipidee_fcgi_header_pack.c15
-rw-r--r--src/libtipidee/tipidee_fcgi_header_unpack.c14
-rw-r--r--src/libtipidee/tipidee_fcgi_params.c8
-rw-r--r--src/libtipidee/tipidee_fcgi_put.c34
-rw-r--r--src/libtipidee/tipidee_fcgi_putv.c47
-rw-r--r--src/libtipidee/tipidee_fcgi_read.c59
-rw-r--r--src/libtipidee/tipidee_fcgi_startread.c12
-rw-r--r--src/libtipidee/tipidee_fcgi_startwrite.c12
-rw-r--r--src/libtipidee/tipidee_fcgi_stdin.c8
-rw-r--r--src/libtipidee/tipidee_fcgi_unknowntype_body_pack.c11
-rw-r--r--src/libtipidee/tipidee_fcgi_unknowntype_body_unpack.c11
-rw-r--r--src/libtipidee/tipidee_fcgi_unknowntype_record_pack.c9
-rw-r--r--src/libtipidee/tipidee_fcgi_unknowntype_record_unpack.c9
-rw-r--r--src/libtipidee/tipidee_headers_parse.c46
-rw-r--r--src/tipideed/cgi.c107
-rw-r--r--src/tipideed/deps-exe/tipideed1
-rw-r--r--src/tipideed/fastcgi.c314
-rw-r--r--src/tipideed/process_cgi_headers.c115
-rw-r--r--src/tipideed/tipideed-internal.h9
-rw-r--r--src/tipideed/tipideed.c2
35 files changed, 754 insertions, 394 deletions
diff --git a/src/include/tipidee/fcgi.h b/src/include/tipidee/fcgi.h
index be2f0af..597702d 100644
--- a/src/include/tipidee/fcgi.h
+++ b/src/include/tipidee/fcgi.h
@@ -4,17 +4,50 @@
#define TIPIDEE_FCGI_H
#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/uio.h>
-typedef struct fcgi_header_s fcgi_header, *fcgi_header_ref ;
-struct fcgi_header_s
+#include <skalibs/buffer.h>
+#include <skalibs/tai.h>
+#include <skalibs/stralloc.h>
+
+typedef struct tipidee_fcgi_s tipidee_fcgi, *tipidee_fcgi_ref ;
+struct tipidee_fcgi_s
{
- uint8_t version ;
- uint8_t type ;
- uint16_t requestid ;
- uint16_t len ;
- uint8_t padlen ;
- uint8_t reserved ;
+ buffer b ;
+ char buf[4096] ;
+ tain deadline ;
+ uint16_t id ;
} ;
+#define TIPIDEE_FCGI_ZERO { .b = BUFFER_ZERO, .deadline = TAIN_ZERO, .id = 0 }
+
+extern void tipidee_fcgi_startwrite (tipidee_fcgi *, int, pid_t, tain const *) ;
+extern void tipidee_fcgi_startread (tipidee_fcgi *, int, pid_t, tain const *) ;
+
+extern size_t tipidee_fcgi_put (tipidee_fcgi *, uint8_t, char const *, size_t, tain *) ;
+#define tipidee_fcgi_put_g(fc, rectype, s, len) tipidee_fcgi_put(fc, rectype, s, (len), &STAMP)
+
+extern size_t tipidee_fcgi_putv (tipidee_fcgi *, uint8_t, struct iovec const *, unsigned int, tain *) ;
+#define tipidee_fcgi_putv_g(fc, rectype, v, n) tipidee_fcgi_putv(fc, rectype, v, (n), &STAMP)
+
+extern int tipidee_fcgi_flush (tipidee_fcgi *, tain *) ;
+#define tipidee_fcgi_flush_g(fc) tipidee_fcgi_flush((fc), &STAMP)
+
+extern int tipidee_fcgi_beginrequest (tipidee_fcgi *, tain *) ;
+#define tipidee_fcgi_beginrequest_g(fc) tipidee_fcgi_beginrequest((fc), &STAMP)
+
+extern int tipidee_fcgi_addenvb (stralloc *, char const *, size_t, char const *, size_t) ;
+#define tipidee_fcgi_addenv(sa, key, val) tipidee_fcgi_addenvb(sa, key, strlen(key), val, strlen(val))
+
+extern int tipidee_fcgi_params (tipidee_fcgi *, char const *, size_t, tain *) ;
+#define tipidee_fcgi_params_g(fc, s, len) tipidee_fcgi_params(fc, s, (len), &STAMP)
+
+extern int tipidee_fcgi_stdin (tipidee_fcgi *, char const *, size_t, tain *) ;
+#define tipidee_fcgi_stdin_g(fc, s, len) tipidee_fcgi_stdin(fc, s, (len), &STAMP)
+
+extern int tipidee_fcgi_read (tipidee_fcgi *, uint32_t *, stralloc *, tain *) ;
+#define tipidee_fcgi_read_g(fc, status, sa) tipidee_fcgi_read(fc, status, (sa), &STAMP)
typedef enum fcgi_type_e fcgi_type ;
enum fcgi_type_e
@@ -30,33 +63,11 @@ enum fcgi_type_e
FCGI_GET_VALUES,
FCGI_GET_VALUES_RESULT,
FCGI_UNKNOWN_TYPE,
- FCGI_MAXTYPE
-} ;
-
-#define FCGI_NULL_REQUEST_ID 0
-
-extern void tipidee_fcgi_header_pack (char *, fcgi_header const *) ;
-extern void tipidee_fcgi_header_unpack (char const *, fcgi_header *) ;
-
-
-typedef struct fcgi_beginrequest_body_s fcgi_beginrequest_body, *fcgi_beginrequest_body_ref ;
-struct fcgi_beginrequest_body_s
-{
- uint16_t role ;
- uint8_t flags;
- unsigned char reserved[5] ;
} ;
-extern void tipidee_fcgi_beginrequest_body_pack (char *, fcgi_beginrequest_body const *) ;
-extern void tipidee_fcgi_beginrequest_body_unpack (char const *, fcgi_beginrequest_body *) ;
+#define FCGI_VERSION_1 1
-
-typedef struct fcgi_beginrequest_record_s fcgi_beginrequest_record, *fcgi_beginrequest_record_ref ;
-struct fcgi_beginrequest_record_s
-{
- fcgi_header header ;
- fcgi_beginrequest_body body ;
-} ;
+#define FCGI_NULL_REQUEST_ID 0
#define FCGI_KEEP_CONN 1
@@ -64,61 +75,9 @@ struct fcgi_beginrequest_record_s
#define FCGI_AUTHORIZER 2
#define FCGI_FILTER 3
-extern void tipidee_fcgi_beginrequest_record_pack (char *, fcgi_beginrequest_record const *) ;
-extern void tipidee_fcgi_beginrequest_record_unpack (char const *, fcgi_beginrequest_record *) ;
-
-
-typedef struct fcgi_endrequest_body_s fcgi_endrequest_body, *fcgi_endrequest_body_ref ;
-struct fcgi_endrequest_body_s
-{
- uint32_t appstatus ;
- uint8_t protostatus ;
- uint8_t reserved[3] ;
-} ;
-
-extern void tipidee_fcgi_endrequest_body_pack (char *, fcgi_endrequest_body const *) ;
-extern void tipidee_fcgi_endrequest_body_unpack (char const *, fcgi_endrequest_body *) ;
-
-
-typedef struct fcgi_endrequest_record_s fcgi_endrequest_record, *fcgi_endrequest_record_ref ;
-struct fcgi_endrequest_record_s
-{
- fcgi_header header ;
- fcgi_endrequest_body body ;
-} ;
-
#define FCGI_REQUEST_COMPLETE 0
#define FCGI_CANT_MPX_CONN 1
#define FCGI_OVERLOADED 2
#define FCGI_UNKNOWN_ROLE 3
-#define FCGI_MAX_CONNS "FCGI_MAX_CONNS"
-#define FCGI_MAX_REQS "FCGI_MAX_REQS"
-#define FCGI_MPXS_CONNS "FCGI_MPXS_CONNS"
-
-extern void tipidee_fcgi_endrequest_record_pack (char *, fcgi_endrequest_record const *) ;
-extern void tipidee_fcgi_endrequest_record_unpack (char const *, fcgi_endrequest_record *) ;
-
-
-typedef struct fcgi_unknowntype_body_s fcgi_unknowntype_body, *fcgi_unknowntype_body_ref ;
-struct fcgi_unknowntype_body_s
-{
- uint8_t type ;
- uint8_t reserved[7] ;
-} ;
-
-extern void tipidee_fcgi_unknowntype_body_pack (char *, fcgi_unknowntype_body const *) ;
-extern void tipidee_fcgi_unknowntype_body_unpack (char const *, fcgi_unknowntype_body *) ;
-
-
-typedef struct fcgi_unknowntype_record_s fcgi_unknowntype_record, *fcgi_unknowntype_record_ref ;
-struct fcgi_unknowntype_record_s
-{
- fcgi_header header ;
- fcgi_unknowntype_body body ;
-} ;
-
-extern void tipidee_fcgi_unknowntype_record_pack (char *, fcgi_unknowntype_record const *) ;
-extern void tipidee_fcgi_unknowntype_record_unpack (char const *, fcgi_unknowntype_record *) ;
-
#endif
diff --git a/src/include/tipidee/headers.h b/src/include/tipidee/headers.h
index 420b4c9..d4a1a10 100644
--- a/src/include/tipidee/headers.h
+++ b/src/include/tipidee/headers.h
@@ -28,6 +28,7 @@ struct tipidee_headers_s
extern void tipidee_headers_init (tipidee_headers *, char *, size_t) ;
+extern int tipidee_headers_parse_fromstring_nb (char const *, size_t, size_t *, tipidee_headers *, disize *, uint32_t *) ;
extern int tipidee_headers_parse_nb (buffer *, tipidee_headers *, disize *, uint32_t *) ;
extern int tipidee_headers_timed_parse (buffer *, tipidee_headers *, tain const *, tain *) ;
#define tipidee_headers_timed_parse_g(b, hdr, deadline) tipidee_headers_timed_parse(b, hdr, (deadline), &STAMP)
diff --git a/src/include/tipidee/tipidee.h b/src/include/tipidee/tipidee.h
index 50ee7bf..ea0ca72 100644
--- a/src/include/tipidee/tipidee.h
+++ b/src/include/tipidee/tipidee.h
@@ -5,6 +5,7 @@
#include <tipidee/config.h>
#include <tipidee/conf.h>
+#include <tipidee/fcgi.h>
#include <tipidee/headers.h>
#include <tipidee/log.h>
#include <tipidee/method.h>
diff --git a/src/libtipidee/deps-lib/tipidee b/src/libtipidee/deps-lib/tipidee
index 1a73f52..497b74a 100644
--- a/src/libtipidee/deps-lib/tipidee
+++ b/src/libtipidee/deps-lib/tipidee
@@ -10,20 +10,16 @@ tipidee_conf_get_responseheaders.o
tipidee_conf_get_string.o
tipidee_conf_get_uint32.o
tipidee_conf_init.o
-tipidee_fcgi_beginrequest_body_pack.o
-tipidee_fcgi_beginrequest_body_unpack.o
-tipidee_fcgi_beginrequest_record_pack.o
-tipidee_fcgi_beginrequest_record_unpack.o
-tipidee_fcgi_endrequest_body_pack.o
-tipidee_fcgi_endrequest_body_unpack.o
-tipidee_fcgi_endrequest_record_pack.o
-tipidee_fcgi_endrequest_record_unpack.o
-tipidee_fcgi_header_pack.o
-tipidee_fcgi_header_unpack.o
-tipidee_fcgi_unknowntype_body_pack.o
-tipidee_fcgi_unknowntype_body_unpack.o
-tipidee_fcgi_unknowntype_record_pack.o
-tipidee_fcgi_unknowntype_record_unpack.o
+tipidee_fcgi_addenv.o
+tipidee_fcgi_beginrequest.o
+tipidee_fcgi_flush.o
+tipidee_fcgi_params.o
+tipidee_fcgi_put.o
+tipidee_fcgi_putv.o
+tipidee_fcgi_read.o
+tipidee_fcgi_startread.o
+tipidee_fcgi_startwrite.o
+tipidee_fcgi_stdin.o
tipidee_headers_get_content_length.o
tipidee_headers_init.o
tipidee_headers_parse.o
diff --git a/src/libtipidee/tipidee_fcgi_addenv.c b/src/libtipidee/tipidee_fcgi_addenv.c
new file mode 100644
index 0000000..fb9e859
--- /dev/null
+++ b/src/libtipidee/tipidee_fcgi_addenv.c
@@ -0,0 +1,41 @@
+/* ISC license. */
+
+#include <errno.h>
+
+#include <skalibs/uint32.h>
+#include <skalibs/stralloc.h>
+
+#include <tipidee/fcgi.h>
+
+static int encode (stralloc *sa, size_t n)
+{
+ if (n <= 0x7f)
+ {
+ char c = n ;
+ return stralloc_catb(sa, &c, 1) ;
+ }
+ else if (n < 0x7ffffffful)
+ {
+ char pack[4] ;
+ uint32_pack_big(pack, n | 0x80000000) ;
+ return stralloc_catb(sa, pack, 4) ;
+ }
+ else return (errno = EOVERFLOW, 0) ;
+}
+
+int tipidee_fcgi_addenvb (stralloc *sa, char const *key, size_t keylen, char const *val, size_t vallen)
+{
+ size_t start = sa->len ;
+ if (!encode(sa, keylen)) return 0 ;
+ if (!encode(sa, vallen)
+ || !stralloc_catb(sa, key, keylen)
+ || !stralloc_catb(sa, val, vallen)) goto err ;
+ if (sa->len > 0x7fff) goto err0 ;
+ return 1 ;
+
+ err0:
+ errno = E2BIG ;
+ err:
+ sa->len = start ;
+ return 0 ;
+}
diff --git a/src/libtipidee/tipidee_fcgi_beginrequest.c b/src/libtipidee/tipidee_fcgi_beginrequest.c
new file mode 100644
index 0000000..8a5a9a9
--- /dev/null
+++ b/src/libtipidee/tipidee_fcgi_beginrequest.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <tipidee/fcgi.h>
+
+int tipidee_fcgi_beginrequest (tipidee_fcgi *fc, tain *stamp)
+{
+ char body[8] = { 0, FCGI_RESPONDER, FCGI_KEEP_CONN, 0, 0, 0, 0, 0 } ;
+ return tipidee_fcgi_put(fc, FCGI_BEGIN_REQUEST, body, 8, stamp) == 8 ;
+}
diff --git a/src/libtipidee/tipidee_fcgi_beginrequest_body_pack.c b/src/libtipidee/tipidee_fcgi_beginrequest_body_pack.c
deleted file mode 100644
index 400be69..0000000
--- a/src/libtipidee/tipidee_fcgi_beginrequest_body_pack.c
+++ /dev/null
@@ -1,14 +0,0 @@
-/* ISC license. */
-
-#include <string.h>
-
-#include <skalibs/uint16.h>
-
-#include <tipidee/fcgi.h>
-
-void tipidee_fcgi_beginrequest_body_pack (char *s, fcgi_beginrequest_body const *bd)
-{
- uint16_pack_big(s, bd->role) ; s += 2 ;
- *s++ = bd->flags ;
- memset(s, 0, 5) ;
-}
diff --git a/src/libtipidee/tipidee_fcgi_beginrequest_body_unpack.c b/src/libtipidee/tipidee_fcgi_beginrequest_body_unpack.c
deleted file mode 100644
index a729b03..0000000
--- a/src/libtipidee/tipidee_fcgi_beginrequest_body_unpack.c
+++ /dev/null
@@ -1,14 +0,0 @@
-/* ISC license. */
-
-#include <string.h>
-
-#include <skalibs/uint16.h>
-
-#include <tipidee/fcgi.h>
-
-void tipidee_fcgi_beginrequest_body_unpack (char const *s, fcgi_beginrequest_body *bd)
-{
- uint16_unpack_big(s, &bd->role) ; s += 2 ;
- bd->flags = *s++ ;
- memcpy((char *)bd->reserved, s, 5) ; s += 5 ;
-}
diff --git a/src/libtipidee/tipidee_fcgi_beginrequest_record_pack.c b/src/libtipidee/tipidee_fcgi_beginrequest_record_pack.c
deleted file mode 100644
index 3329e8d..0000000
--- a/src/libtipidee/tipidee_fcgi_beginrequest_record_pack.c
+++ /dev/null
@@ -1,9 +0,0 @@
-/* ISC license. */
-
-#include <tipidee/fcgi.h>
-
-void tipidee_fcgi_beginrequest_record_pack (char *s, fcgi_beginrequest_record const *rec)
-{
- tipidee_fcgi_header_pack(s, &rec->header) ; s += 8 ;
- tipidee_fcgi_beginrequest_body_pack(s, &rec->body) ;
-}
diff --git a/src/libtipidee/tipidee_fcgi_beginrequest_record_unpack.c b/src/libtipidee/tipidee_fcgi_beginrequest_record_unpack.c
deleted file mode 100644
index c68a08f..0000000
--- a/src/libtipidee/tipidee_fcgi_beginrequest_record_unpack.c
+++ /dev/null
@@ -1,9 +0,0 @@
-/* ISC license. */
-
-#include <tipidee/fcgi.h>
-
-void tipidee_fcgi_beginrequest_record_unpack (char const *s, fcgi_beginrequest_record *rec)
-{
- tipidee_fcgi_header_unpack(s, &rec->header) ; s += 8 ;
- tipidee_fcgi_beginrequest_body_unpack(s, &rec->body) ;
-}
diff --git a/src/libtipidee/tipidee_fcgi_endrequest_body_pack.c b/src/libtipidee/tipidee_fcgi_endrequest_body_pack.c
deleted file mode 100644
index d289d6d..0000000
--- a/src/libtipidee/tipidee_fcgi_endrequest_body_pack.c
+++ /dev/null
@@ -1,14 +0,0 @@
-/* ISC license. */
-
-#include <string.h>
-
-#include <skalibs/uint32.h>
-
-#include <tipidee/fcgi.h>
-
-void tipidee_fcgi_endrequest_body_pack (char *s, fcgi_endrequest_body const *bd)
-{
- uint32_pack_big(s, bd->appstatus) ; s += 4 ;
- *s++ = bd->protostatus ;
- memset(s, 0, 3) ;
-}
diff --git a/src/libtipidee/tipidee_fcgi_endrequest_body_unpack.c b/src/libtipidee/tipidee_fcgi_endrequest_body_unpack.c
deleted file mode 100644
index 9f52f18..0000000
--- a/src/libtipidee/tipidee_fcgi_endrequest_body_unpack.c
+++ /dev/null
@@ -1,14 +0,0 @@
-/* ISC license. */
-
-#include <string.h>
-
-#include <skalibs/uint32.h>
-
-#include <tipidee/fcgi.h>
-
-void tipidee_fcgi_endrequest_body_unpack (char const *s, fcgi_endrequest_body *bd)
-{
- uint32_unpack_big(s, &bd->appstatus) ; s += 4 ;
- bd->protostatus = *s++ ;
- memcpy((char *)bd->reserved, s, 3) ; s += 3 ;
-}
diff --git a/src/libtipidee/tipidee_fcgi_endrequest_record_pack.c b/src/libtipidee/tipidee_fcgi_endrequest_record_pack.c
deleted file mode 100644
index 46f3ee9..0000000
--- a/src/libtipidee/tipidee_fcgi_endrequest_record_pack.c
+++ /dev/null
@@ -1,9 +0,0 @@
-/* ISC license. */
-
-#include <tipidee/fcgi.h>
-
-void tipidee_fcgi_endrequest_record_pack (char *s, fcgi_endrequest_record const *rec)
-{
- tipidee_fcgi_header_pack(s, &rec->header) ; s += 8 ;
- tipidee_fcgi_endrequest_body_pack(s, &rec->body) ;
-}
diff --git a/src/libtipidee/tipidee_fcgi_endrequest_record_unpack.c b/src/libtipidee/tipidee_fcgi_endrequest_record_unpack.c
deleted file mode 100644
index dc0acd5..0000000
--- a/src/libtipidee/tipidee_fcgi_endrequest_record_unpack.c
+++ /dev/null
@@ -1,9 +0,0 @@
-/* ISC license. */
-
-#include <tipidee/fcgi.h>
-
-void tipidee_fcgi_endrequest_record_unpack (char const *s, fcgi_endrequest_record *rec)
-{
- tipidee_fcgi_header_unpack(s, &rec->header) ; s += 8 ;
- tipidee_fcgi_endrequest_body_unpack(s, &rec->body) ;
-}
diff --git a/src/libtipidee/tipidee_fcgi_flush.c b/src/libtipidee/tipidee_fcgi_flush.c
new file mode 100644
index 0000000..f32f8d4
--- /dev/null
+++ b/src/libtipidee/tipidee_fcgi_flush.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/unix-timed.h>
+
+#include <tipidee/fcgi.h>
+
+int tipidee_fcgi_flush (tipidee_fcgi *fc, tain *stamp)
+{
+ return buffer_timed_flush(&fc->b, &fc->deadline, stamp) ;
+}
diff --git a/src/libtipidee/tipidee_fcgi_header_pack.c b/src/libtipidee/tipidee_fcgi_header_pack.c
deleted file mode 100644
index 2f1a550..0000000
--- a/src/libtipidee/tipidee_fcgi_header_pack.c
+++ /dev/null
@@ -1,15 +0,0 @@
-/* ISC license. */
-
-#include <skalibs/uint16.h>
-
-#include <tipidee/fcgi.h>
-
-void tipidee_fcgi_header_pack (char *s, fcgi_header const *hdr)
-{
- *s++ = hdr->version ;
- *s++ = hdr->type ;
- uint16_pack_big(s, hdr->requestid) ; s += 2 ;
- uint16_pack_big(s, hdr->len) ; s += 2 ;
- *s++ = hdr->padlen ;
- *s++ = 0 ;
-}
diff --git a/src/libtipidee/tipidee_fcgi_header_unpack.c b/src/libtipidee/tipidee_fcgi_header_unpack.c
deleted file mode 100644
index 53debd7..0000000
--- a/src/libtipidee/tipidee_fcgi_header_unpack.c
+++ /dev/null
@@ -1,14 +0,0 @@
-/* ISC license. */
-
-#include <skalibs/uint16.h>
-
-#include <tipidee/fcgi.h>
-
-void tipidee_fcgi_header_unpack (char const *s, fcgi_header *hdr)
-{
- hdr->version = *s++ ;
- hdr->type = *s++ ;
- uint16_unpack_big(s, &hdr->requestid) ; s += 2 ;
- uint16_unpack_big(s, &hdr->len) ; s += 2 ;
- hdr->padlen = *s++ ;
-}
diff --git a/src/libtipidee/tipidee_fcgi_params.c b/src/libtipidee/tipidee_fcgi_params.c
new file mode 100644
index 0000000..cac4e50
--- /dev/null
+++ b/src/libtipidee/tipidee_fcgi_params.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+#include <tipidee/fcgi.h>
+
+int tipidee_fcgi_params (tipidee_fcgi *fc, char const *s, size_t len, tain *stamp)
+{
+ return tipidee_fcgi_put(fc, FCGI_PARAMS, s, len, stamp) == len ;
+}
diff --git a/src/libtipidee/tipidee_fcgi_put.c b/src/libtipidee/tipidee_fcgi_put.c
new file mode 100644
index 0000000..0f4b493
--- /dev/null
+++ b/src/libtipidee/tipidee_fcgi_put.c
@@ -0,0 +1,34 @@
+/* ISC license. */
+
+#include <stdint.h>
+
+#include <skalibs/uint16.h>
+#include <skalibs/buffer.h>
+#include <skalibs/unix-timed.h>
+
+#include <tipidee/fcgi.h>
+
+static uint16_t putit (tipidee_fcgi *fc, uint8_t rectype, char const *s, uint16_t len, tain *stamp)
+{
+ char hdr[8] = { 1, (char)rectype, fc->id >> 8, fc->id & 0xff, 0, 0, 0, 0 } ;
+ uint16_t w ;
+ uint16_pack_big(hdr + 4, len) ;
+ w = buffer_timed_put(&fc->b, hdr, 8, &fc->deadline, stamp) ;
+ if (w < 8) return 0 ;
+ return buffer_timed_put(&fc->b, s, len, &fc->deadline, stamp) ;
+}
+
+size_t tipidee_fcgi_put (tipidee_fcgi *fc, uint8_t rectype, char const *s, size_t len, tain *stamp)
+{
+ size_t w = 0 ;
+ while (len > 0xffffu)
+ {
+ uint16_t r = putit(fc, rectype, s, 0xffffu, stamp) ;
+ w += r ;
+ if (r < 0xffffu) return w ;
+ s += 0xffff ;
+ len -= 0xffff ;
+ }
+ w += putit(fc, rectype, s, len, stamp) ;
+ return w ;
+}
diff --git a/src/libtipidee/tipidee_fcgi_putv.c b/src/libtipidee/tipidee_fcgi_putv.c
new file mode 100644
index 0000000..32f5ba5
--- /dev/null
+++ b/src/libtipidee/tipidee_fcgi_putv.c
@@ -0,0 +1,47 @@
+/* ISC license. */
+
+#include <sys/uio.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <skalibs/uint16.h>
+#include <skalibs/buffer.h>
+#include <skalibs/siovec.h>
+#include <skalibs/unix-timed.h>
+
+#include <tipidee/fcgi.h>
+
+static uint16_t putvit (tipidee_fcgi *fc, uint8_t rectype, struct iovec const *v, unsigned int n, uint16_t len, tain *stamp)
+{
+ char hdr[8] = { 1, (char)rectype, fc->id >> 8, fc->id & 0xff, 0, 0, 0, 0 } ;
+ uint16_t w ;
+ uint16_pack_big(hdr + 4, len) ;
+ w = buffer_timed_put(&fc->b, hdr, 8, &fc->deadline, stamp) ;
+ if (w < 8) return 0 ;
+ return buffer_timed_putv(&fc->b, v, n, &fc->deadline, stamp) ;
+}
+
+size_t tipidee_fcgi_putv (tipidee_fcgi *fc, uint8_t rectype, struct iovec const *v, unsigned int n, tain *stamp)
+{
+ if (!n) return 0 ;
+ size_t w = 0 ;
+ unsigned int base = 0 ;
+ for (unsigned int i = 0 ; i < n ; i++)
+ if (v[i].iov_len > 0xffffu) return (errno = EMSGSIZE, 0) ;
+ while (base < n)
+ {
+ size_t len = 0 ;
+ unsigned int i = 0 ;
+ uint16_t r ;
+ for (; base + i < n ; i++)
+ {
+ if (len + v[base + i].iov_len > 0xffffu) break ;
+ len += v[base + i].iov_len ;
+ }
+ r = putvit(fc, rectype, v + base, i, len, stamp) ;
+ w += r ;
+ if (r < len) break ;
+ base += i ;
+ }
+ return w ;
+}
diff --git a/src/libtipidee/tipidee_fcgi_read.c b/src/libtipidee/tipidee_fcgi_read.c
new file mode 100644
index 0000000..9b6dcb0
--- /dev/null
+++ b/src/libtipidee/tipidee_fcgi_read.c
@@ -0,0 +1,59 @@
+/* ISC license. */
+
+#include <stdint.h>
+#include <errno.h>
+
+#include <skalibs/uint16.h>
+#include <skalibs/uint32.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/unix-timed.h>
+
+#include <tipidee/fcgi.h>
+
+#include <skalibs/posixishard.h>
+
+int tipidee_fcgi_read (tipidee_fcgi *fc, uint32_t *status, stralloc *sa, tain *stamp)
+{
+ int stream ;
+ uint16_t u ;
+ char hdr[8] ;
+ if (buffer_timed_get(&fc->b, hdr, 8, &fc->deadline, stamp) < 8) return -1 ;
+ if (hdr[0] != 1) return (errno = EPROTO, -1) ;
+ uint16_unpack_big(hdr + 2, &u) ;
+ if (u != fc->id) return (errno = EPROTO, -1) ;
+ uint16_unpack_big(hdr + 4, &u) ;
+ switch (hdr[1])
+ {
+ case FCGI_STDOUT : stream = 1 ;
+ case FCGI_STDERR : stream = 2 ;
+ case FCGI_END_REQUEST : stream = 0 ;
+ default : return (errno = EPROTO, -1) ;
+ }
+ if (stream)
+ {
+ if (!stralloc_readyplus(sa, u)) return -1 ;
+ if (buffer_timed_get(&fc->b, sa->s + sa->len, u, &fc->deadline, stamp) < u) return -1 ;
+ sa->len += u ;
+ }
+ else
+ {
+ char endreq[8] ;
+ if (u != 8) return (errno = EPROTO, -1) ;
+ if (buffer_timed_get(&fc->b, endreq, 8, &fc->deadline, stamp) < 8) return -1 ;
+ switch (endreq[4])
+ {
+ case FCGI_REQUEST_COMPLETE : break ;
+ case FCGI_CANT_MPX_CONN : return (errno = ECONNREFUSED, -1) ;
+ case FCGI_OVERLOADED : return (errno = ENFILE, -1) ;
+ case FCGI_UNKNOWN_ROLE : return (errno = EAFNOSUPPORT, -1) ;
+ default : return (errno = EPROTO, 1) ;
+ }
+ uint32_unpack_big(endreq, status) ;
+ }
+ if (hdr[6])
+ {
+ char tmp[(uint8_t)hdr[6]] ;
+ if (buffer_timed_get(&fc->b, tmp, (uint8_t)hdr[6], &fc->deadline, stamp)) return -1 ;
+ }
+ return stream ;
+}
diff --git a/src/libtipidee/tipidee_fcgi_startread.c b/src/libtipidee/tipidee_fcgi_startread.c
new file mode 100644
index 0000000..4899e55
--- /dev/null
+++ b/src/libtipidee/tipidee_fcgi_startread.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+
+#include <tipidee/fcgi.h>
+
+void tipidee_fcgi_startread (tipidee_fcgi *fc, int fd, pid_t pid, tain const *deadline)
+{
+ buffer_init(&fc->b, &buffer_read, fd, fc->buf, 4096) ;
+ fc->deadline = *deadline ;
+ fc->id = pid & 0xffffu ; fc->id += !fc->id ;
+}
diff --git a/src/libtipidee/tipidee_fcgi_startwrite.c b/src/libtipidee/tipidee_fcgi_startwrite.c
new file mode 100644
index 0000000..12fd628
--- /dev/null
+++ b/src/libtipidee/tipidee_fcgi_startwrite.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+
+#include <tipidee/fcgi.h>
+
+void tipidee_fcgi_startwrite (tipidee_fcgi *fc, int fd, pid_t pid, tain const *deadline)
+{
+ buffer_init(&fc->b, &buffer_write, fd, fc->buf, 4096) ;
+ fc->deadline = *deadline ;
+ fc->id = pid & 0xffffu ; fc->id += !fc->id ;
+}
diff --git a/src/libtipidee/tipidee_fcgi_stdin.c b/src/libtipidee/tipidee_fcgi_stdin.c
new file mode 100644
index 0000000..b1a641a
--- /dev/null
+++ b/src/libtipidee/tipidee_fcgi_stdin.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+#include <tipidee/fcgi.h>
+
+int tipidee_fcgi_stdin (tipidee_fcgi *fc, char const *s, size_t len, tain *stamp)
+{
+ return tipidee_fcgi_put(fc, FCGI_STDIN, s, len, stamp) == len ;
+}
diff --git a/src/libtipidee/tipidee_fcgi_unknowntype_body_pack.c b/src/libtipidee/tipidee_fcgi_unknowntype_body_pack.c
deleted file mode 100644
index f99da8f..0000000
--- a/src/libtipidee/tipidee_fcgi_unknowntype_body_pack.c
+++ /dev/null
@@ -1,11 +0,0 @@
-/* ISC license. */
-
-#include <string.h>
-
-#include <tipidee/fcgi.h>
-
-void tipidee_fcgi_unknowntype_body_pack (char *s, fcgi_unknowntype_body const *bd)
-{
- *s++ = bd->type ;
- memset(s, 0, 7) ;
-}
diff --git a/src/libtipidee/tipidee_fcgi_unknowntype_body_unpack.c b/src/libtipidee/tipidee_fcgi_unknowntype_body_unpack.c
deleted file mode 100644
index eb0684c..0000000
--- a/src/libtipidee/tipidee_fcgi_unknowntype_body_unpack.c
+++ /dev/null
@@ -1,11 +0,0 @@
-/* ISC license. */
-
-#include <string.h>
-
-#include <tipidee/fcgi.h>
-
-void tipidee_fcgi_unknowntype_body_unpack (char const *s, fcgi_unknowntype_body *bd)
-{
- bd->type = *s++ ;
- memcpy((char *)bd->reserved, s, 7) ; s += 7 ;
-}
diff --git a/src/libtipidee/tipidee_fcgi_unknowntype_record_pack.c b/src/libtipidee/tipidee_fcgi_unknowntype_record_pack.c
deleted file mode 100644
index 9d962e2..0000000
--- a/src/libtipidee/tipidee_fcgi_unknowntype_record_pack.c
+++ /dev/null
@@ -1,9 +0,0 @@
-/* ISC license. */
-
-#include <tipidee/fcgi.h>
-
-void tipidee_fcgi_unknowntype_record_pack (char *s, fcgi_unknowntype_record const *rec)
-{
- tipidee_fcgi_header_pack(s, &rec->header) ; s += 8 ;
- tipidee_fcgi_unknowntype_body_pack(s, &rec->body) ;
-}
diff --git a/src/libtipidee/tipidee_fcgi_unknowntype_record_unpack.c b/src/libtipidee/tipidee_fcgi_unknowntype_record_unpack.c
deleted file mode 100644
index 24c6631..0000000
--- a/src/libtipidee/tipidee_fcgi_unknowntype_record_unpack.c
+++ /dev/null
@@ -1,9 +0,0 @@
-/* ISC license. */
-
-#include <tipidee/fcgi.h>
-
-void tipidee_fcgi_unknowntype_record_unpack (char const *s, fcgi_unknowntype_record *rec)
-{
- tipidee_fcgi_header_unpack(s, &rec->header) ; s += 8 ;
- tipidee_fcgi_unknowntype_body_unpack(s, &rec->body) ;
-}
diff --git a/src/libtipidee/tipidee_headers_parse.c b/src/libtipidee/tipidee_headers_parse.c
index 4881633..b621b70 100644
--- a/src/libtipidee/tipidee_headers_parse.c
+++ b/src/libtipidee/tipidee_headers_parse.c
@@ -9,6 +9,7 @@
#include <skalibs/bytestr.h>
#include <skalibs/buffer.h>
#include <skalibs/error.h>
+#include <skalibs/disize.h>
#include <skalibs/avltreen.h>
#include <skalibs/unix-timed.h>
@@ -71,26 +72,43 @@ states: 4 bits, actions: 7 bits
*/
-struct tainp_s
+struct buffertime_s
{
+ buffer *b ;
tain const *deadline ;
tain *stamp ;
} ;
-typedef ssize_t get1_func (buffer *, char *, struct tainp_s *) ;
+struct string_s
+{
+ char const *s ;
+ size_t len ;
+ size_t *i ;
+} ;
+
+typedef ssize_t get1_func (char *, void *) ;
typedef get1_func *get1_func_ref ;
-static ssize_t get1_timed (buffer *b, char *c, struct tainp_s *d)
+static ssize_t get1_timed (char *c, void *param)
{
- return buffer_timed_get(b, c, 1, d->deadline, d->stamp) ;
+ struct buffertime_s *p = param ;
+ return buffer_timed_get(p->b, c, 1, p->deadline, p->stamp) ;
}
-static ssize_t get1_notimed (buffer *b, char *c, struct tainp_s *data)
+static ssize_t get1_notimed (char *c, void *param)
{
- (void)data ;
+ buffer *b = param ;
return buffer_get(b, c, 1) ;
}
+static ssize_t get1_string (char *c, void *param)
+{
+ struct string_s *st = param ;
+ if ((*st->i) >= st->len) return (errno = EAGAIN, -1) ;
+ *c = st->s[(*st->i)++] ;
+ return 1 ;
+}
+
static uint8_t cclass (char c)
{
static uint8_t const ctable[128] = "00000000032001000000000000000000365666665566566566666666664565655666666666666666666666666665556666666666666666666666666666656560" ;
@@ -104,7 +122,7 @@ static int needs_processing (char const *s)
return 1 ;
}
-static int tipidee_headers_parse_with (buffer *b, tipidee_headers *hdr, get1_func_ref next, struct tainp_s *data, disize *header, uint32_t *state)
+static int tipidee_headers_parse_with (tipidee_headers *hdr, disize *header, uint32_t *state, get1_func_ref next, void *param)
{
static uint16_t const table[10][8] =
{
@@ -123,7 +141,7 @@ static int tipidee_headers_parse_with (buffer *b, tipidee_headers *hdr, get1_fun
{
uint16_t c ;
char cur = 0 ;
- if ((*next)(b, &cur, data) < 0)
+ if ((*next)(&cur, param) == -1)
return errno == ETIMEDOUT ? 408 : error_isagain(errno) ? -2 : -1 ;
c = table[*state][cclass(cur)] ;
/*
@@ -201,13 +219,19 @@ static int tipidee_headers_parse_with (buffer *b, tipidee_headers *hdr, get1_fun
int tipidee_headers_timed_parse (buffer *b, tipidee_headers *hdr, tain const *deadline, tain *stamp)
{
- struct tainp_s d = { .deadline = deadline, .stamp = stamp } ;
+ struct buffertime_s bt = { .b = b, .deadline = deadline, .stamp = stamp } ;
disize header = DISIZE_ZERO ;
uint32_t state = 0 ;
- return tipidee_headers_parse_with(b, hdr, &get1_timed, &d, &header, &state) ;
+ return tipidee_headers_parse_with(hdr, &header, &state, &get1_timed, &bt) ;
}
int tipidee_headers_parse_nb (buffer *b, tipidee_headers *hdr, disize *header, uint32_t *state)
{
- return tipidee_headers_parse_with(b, hdr, &get1_notimed, 0, header, state) ;
+ return tipidee_headers_parse_with(hdr, header, state, &get1_notimed, b) ;
+}
+
+int tipidee_headers_parse_fromstring_nb (char const *s, size_t len, size_t *i, tipidee_headers *hdr, disize *header, uint32_t *state)
+{
+ struct string_s st = { .s = s, .len = len, .i = i } ;
+ return tipidee_headers_parse_with(hdr, header, state, &get1_string, &st) ;
}
diff --git a/src/tipideed/cgi.c b/src/tipideed/cgi.c
index ca66ec5..83f349d 100644
--- a/src/tipideed/cgi.c
+++ b/src/tipideed/cgi.c
@@ -151,33 +151,9 @@ static inline int do_nph (tipidee_rql const *rql, char const *docroot, char cons
die500sys(rql, errno == ENOENT ? 127 : 126, docroot, "exec nph ", argv[0]) ;
}
-static inline int local_redirect (tipidee_rql *rql, char const *docroot, char const *loc, char *uribuf, char const *cginame)
-{
- size_t n ;
- size_t hostlen = strlen(rql->uri.host) ;
- uint16_t port = rql->uri.port ;
- uint8_t ishttps = rql->uri.https ;
- char hosttmp[hostlen + 1] ;
- memcpy(hosttmp, rql->uri.host, hostlen + 1) ;
- n = tipidee_uri_parse(uribuf, URI_BUFSIZE, loc, &rql->uri) ;
- if (!n || n + hostlen + 1 > URI_BUFSIZE)
- die502x(rql, 2, docroot, "cgi ", cginame, " returned an invalid ", "Location", " value", " for local redirection") ;
- memcpy(uribuf + n, hosttmp, hostlen + 1) ;
- rql->uri.host = uribuf + n ;
- rql->uri.port = port ;
- rql->uri.https = ishttps ;
- tipidee_log_debug(g.logv, "cgi ", cginame, ": local redirect to ", rql->uri.path) ;
- return 1 ;
-}
-
static inline int do_cgi (tipidee_rql *rql, char const *docroot, char const *const *argv, char const *const *envp, char const *body, size_t bodylen, char *uribuf, int autochunk, uint32_t raflags)
{
- char const *reason = "OK" ;
- char const *location ;
- char const *contentlength ;
- char const *statusfield ;
uint64_t rbodylen = 0 ;
- unsigned int status = 0 ;
int r ;
tipidee_headers hdr ;
char hdrbuf[4096] ;
@@ -249,7 +225,6 @@ static inline int do_cgi (tipidee_rql *rql, char const *docroot, char const *con
return 0 ;
normalcase:
-
if (x[1].fd >= 0)
{
if (timed_write_g(x[1].fd, body + bodyw, bodylen - bodyw, &deadline) < bodylen - bodyw)
@@ -262,91 +237,19 @@ static inline int do_cgi (tipidee_rql *rql, char const *docroot, char const *con
}
tain_add_g(&deadline, &g.writetto) ;
- statusfield = tipidee_headers_search(&hdr, "Status") ;
- location = tipidee_headers_search(&hdr, "Location") ;
- contentlength = tipidee_headers_search(&hdr, "Content-Length") ;
- if (contentlength)
- {
- if (!uint640_scan(contentlength, &rbodylen))
- die502x(rql, 2, docroot, "cgi ", argv[0], " returned an invalid ", "Content-Length", " header") ;
- }
- if (statusfield)
- {
- size_t m = uint_scan(statusfield, &status) ;
- if (!m || (statusfield[m] && statusfield[m] != ' '))
- die502x(rql, 2, docroot, "cgi ", argv[0], " returned an invalid ", "Status", " header") ;
- if (statusfield[m]) reason = statusfield + m + 1 ;
- else
- {
- tipidee_defaulttext dt ;
- reason = tipidee_util_defaulttext(status, &dt) ? dt.reason : "" ;
- }
- if (!location && (status == 301 || status == 302 || status == 307 || status == 308))
- die502x(rql, 2, docroot, "cgi ", argv[0], " returned a redirection status code without a ", "Location", " header") ;
- if (status < 100 || status > 999)
- die502x(rql, 2, docroot, "cgi ", argv[0], " returned an invalid ", "Status", " value") ;
- }
- if (location)
- {
- if (!location[0]) die502x(rql, 2, docroot, "cgi ", argv[0], " returned an invalid ", "Location", " header") ;
- if (location[0] == '/' && location[1] != '/')
- {
- close(x[0].fd) ;
- return local_redirect(rql, docroot, location, uribuf, argv[0]) ;
- }
- if (rbodylen)
- {
- if (!status)
- die502x(rql, 2, docroot, "cgi ", argv[0], " didn't output a ", "Status", " header", " for a client redirect response with document") ;
- if (status < 300 || status > 399)
- die502x(rql, 2, docroot, "cgi ", argv[0], " returned an invalid ", "Status", " value", " for a client redirect response with document") ;
- }
- else
- {
- for (size_t i = 0 ; i < hdr.n ; i++)
- {
- char const *key = hdr.buf + hdr.list[i].left ;
- if (!strcasecmp(key, "Location") || !strcasecmp(key, "Status")) continue ;
- if (str_start(key, "X-CGI-")) continue ;
- die502x(rql, 2, docroot, "cgi ", argv[0], " returned extra headers", " for a client redirect response without document") ;
- }
- if (!status)
- {
- status = 302 ;
- reason = "Found" ;
- }
- }
- }
- else
- {
- if (!status) status = 200 ;
- if (status != 304 && (status < 400 || status > 599) && !tipidee_headers_search(&hdr, "Content-Type"))
- die502x(rql, 2, docroot, "cgi ", argv[0], " didn't output a ", "Content-Type", " header") ;
- }
-
- tipidee_response_status(buffer_1, rql, status, reason) ;
- tipidee_response_header_writemerge_G(buffer_1, g.rhdr, g.rhdrn, &hdr, !g.cont) ;
-
- if (contentlength)
+ r = process_cgi_headers(rql, &hdr, docroot, "cgi", argv[0], autochunk, &rbodylen) ;
+ if (r == 2)
{
- char fmt[UINT64_FMT] ;
- fmt[uint64_fmt(fmt, rbodylen)] = 0 ;
- buffer_putsnoflush(buffer_1, "Content-Length: ") ;
- buffer_putsnoflush(buffer_1, fmt) ;
- buffer_putnoflush(buffer_1, "\r\n", 2) ;
+ close(x[0].fd) ;
+ return local_redirect(rql, docroot, tipidee_headers_search(&hdr, "Location"), uribuf, "cgi", argv[0]) ;
}
- else if (autochunk)
- buffer_putsnoflush(buffer_1, "Transfer-Encoding: chunked\r\n") ;
-
- buffer_putnoflush(buffer_1, "\r\n", 2) ;
- tipidee_log_answer(g.logv, rql, status, rbodylen) ;
if (rql->m == TIPIDEE_METHOD_HEAD)
{
if (!buffer_timed_flush_g(buffer_1, &deadline))
strerr_diefu1sys(111, "write to stdout") ;
}
- else if (contentlength)
+ else if (r)
{
size_t len ;
struct iovec v[2] ;
diff --git a/src/tipideed/deps-exe/tipideed b/src/tipideed/deps-exe/tipideed
index bc32b06..1527240 100644
--- a/src/tipideed/deps-exe/tipideed
+++ b/src/tipideed/deps-exe/tipideed
@@ -3,6 +3,7 @@ errors.o
harden.o
fastcgi.o
options.o
+process_cgi_headers.o
regular.o
redirection.o
rproxy.o
diff --git a/src/tipideed/fastcgi.c b/src/tipideed/fastcgi.c
index 5d5debf..ffd2c84 100644
--- a/src/tipideed/fastcgi.c
+++ b/src/tipideed/fastcgi.c
@@ -1,10 +1,15 @@
/* ISC license. */
+#include <errno.h>
#include <stdint.h>
#include <unistd.h>
+#include <string.h>
#include <strings.h>
+#include <skalibs/gccattributes.h>
#include <skalibs/uint16.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/disize.h>
#include <skalibs/fmtscan.h>
#include <skalibs/tai.h>
#include <skalibs/buffer.h>
@@ -16,51 +21,320 @@
#include <tipidee/tipidee.h>
#include "tipideed-internal.h"
-#define putit(b, s, deadline) if (buffer_timed_puts_g(b, s, deadline) == -1) die500sys(rql, 111, docroot, "write to ", fn)
+typedef struct fctx_s fctx, *fctx_ref ;
+struct fctx_s
+{
+ tipidee_fcgi fc ;
+ tipidee_rql *rql ;
+ char const *sub ;
+ char const *docroot ;
+ char const *fn ;
+} ;
+
+
+/*
+ Scan g.sa for environment variables
+
+
+st\ev \0 = other
+ 0 1 2
+
+0 m
+KSTART X X KEY
+
+1 k
+KEY KSTART VSTART KEY
+
+2 mv m m
+VSTART KSTART VALUE VALUE
+
+3 v
+VALUE KSTART VALUE VALUE
+
+4
+X
+
+0x10 k store key start and length
+0x20 m mark
+0x40 v store value start and length
+
+*/
+
+static uint8_t cclass (char c) gccattr_pure ;
+static uint8_t cclass (char c)
+{
+ switch (c)
+ {
+ case 0 : return 0 ;
+ case '=' : return 1 ;
+ default : return 2 ;
+ }
+}
+
+static int parse_vars (stralloc *sa, char const *s, size_t len)
+{
+ static uint8_t table[4][3] =
+ {
+ { 0x04, 0x04, 0x21 },
+ { 0x00, 0x12, 0x01 },
+ { 0x60, 0x23, 0x23 },
+ { 0x40, 0x03, 0x03 }
+ } ;
+ size_t keystart = 0, keylen = 0, mark = 0 ;
+ uint8_t state = 0 ;
+ for (size_t i = 0 ; i < len ; i++)
+ {
+ uint8_t c = table[state][cclass(s[i])] ;
+ state = c & 0x07 ;
+ if (state >= 4) return (errno = EDOM, 0) ;
+ if (c & 0x10) { keystart = mark ; keylen = i - mark ; }
+ if (c & 0x20) mark = i ;
+ if (c & 0x40)
+ {
+ if (!tipidee_fcgi_addenvb(sa, s + keystart, keylen, s + mark, i - mark)) return 0 ;
+ }
+ }
+ return 1 ;
+}
-static void do_fastcgi (tipidee_rql const *rql, int fd, char const *sub, char const *docroot, tipidee_headers const *hdr, char const *body, size_t bodylen, tain const *deadline, char const *fn)
+static void addenv (fctx *c, stralloc *sa, char const *key, char const *val)
{
- char buf[4096] ;
- buffer b = BUFFER_INIT(&buffer_write, fd, buf, 4096) ;
- _exit(0) ;
+ if (!tipidee_fcgi_addenv(sa, key, val))
+ {
+ if (errno != E2BIG) die500sys(c->rql, 111, c->docroot, "prepare environment for ", "fastcgi", " ", c->fn) ;
+ if (!tipidee_fcgi_params_g(&c->fc, sa->s, sa->len)) die500sys(c->rql, 111, c->docroot, "send environment to ", "fastcgi", " ", c->fn) ;
+ sa->len = 0 ;
+ if (!tipidee_fcgi_addenv(sa, key, val)) die500sys(c->rql, 111, c->docroot, "prepare environment for ", "fastcgi", " ", c->fn) ;
+ }
}
-static void fastcgi_unix (tipidee_rql const *rql, char const *socketpath, char const *sub, char const *docroot, tipidee_headers const *hdr, char const *body, size_t bodylen)
+static void prepare_env (fctx *c, tipidee_headers const *hdr, size_t bodylen, stralloc *sa)
+{
+ size_t docrootlen = strlen(c->docroot) ;
+ sa->len = 0 ;
+ if (!parse_vars(sa, g.sa.s + g.cwdlen + 1, g.sa.len - (g.cwdlen + 1)))
+ {
+ if (errno == EDOM) die500sys(c->rql, 102, c->docroot, "can't happen: invalid environment string") ;
+ else die500sys(c->rql, 111, c->docroot, "encode ", "environment string for ", "fastcgi", " ", c->fn) ;
+ }
+ if (bodylen)
+ {
+ char fmt[SIZE_FMT] ;
+ fmt[size_fmt(fmt, bodylen)] = 0 ;
+ addenv(c, sa, "CONTENT_LENGTH", fmt) ;
+ }
+ if (c->rql->uri.query)
+ {
+ size_t pathlen = strlen(c->rql->uri.path) ;
+ size_t querylen = strlen(c->rql->uri.query) ;
+ char val[pathlen + querylen + 2] ;
+ memcpy(val, c->rql->uri.path, pathlen) ;
+ val[pathlen] = '?' ;
+ memcpy(val + pathlen + 1, c->rql->uri.query, querylen + 1) ;
+ addenv(c, sa, "REQUEST_URI", val) ;
+ }
+ else addenv(c, sa, "REQUEST_URI", c->rql->uri.path) ;
+ addenv(c, sa, "REQUEST_METHOD", tipidee_method_tostr(c->rql->m)) ;
+ addenv(c, sa, "QUERY_STRING", c->rql->uri.query ? c->rql->uri.query : "") ;
+ if (c->sub)
+ {
+ size_t sublen = strlen(c->sub) ;
+ size_t pathlen = strlen(c->rql->uri.path) ;
+ char val[pathlen - sublen - docrootlen + 1] ;
+ memcpy(val, c->rql->uri.path + docrootlen, pathlen - sublen - docrootlen) ;
+ val[pathlen - sublen - docrootlen] = 0 ;
+ addenv(c, sa, "PATH_INFO", c->sub) ;
+ addenv(c, sa, "SCRIPT_NAME", val) ;
+ }
+ else addenv(c, sa, "SCRIPT_NAME", c->rql->uri.path + docrootlen) ;
+ addenv(c, sa, "SERVER_NAME", c->rql->uri.host) ;
+ addenv(c, sa, "SERVER_PROTOCOL", c->rql->http_minor ? "HTTP/1.1" : "HTTP/1.0") ;
+
+ for (size_t i = 0 ; i < hdr->n ; i++)
+ {
+ char const *key = hdr->buf + hdr->list[i].left ;
+ char const *val = hdr->buf + hdr->list[i].right ;
+ if (!strcasecmp(key, "Authorization"))
+ {
+ size_t len = strlen(val) ;
+ size_t n = byte_chr(val, len, ' ') ;
+ if (n < len)
+ {
+ char tmp[n+1] ;
+ memcpy(tmp, val, n) ;
+ tmp[n] = 0 ;
+ addenv(c, sa, "AUTH_TYPE", tmp) ;
+ }
+ if (g.flagcgipassauth) addenv(c, sa, "HTTP_AUTHORIZATION", val) ;
+ }
+ else if (!strcasecmp(key, "Content-Type")) addenv(c, sa, "CONTENT_TYPE", val) ;
+ else if (!strcasecmp(key, "Content-Length") || !strcasecmp(key, "Connection")) ;
+ else
+ {
+ size_t keylen = strlen(key) ;
+ char tmp[keylen + 6] ;
+ memcpy(tmp, "HTTP_", 5) ;
+ for (size_t i = 0 ; i < keylen ; i++)
+ tmp[5 + i] = key[i] == '-' ? '_' : key[i] >= 'a' && key[i] <= 'z' ? key[i] - 32 : key[i] ;
+ tmp[5 + keylen] = 0 ;
+ addenv(c, sa, tmp, val) ;
+ }
+ }
+ if (sa->len && !tipidee_fcgi_params_g(&c->fc, sa->s, sa->len))
+ die500sys(c->rql, 111, c->docroot, "send", " environment to ", "fastcgi", " ", c->fn) ;
+ sa->len = 0 ;
+ if (!tipidee_fcgi_params_g(&c->fc, 0, 0))
+ die500sys(c->rql, 111, c->docroot, "finish sending", " environment to ", "fastcgi", " ", c->fn) ;
+}
+
+static void do_write (fctx *c, char const *s, size_t len, uint64_t cl, uint64_t *w)
+{
+ tain wdeadline ;
+ tain_add_g(&wdeadline, &g.writetto) ;
+ if (cl + len > *w)
+ die502x(c->rql, 111, c->docroot, "fastcgi", " ", c->fn, " sent more data than advertised") ;
+ if (!cl)
+ {
+ char fmt[SIZE_XFMT] ;
+ size_t w = size_xfmt(fmt, len) ;
+ if (buffer_timed_put_g(buffer_1, fmt, w, &wdeadline) < w
+ || buffer_timed_put_g(buffer_1, "\r\n", 2, &wdeadline) < 2)
+ strerr_diefusys(111, "write to stdout") ;
+ }
+ if (buffer_timed_put_g(buffer_1, s, len, &wdeadline) < len)
+ strerr_diefusys(111, "write to stdout") ;
+ if (!cl && buffer_timed_put_g(buffer_1, "\r\n", 2, &wdeadline) < 2)
+ strerr_diefusys(111, "write to stdout") ;
+ if (!buffer_timed_flush_g(buffer_1, &wdeadline))
+ strerr_diefusys(111, "write to stdout") ;
+ *w += len ;
+}
+
+static int do_fastcgi (fctx *c, int fd, tipidee_headers const *hdr, char const *body, size_t bodylen, tain const *deadline, char *uribuf)
+{
+ static stralloc sa = STRALLOC_ZERO ;
+ tipidee_headers rhdr ;
+ char rhdrbuf[4096] ;
+ uint64_t cl = 0 ;
+ uint64_t w = 0 ;
+ uint32_t status = 0 ;
+ disize curheader = DISIZE_ZERO ;
+ uint32_t parserstate = 0 ;
+ int stream = 1 ;
+ int state = 0 ;
+
+ tipidee_headers_init(&rhdr, rhdrbuf, 4096) ;
+ tipidee_fcgi_startwrite(&c->fc, fd, getpid(), deadline) ;
+ if (!tipidee_fcgi_beginrequest_g(&c->fc)) die500sys(c->rql, 111, c->docroot, "send request to ", "fastcgi", " ", c->fn) ;
+ prepare_env(c, hdr, bodylen, &sa) ;
+ if (bodylen && !tipidee_fcgi_stdin_g(&c->fc, body, bodylen)) die500sys(c->rql, 111, c->docroot, "send", " request body to ", "fastcgi", " ", c->fn) ;
+ if (!tipidee_fcgi_stdin_g(&c->fc, 0, 0)) die500sys(c->rql, 111, c->docroot, "finish sending", " request body to ", "fastcgi", " ", c->fn) ;
+
+ tipidee_fcgi_startread(&c->fc, fd, c->fc.id, deadline) ;
+ while (stream)
+ {
+ stream = tipidee_fcgi_read_g(&c->fc, &status, &sa) ;
+ if (stream == -1)
+ {
+ switch (errno)
+ {
+ case ECONNREFUSED: die502x(c->rql, 111, c->docroot, "fastcgi", " ", c->fn, " said it can only process one connection") ;
+ case ENFILE: die502x(c->rql, 111, c->docroot, "fastcgi", " ", c->fn, " is overloaded") ;
+ case EAFNOSUPPORT: die502x(c->rql, 111, c->docroot, "fastcgi", " ", c->fn, " does not support the Responder role") ;
+ case EPROTO : die502x(c->rql, 111, c->docroot, "fastcgi", " ", c->fn, " spoke a weird dialect") ;
+ default : die502sys(c->rql, 111, c->docroot, "unable to ", "read", " from ", "fastcgi", " ", c->fn) ;
+ }
+ }
+ else if (stream == 1)
+ {
+ if (!state)
+ {
+ size_t i = 0 ;
+ int r ;
+ switch (tipidee_headers_parse_fromstring_nb(sa.s, sa.len, &i, &rhdr, &curheader, &parserstate))
+ {
+ case -2 : goto cont ;
+ case -1 : die500sys(c->rql, 111, c->docroot, "read", " from ", "fastcgi", " ", c->fn) ;
+ case 0 : break ;
+ case 400 : die502x(c->rql, 2, c->docroot, "invalid output", " from ", "fastcgi", " ", c->fn) ;
+ case 413 : die502x(c->rql, 2, c->docroot, rhdr.n >= TIPIDEE_HEADERS_MAX ? "Too many headers" : "Too much header data", " from ", "fastcgi", " ", c->fn) ;
+ case 500 : die500x(c->rql, 101, c->docroot, "can't happen: ", "avltreen_insert failed", " in do_fastcgi") ;
+ default : die500x(c->rql, 101, c->docroot, "can't happen: ", "unknown tipidee_headers_parse return code", " in do_fastcgi") ;
+ }
+
+ r = process_cgi_headers(c->rql, &rhdr, c->docroot, "fastcgi", c->fn, 1, &cl) ;
+ if (r == 2)
+ {
+ fd_close(fd) ;
+ return local_redirect(c->rql, c->docroot, tipidee_headers_search(&rhdr, "Location"), uribuf, "fastcgi", c->fn) ;
+ }
+ if (c->rql->m == TIPIDEE_METHOD_HEAD)
+ {
+ tain wdeadline ;
+ tain_add_g(&wdeadline, &g.writetto) ;
+ if (!buffer_timed_flush_g(buffer_1, &wdeadline))
+ strerr_diefu1sys(111, "write to stdout") ;
+ return 0 ;
+ }
+ state = 1 ;
+ if (i < sa.len) do_write(c, sa.s + i, sa.len - i, cl, &w) ;
+ }
+ else if (state == 1) do_write(c, sa.s, sa.len, cl, &w) ;
+ else die502x(c->rql, 111, c->docroot, "fastcgi", " ", c->fn, " kept sending FCGI_STDOUT data after EOF marker") ;
+ cont:
+ if (!sa.len) state = 2 ;
+ sa.len = 0 ;
+ }
+ else if (stream == 2)
+ {
+ buffer_putflush(buffer_2, sa.s, sa.len) ;
+ tain_now_g() ;
+ sa.len = 0 ;
+ }
+ else die502x(c->rql, 111, c->docroot, "fastcgi", " ", c->fn, " sent data on an unsupported stream") ;
+ }
+ fd_close(fd) ;
+ if (cl && w < cl)
+ die502x(c->rql, 111, c->docroot, "fastcgi", " ", c->fn, " sent less data than advertised") ;
+ return 0 ;
+}
+
+static int fastcgi_unix (fctx *c, char const *socketpath, tipidee_headers const *hdr, char const *body, size_t bodylen, char *uribuf)
{
tain deadline ;
int fd = ipc_stream_nbcoe() ;
- if (fd == -1) die500sys(rql, 111, docroot, "create socket") ;
+ if (fd == -1) die500sys(c->rql, 111, c->docroot, "create socket") ;
tain_add_g(&deadline, &g.readtto) ;
- if (!ipc_timed_connect_g(fd, socketpath, &deadline)) die500sys(rql, 111, docroot, "connect to ", socketpath) ;
- do_fastcgi(rql, fd, sub, docroot, hdr, body, bodylen, &deadline, socketpath) ;
- fd_close(fd) ;
+ if (!ipc_timed_connect_g(fd, socketpath, &deadline)) die500sys(c->rql, 111, c->docroot, "connect to ", socketpath) ;
+ c->fn = socketpath ;
+ return do_fastcgi(c, fd, hdr, body, bodylen, &deadline, uribuf) ;
}
-static inline void fastcgi_tcp (tipidee_rql const *rql, char const *ip, uint16_t port, int is6, char const *sub, char const *docroot, tipidee_headers const *hdr, char const *body, size_t bodylen)
+static inline int fastcgi_tcp (fctx *c, char const *ip, uint16_t port, int is6, tipidee_headers const *hdr, char const *body, size_t bodylen, char *uribuf)
{
tain deadline ;
size_t m = 0 ;
int fd = socket_tcp46_nbcoe(is6) ;
char fmt[IP6_FMT + UINT16_FMT + 2] ;
- if (fd == -1) die500sys(rql, 111, docroot, "create socket") ;
- tain_add_g(&deadline, &g.readtto) ;
+ if (fd == -1) die500sys(c->rql, 111, c->docroot, "create socket") ;
+ tain_add_g(&deadline, &g.cgitto) ;
if (is6) fmt[m++] = '[' ;
m += is6 ? ip6_fmt(fmt + m, ip) : ip4_fmt(fmt + m, ip) ;
if (is6) fmt[m++] = ']' ;
fmt[m++] = ':' ;
m += uint16_fmt(fmt + m, port) ;
fmt[m++] = 0 ;
-
if (!(is6 ? socket_deadlineconnstamp6_g(fd, ip, port, &deadline) : socket_deadlineconnstamp4_g(fd, ip, port, &deadline)))
- die500sys(rql, 111, docroot, "connect to ", fmt) ;
- do_fastcgi(rql, fd, sub, docroot, hdr, body, bodylen, &deadline, fmt) ;
- fd_close(fd) ;
+ die500sys(c->rql, 111, c->docroot, "connect to ", fmt) ;
+ c->fn = fmt ;
+ return do_fastcgi(c, fd, hdr, body, bodylen, &deadline, uribuf) ;
}
-void fastcgi (tipidee_rql const *rql, tipidee_redirection const *rd, char const *docroot, tipidee_headers const *hdr, char const *body, size_t bodylen)
+int fastcgi (tipidee_rql *rql, tipidee_redirection const *rd, char const *docroot, tipidee_headers const *hdr, char const *body, size_t bodylen, char *uribuf)
{
+ fctx c = { .fc = TIPIDEE_FCGI_ZERO, .rql = rql, .sub = rd->sub, .docroot = docroot, .fn = 0 } ;
if (rd->flags & TIPIDEE_REDIR_ISINET)
- fastcgi_tcp(rql, rd->addr, rd->port, !!(rd->flags & TIPIDEE_REDIR_ISV6), rd->sub, docroot, hdr, body, bodylen) ;
+ return fastcgi_tcp(&c, rd->addr, rd->port, !!(rd->flags & TIPIDEE_REDIR_ISV6), hdr, body, bodylen, uribuf) ;
else
- fastcgi_unix(rql, rd->addr, rd->sub, docroot, hdr, body, bodylen) ;
+ return fastcgi_unix(&c, rd->addr, hdr, body, bodylen, uribuf) ;
}
diff --git a/src/tipideed/process_cgi_headers.c b/src/tipideed/process_cgi_headers.c
new file mode 100644
index 0000000..a02dde7
--- /dev/null
+++ b/src/tipideed/process_cgi_headers.c
@@ -0,0 +1,115 @@
+/* ISC license. */
+
+#include <stdint.h>
+
+#include <skalibs/uint64.h>
+#include <skalibs/types.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/buffer.h>
+
+#include <tipidee/tipidee.h>
+#include "tipideed-internal.h"
+
+int local_redirect (tipidee_rql *rql, char const *docroot, char const *loc, char *uribuf, char const *what, char const *cginame)
+{
+ size_t n ;
+ size_t hostlen = strlen(rql->uri.host) ;
+ uint16_t port = rql->uri.port ;
+ uint8_t ishttps = rql->uri.https ;
+ char hosttmp[hostlen + 1] ;
+ memcpy(hosttmp, rql->uri.host, hostlen + 1) ;
+ n = tipidee_uri_parse(uribuf, URI_BUFSIZE, loc, &rql->uri) ;
+ if (!n || n + hostlen + 1 > URI_BUFSIZE)
+ die502x(rql, 2, docroot, what, " ", cginame, " returned an invalid ", "Location", " value", " for local redirection") ;
+ memcpy(uribuf + n, hosttmp, hostlen + 1) ;
+ rql->uri.host = uribuf + n ;
+ rql->uri.port = port ;
+ rql->uri.https = ishttps ;
+ tipidee_log_debug(g.logv, what, " ", cginame, ": local redirect to ", rql->uri.path) ;
+ return 1 ;
+}
+
+int process_cgi_headers (tipidee_rql const *rql, tipidee_headers *hdr, char const *docroot, char const *what, char const *app, int autochunk, uint64_t *cl)
+{
+ char const *reason = "OK" ;
+ char const *location ;
+ char const *contentlength ;
+ char const *statusfield ;
+ unsigned int status = 0 ;
+
+ statusfield = tipidee_headers_search(hdr, "Status") ;
+ location = tipidee_headers_search(hdr, "Location") ;
+ contentlength = tipidee_headers_search(hdr, "Content-Length") ;
+ if (contentlength)
+ {
+ if (!uint640_scan(contentlength, cl))
+ die502x(rql, 2, docroot, what, " ", app, " returned an invalid ", "Content-Length", " header") ;
+ }
+ if (statusfield)
+ {
+ size_t m = uint_scan(statusfield, &status) ;
+ if (!m || (statusfield[m] && statusfield[m] != ' '))
+ die502x(rql, 2, docroot, what, " ", app, " returned an invalid ", "Status", " header") ;
+ if (statusfield[m]) reason = statusfield + m + 1 ;
+ else
+ {
+ tipidee_defaulttext dt ;
+ reason = tipidee_util_defaulttext(status, &dt) ? dt.reason : "" ;
+ }
+ if (!location && (status == 301 || status == 302 || status == 307 || status == 308))
+ die502x(rql, 2, docroot, what, " ", app, " returned a redirection status code without a ", "Location", " header") ;
+ if (status < 100 || status > 999)
+ die502x(rql, 2, docroot, what, " ", app, " returned an invalid ", "Status", " value") ;
+ }
+ if (location)
+ {
+ if (!location[0]) die502x(rql, 2, docroot, what, " ", app, " returned an invalid ", "Location", " header") ;
+ if (location[0] == '/' && location[1] != '/') return 2 ;
+ if (*cl)
+ {
+ if (!status)
+ die502x(rql, 2, docroot, what, " ", app, " didn't output a ", "Status", " header", " for a client redirect response with document") ;
+ if (status < 300 || status > 399)
+ die502x(rql, 2, docroot, what, " ", app, " returned an invalid ", "Status", " value", " for a client redirect response with document") ;
+ }
+ else
+ {
+ for (uint32_t i = 0 ; i < hdr->n ; i++)
+ {
+ char const *key = hdr->buf + hdr->list[i].left ;
+ if (!strcasecmp(key, "Location") || !strcasecmp(key, "Status")) continue ;
+ if (str_start(key, "X-CGI-")) continue ;
+ die502x(rql, 2, docroot, what, " ", app, " returned extra headers", " for a client redirect response without document") ;
+ }
+ if (!status)
+ {
+ status = 302 ;
+ reason = "Found" ;
+ }
+ }
+ }
+ else
+ {
+ if (!status) status = 200 ;
+ if (status != 304 && (status < 400 || status > 599) && !tipidee_headers_search(hdr, "Content-Type"))
+ die502x(rql, 2, docroot, what, " ", app, " didn't output a ", "Content-Type", " header") ;
+ }
+
+ tipidee_response_status(buffer_1, rql, status, reason) ;
+ tipidee_response_header_writemerge_G(buffer_1, g.rhdr, g.rhdrn, hdr, !g.cont) ;
+
+ if (contentlength)
+ {
+ char fmt[UINT64_FMT] ;
+ fmt[uint64_fmt(fmt, *cl)] = 0 ;
+ buffer_putsnoflush(buffer_1, "Content-Length: ") ;
+ buffer_putsnoflush(buffer_1, fmt) ;
+ buffer_putnoflush(buffer_1, "\r\n", 2) ;
+ }
+ else if (autochunk)
+ buffer_putsnoflush(buffer_1, "Transfer-Encoding: chunked\r\n") ;
+
+ buffer_putnoflush(buffer_1, "\r\n", 2) ;
+ tipidee_log_answer(g.logv, rql, status, *cl) ;
+ return !!contentlength ;
+}
diff --git a/src/tipideed/tipideed-internal.h b/src/tipideed/tipideed-internal.h
index 5d72cd6..9b076cd 100644
--- a/src/tipideed/tipideed-internal.h
+++ b/src/tipideed/tipideed-internal.h
@@ -119,6 +119,7 @@ extern void respond_416 (tipidee_rql const *, char const *, uint64_t) ;
#define die500x(r, e, d, ...) diefx(r, e, d, 500, __VA_ARGS__)
#define die500sys(r, e, d, ...) diefusys(r, e, d, 500, __VA_ARGS__)
#define die502x(r, e, d, ...) diefx(r, e, d, 502, __VA_ARGS__)
+#define die502sys(r, e, d, ...) diefusys(r, e, d, 502, __VA_ARGS__)
/* redirection */
@@ -133,7 +134,7 @@ extern void rproxy (tipidee_rql const *, tipidee_redirection const *, char const
/* fastcgi */
-extern void fastcgi (tipidee_rql const *, tipidee_redirection const *, char const *, tipidee_headers const *, char const *, size_t) ;
+extern int fastcgi (tipidee_rql *, tipidee_redirection const *, char const *, tipidee_headers const *, char const *, size_t, char *) ;
/* trace */
@@ -174,6 +175,12 @@ extern int respond_304 (tipidee_rql const *, char const *, struct stat const *)
extern int respond_cgi (tipidee_rql *, char const *, char const *, size_t, char const *, char *, tipidee_headers const *, tipidee_resattr const *, char const *, size_t) ;
+ /* process_cgi_headers */
+
+extern int process_cgi_headers (tipidee_rql const *, tipidee_headers *, char const *, char const *, char const *, int, uint64_t *) ;
+extern int local_redirect (tipidee_rql *, char const *, char const *, char *, char const *, char const *) ;
+
+
/* util */
extern size_t translate_path (char const *) ;
diff --git a/src/tipideed/tipideed.c b/src/tipideed/tipideed.c
index 4bd3242..858f078 100644
--- a/src/tipideed/tipideed.c
+++ b/src/tipideed/tipideed.c
@@ -246,7 +246,7 @@ static inline int serve (tipidee_rql *rql, char const *docroot, char *uribuf, ti
case TIPIDEE_REDIR_NONE : break ;
case TIPIDEE_REDIR_REDIRECT : respond_30x(rql, &rd) ; return 0 ;
case TIPIDEE_REDIR_RPROXY : rproxy(rql, &rd, docroot, hdr, body, bodylen) ; return 0 ;
- case TIPIDEE_REDIR_FASTCGI : fastcgi(rql, &rd, docroot, hdr, body, bodylen) ; return 0 ;
+ case TIPIDEE_REDIR_FASTCGI : fastcgi(rql, &rd, docroot, hdr, body, bodylen, uribuf) ; return 0 ;
default : strerr_dief(101, "can't happen: ", "unknown redirection type") ;
}
}