[tests] remove FastCGI test dependency on libfcgi
- rewrite fcgi-responder as standalone app fcgi-responder is now a minimal, standalone FastCGI server for tests - remove dependency on fcgi-devel package - merge fcgi-auth into fcgi-responder
This commit is contained in:
parent
c68a7b4552
commit
fc01b820ec
|
@ -32,7 +32,6 @@ configparser.h
|
|||
configure
|
||||
depcomp
|
||||
distribute.sh
|
||||
fcgi-auth
|
||||
fcgi-responder
|
||||
install-sh
|
||||
lemon
|
||||
|
|
14
INSTALL
14
INSTALL
|
@ -142,23 +142,11 @@ required packages to run test harness ::
|
|||
perl-LWP-MediaTypes
|
||||
perl-Tie-Function
|
||||
perl-TimeDate
|
||||
php
|
||||
php-cgi
|
||||
|
||||
optional packages to run test harness ::
|
||||
|
||||
fcgi-devel
|
||||
|
||||
$ cd tests/ && make fcgi-auth fcgi-responder
|
||||
|
||||
run test harness
|
||||
|
||||
$ make check
|
||||
|
||||
run test harness with additional FastCGI tests (requires fcgi-devel package)
|
||||
|
||||
$ cd tests/ && make check-am
|
||||
|
||||
|
||||
static build using SCons
|
||||
------------------------
|
||||
|
@ -193,7 +181,7 @@ build using CMake and Xcode on Mac OS X with MacPorts
|
|||
$ xcodebuild --license
|
||||
$ xcode-select --install
|
||||
$ sudo port selfupdate
|
||||
$ sudo port install autoconf automake cmake libtool m4 pcre pkgconfig zlib brotli openssl libxml sqlite3 openldap fcgi p5-cgi libunwind libunwind-headers mysql57 libev gdbm openldap ossp-uuid
|
||||
$ sudo port install autoconf automake cmake libtool m4 pcre pkgconfig zlib brotli openssl libxml sqlite3 openldap libunwind libunwind-headers mysql57 libev gdbm openldap ossp-uuid
|
||||
# Note: some of the above require more fiddling to configure with CMake...
|
||||
|
||||
# cmake and build
|
||||
|
|
|
@ -331,7 +331,6 @@ if 1:
|
|||
LIBCRYPTO = '',
|
||||
LIBDBI = '',
|
||||
LIBDL = '',
|
||||
LIBFCGI = '',
|
||||
LIBGDBM = '',
|
||||
LIBGNUTLS = '',
|
||||
LIBGSSAPI_KRB5 = '',
|
||||
|
@ -498,10 +497,6 @@ if 1:
|
|||
if autoconf.CheckLibWithHeader('dl', 'dlfcn.h', 'C'):
|
||||
autoconf.env.Append(LIBDL = 'dl')
|
||||
|
||||
# used in tests if present
|
||||
if autoconf.CheckLibWithHeader('fcgi', 'fastcgi.h', 'C'):
|
||||
autoconf.env.Append(LIBFCGI = 'fcgi')
|
||||
|
||||
if env['with_bzip2']:
|
||||
if not autoconf.CheckLibWithHeader('bz2', 'bzlib.h', 'C'):
|
||||
fail("Couldn't find bz2")
|
||||
|
|
11
configure.ac
11
configure.ac
|
@ -1604,17 +1604,6 @@ if test "$mmap" = true; then
|
|||
AC_DEFINE([ENABLE_MMAP], [1], [Use mmap if available])
|
||||
fi
|
||||
|
||||
dnl check for fastcgi lib, for the tests only
|
||||
AC_MSG_NOTICE([----------------------------------------])
|
||||
fastcgi_found=no
|
||||
AC_CHECK_LIB([fcgi], [FCGI_Accept], [
|
||||
AC_CHECK_HEADERS([fastcgi.h fastcgi/fastcgi.h], [
|
||||
fastcgi_found=yes
|
||||
])
|
||||
])
|
||||
|
||||
AM_CONDITIONAL([CHECK_WITH_FASTCGI], [test "$fastcgi_found" = yes])
|
||||
|
||||
|
||||
AC_MSG_NOTICE([----------------------------------------])
|
||||
dnl check for extra compiler options (warning options)
|
||||
|
|
|
@ -116,10 +116,6 @@ check_include_files(stdint.h HAVE_STDINT_H)
|
|||
check_include_files(strings.h HAVE_STRINGS_H)
|
||||
check_include_files(syslog.h HAVE_SYSLOG_H)
|
||||
|
||||
# check for fastcgi lib, for the tests only
|
||||
check_include_files(fastcgi.h HAVE_FASTCGI_H)
|
||||
check_include_files(fastcgi/fastcgi.h HAVE_FASTCGI_FASTCGI_H)
|
||||
|
||||
# will be needed for auth
|
||||
check_include_files(crypt.h HAVE_CRYPT_H)
|
||||
# check if we need libcrypt for crypt_r()
|
||||
|
|
|
@ -54,12 +54,6 @@ conf_data.set('HAVE_STDINT_H', compiler.has_header('stdint.h'))
|
|||
conf_data.set('HAVE_STRINGS_H', compiler.has_header('strings.h'))
|
||||
conf_data.set('HAVE_SYSLOG_H', compiler.has_header('syslog.h'))
|
||||
|
||||
# check for fastcgi lib, for the tests only
|
||||
conf_data.set('HAVE_FASTCGI_H', compiler.has_header('fastcgi.h'))
|
||||
if not(conf_data.get('HAVE_FASTCGI_H'))
|
||||
conf_data.set('HAVE_FASTCGI_FASTCGI_H', compiler.has_header('fastcgi/fastcgi.h'))
|
||||
endif
|
||||
|
||||
# will be needed for auth
|
||||
conf_data.set('HAVE_CRYPT_H', compiler.has_header('crypt.h'))
|
||||
if conf_data.get('HAVE_CRYPT_H')
|
||||
|
|
|
@ -16,15 +16,7 @@ typedef gw_handler_ctx handler_ctx;
|
|||
#include "log.h"
|
||||
#include "status_counter.h"
|
||||
|
||||
#ifdef HAVE_FASTCGI_FASTCGI_H
|
||||
# include <fastcgi/fastcgi.h>
|
||||
#else
|
||||
# ifdef HAVE_FASTCGI_H
|
||||
# include <fastcgi.h>
|
||||
# else
|
||||
# include "compat/fastcgi.h"
|
||||
# endif
|
||||
#endif /* HAVE_FASTCGI_FASTCGI_H */
|
||||
#include "compat/fastcgi.h"
|
||||
|
||||
#if GW_RESPONDER != FCGI_RESPONDER
|
||||
#error "mismatched defines: (GW_RESPONDER != FCGI_RESPONDER)"
|
||||
|
|
|
@ -1,14 +1,4 @@
|
|||
check_include_files(fastcgi.h HAVE_FASTCGI_H)
|
||||
check_include_files(fastcgi/fastcgi.h HAVE_FASTCGI_FASTCGI_H)
|
||||
if(HAVE_FASTCGI_H OR HAVE_FASTCGI_FASTCGI_H)
|
||||
check_library_exists(fcgi FCGI_Accept "" HAVE_FASTCGI)
|
||||
if(HAVE_FASTCGI)
|
||||
add_executable(fcgi-auth fcgi-auth.c)
|
||||
add_executable(fcgi-responder fcgi-responder.c)
|
||||
target_link_libraries(fcgi-auth fcgi)
|
||||
target_link_libraries(fcgi-responder fcgi)
|
||||
endif()
|
||||
endif()
|
||||
add_executable(fcgi-responder fcgi-responder.c)
|
||||
add_executable(scgi-responder scgi-responder.c)
|
||||
|
||||
set(T_FILES
|
||||
|
|
|
@ -1,16 +1,9 @@
|
|||
# lighttpd.conf and conformance.pl expect this directory
|
||||
testdir=$(srcdir)/tmp/lighttpd/
|
||||
|
||||
if CHECK_WITH_FASTCGI
|
||||
check_PROGRAMS=fcgi-auth fcgi-responder scgi-responder
|
||||
|
||||
fcgi_auth_SOURCES=fcgi-auth.c
|
||||
fcgi_auth_LDADD=-lfcgi
|
||||
check_PROGRAMS=fcgi-responder scgi-responder
|
||||
|
||||
fcgi_responder_SOURCES=fcgi-responder.c
|
||||
fcgi_responder_LDADD=-lfcgi
|
||||
endif
|
||||
|
||||
scgi_responder_SOURCES=scgi-responder.c
|
||||
|
||||
TESTS=\
|
||||
|
|
|
@ -25,14 +25,9 @@ extra_dist = Split('fastcgi-10.conf \
|
|||
LightyTest.pm \
|
||||
mod-setenv.t')
|
||||
|
||||
fcgi_auth = None
|
||||
fcgi_responder = None
|
||||
fcgi_responder = env.Program("fcgi-responder", "fcgi-responder.c")
|
||||
scgi_responder = env.Program("scgi-responder", "scgi-responder.c")
|
||||
|
||||
if env['LIBFCGI']:
|
||||
fcgi_auth = env.Program("fcgi-auth", "fcgi-auth.c", LIBS=[env['LIBFCGI'], env['APPEND_LIBS']])
|
||||
fcgi_responder = env.Program("fcgi-responder", "fcgi-responder.c", LIBS=[env['LIBFCGI'], env['APPEND_LIBS']])
|
||||
|
||||
def CopyTestBinary(env, binary):
|
||||
return env.Command(target = env['ENV']['top_builddir'] + '/tests/' + binary, source = binary, action = Copy("$TARGET", "$SOURCE"))
|
||||
|
||||
|
@ -55,9 +50,8 @@ def BuildTestEnv(env, build_type):
|
|||
|
||||
testenv.Depends(runtests, dependencies)
|
||||
|
||||
if env['LIBFCGI']:
|
||||
fcgis = [CopyTestBinary(testenv, 'fcgi-auth'), CopyTestBinary(testenv, 'fcgi-responder')]
|
||||
testenv.Depends(runtests, fcgis)
|
||||
fcgis = [CopyTestBinary(testenv, 'fcgi-responder'), CopyTestBinary(testenv, 'scgi-responder')]
|
||||
testenv.Depends(runtests, fcgis)
|
||||
|
||||
return [prepare, runtests, cleanup]
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ fastcgi.server = (
|
|||
"grisu-auth" => (
|
||||
"host" => "127.0.0.1",
|
||||
"port" => 20000,
|
||||
"bin-path" => env.SRCDIR + "/fcgi-auth",
|
||||
"bin-path" => env.SRCDIR + "/fcgi-responder",
|
||||
"mode" => "authorizer",
|
||||
"check-local" => "disable",
|
||||
),
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#ifdef HAVE_FASTCGI_FASTCGI_H
|
||||
#include <fastcgi/fcgi_stdio.h>
|
||||
#else
|
||||
#include <fcgi_stdio.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int main (void) {
|
||||
|
||||
while (FCGI_Accept() >= 0) {
|
||||
|
||||
/* Status: 200 OK to allow access is implied
|
||||
* if Status header is not included in response */
|
||||
|
||||
char *p = getenv("QUERY_STRING");
|
||||
if (p != NULL && 0 == strcmp(p, "var")) {
|
||||
printf("Variable-X-LIGHTTPD-FCGI-AUTH: LighttpdTestContent\r\n");
|
||||
} else if (p == NULL || 0 != strcmp(p, "ok")) {
|
||||
printf("Status: 403 Forbidden\r\n");
|
||||
}
|
||||
|
||||
printf("\r\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,56 +1,378 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#ifdef HAVE_FASTCGI_FASTCGI_H
|
||||
#include <fastcgi/fcgi_stdio.h>
|
||||
#else
|
||||
#include <fcgi_stdio.h>
|
||||
#endif
|
||||
/*
|
||||
* simple and trivial FastCGI server w/ hard-coded results for use in unit tests
|
||||
* - processes a single FastCGI request at a time (serially)
|
||||
* - listens on FCGI_LISTENSOCK_FILENO
|
||||
* (socket on FCGI_LISTENSOCK_FILENO must be set up by invoker)
|
||||
* expects to be started w/ listening socket already on FCGI_LISTENSOCK_FILENO
|
||||
* - expect recv data for request headers every 10ms or less
|
||||
* - no read timeouts for request body; might block reading request body
|
||||
* - no write timeouts; might block writing response
|
||||
*
|
||||
* Copyright(c) 2020 Glenn Strauss gstrauss()gluelogic.com All rights reserved
|
||||
* License: BSD 3-clause (same as lighttpd)
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <poll.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main (void) {
|
||||
#ifndef MSG_DONTWAIT
|
||||
#define MSG_DONTWAIT 0
|
||||
#endif
|
||||
|
||||
while (FCGI_Accept() >= 0) {
|
||||
char* p;
|
||||
#include "../src/compat/fastcgi.h"
|
||||
|
||||
if (NULL != (p = getenv("QUERY_STRING"))) {
|
||||
if (0 == strcmp(p, "lf")) {
|
||||
printf("Status: 200 OK\n\n");
|
||||
} else if (0 == strcmp(p, "crlf")) {
|
||||
printf("Status: 200 OK\r\n\r\n");
|
||||
} else if (0 == strcmp(p, "slow-lf")) {
|
||||
printf("Status: 200 OK\n");
|
||||
fflush(stdout);
|
||||
printf("\n");
|
||||
} else if (0 == strcmp(p,"slow-crlf")) {
|
||||
printf("Status: 200 OK\r\n");
|
||||
fflush(stdout);
|
||||
printf("\r\n");
|
||||
} else if (0 == strcmp(p, "die-at-end")) {
|
||||
printf("Status: 200 OK\r\n\r\n");
|
||||
printf("test123");
|
||||
FCGI_Finish();
|
||||
break;
|
||||
} else {
|
||||
printf("Status: 200 OK\r\n\r\n");
|
||||
}
|
||||
} else {
|
||||
printf("Status: 500 Internal Foo\r\n\r\n");
|
||||
}
|
||||
static int finished;
|
||||
static unsigned char buf[65536];
|
||||
|
||||
if (0 == strcmp(p, "path_info")) {
|
||||
printf("%s", getenv("PATH_INFO"));
|
||||
} else if (0 == strcmp(p, "script_name")) {
|
||||
printf("%s", getenv("SCRIPT_NAME"));
|
||||
} else if (0 == strcmp(p, "var")) {
|
||||
p = getenv("X_LIGHTTPD_FCGI_AUTH");
|
||||
printf("%s", p ? p : "(no value)");
|
||||
} else {
|
||||
printf("test123");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
static void
|
||||
fcgi_header (FCGI_Header * const header, const unsigned char type, const int request_id, const int contentLength, const unsigned char paddingLength)
|
||||
{
|
||||
/*force_assert(contentLength <= FCGI_MAX_LENGTH);*/
|
||||
|
||||
header->version = FCGI_VERSION_1;
|
||||
header->type = type;
|
||||
header->requestIdB1 = (request_id >> 8) & 0xff;
|
||||
header->requestIdB0 = request_id & 0xff;
|
||||
header->contentLengthB1 = (contentLength >> 8) & 0xff;
|
||||
header->contentLengthB0 = contentLength & 0xff;
|
||||
header->paddingLength = paddingLength;
|
||||
header->reserved = 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fcgi_unknown_type_rec (FCGI_UnknownTypeRecord * const rec, const int req_id, const unsigned char type)
|
||||
{
|
||||
fcgi_header(&rec->header, FCGI_UNKNOWN_TYPE, req_id, sizeof(rec->header), 0);
|
||||
memset(&rec->body.reserved, 0, sizeof(rec->body.reserved));
|
||||
rec->body.type = type;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fcgi_end_request_rec (FCGI_EndRequestRecord * const rec, const int req_id, const uint32_t appStatus, const unsigned char protocolStatus)
|
||||
{
|
||||
fcgi_header(&rec->header, FCGI_END_REQUEST, req_id, sizeof(rec->header), 0);
|
||||
rec->body.appStatusB3 = (appStatus >> 24) & 0xff;
|
||||
rec->body.appStatusB2 = (appStatus >> 16) & 0xff;
|
||||
rec->body.appStatusB1 = (appStatus >> 8) & 0xff;
|
||||
rec->body.appStatusB0 = appStatus & 0xff;
|
||||
rec->body.protocolStatus = protocolStatus;
|
||||
rec->body.reserved[0] = 0;
|
||||
rec->body.reserved[1] = 0;
|
||||
rec->body.reserved[2] = 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fcgi_puts (const int req_id, const char * const str, size_t len, FILE * const stream)
|
||||
{
|
||||
if (NULL == str) return -1;
|
||||
|
||||
FCGI_Header header;
|
||||
|
||||
for (size_t offset = 0, part; offset != len; offset += part) {
|
||||
part = len - offset > FCGI_MAX_LENGTH ? FCGI_MAX_LENGTH : len - offset;
|
||||
fcgi_header(&header, FCGI_STDOUT, req_id, part, 0);
|
||||
if (1 != fwrite(&header, sizeof(header), 1, stream))
|
||||
return -1;
|
||||
if (part != fwrite(str+offset, 1, part, stream))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const char *
|
||||
fcgi_getenv(const unsigned char * const r, const uint32_t rlen, const char * const name, int nlen, int *len)
|
||||
{
|
||||
/* simple search;
|
||||
* if many lookups are done, then should use more efficient data structure*/
|
||||
for (uint32_t i = 0; i < rlen; ) {
|
||||
int klen = r[i];
|
||||
if (!(r[i] & 0x80))
|
||||
++i;
|
||||
else {
|
||||
klen = ((r[i] & ~0x80)<<24) | (r[i+1]<<16) | (r[i+2]<<8) | r[i+3];
|
||||
i += 4;
|
||||
}
|
||||
int vlen = r[i];
|
||||
if (!(r[i] & 0x80))
|
||||
++i;
|
||||
else {
|
||||
vlen = ((r[i] & ~0x80)<<24) | (r[i+1]<<16) | (r[i+2]<<8) | r[i+3];
|
||||
i += 4;
|
||||
}
|
||||
|
||||
if (klen == nlen && 0 == memcmp(r+i, name, klen)) {
|
||||
*len = vlen;
|
||||
return (const char *)r+i+klen;
|
||||
}
|
||||
|
||||
i += klen + vlen;
|
||||
}
|
||||
|
||||
char s[256];
|
||||
if (nlen > (int)sizeof(s)-1)
|
||||
return NULL;
|
||||
memcpy(s, name, nlen);
|
||||
s[nlen] = '\0';
|
||||
char *e = getenv(s);
|
||||
if (e) *len = strlen(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fcgi_process_params (FILE * const stream, int req_id, int role, unsigned char * const r, uint32_t rlen)
|
||||
{
|
||||
const char *p = NULL;
|
||||
int len;
|
||||
|
||||
/* (FCGI_STDIN currently ignored in these FastCGI unit test responses, so
|
||||
* generate response here based on query string values (indicating test) */
|
||||
|
||||
const char *cdata = NULL;
|
||||
|
||||
if (NULL != (p = fcgi_getenv(r, rlen, "QUERY_STRING", 12, &len))) {
|
||||
if (2 == len && 0 == memcmp(p, "lf", 2))
|
||||
cdata = "Status: 200 OK\n\n";
|
||||
else if (4 == len && 0 == memcmp(p, "crlf", 4))
|
||||
cdata = "Status: 200 OK\r\n\r\n";
|
||||
else if (7 == len && 0 == memcmp(p, "slow-lf", 7)) {
|
||||
cdata = "Status: 200 OK\n";
|
||||
if (0 != fcgi_puts(req_id, cdata, strlen(cdata), stream))
|
||||
return -1;
|
||||
fflush(stdout);
|
||||
cdata = "\n";
|
||||
}
|
||||
else if (9 == len && 0 == memcmp(p, "slow-crlf", 9)) {
|
||||
cdata = "Status: 200 OK\r\n";
|
||||
if (0 != fcgi_puts(req_id, cdata, strlen(cdata), stream))
|
||||
return -1;
|
||||
fflush(stdout);
|
||||
cdata = "\r\n";
|
||||
}
|
||||
else if (10 == len && 0 == memcmp(p, "die-at-end", 10)) {
|
||||
cdata = "Status: 200 OK\r\n\r\n";
|
||||
finished = 1;
|
||||
}
|
||||
else if (role == FCGI_AUTHORIZER
|
||||
&& len >= 5 && 0 == memcmp(p, "auth-", 5)) {
|
||||
if (7 == len && 0 == memcmp(p, "auth-ok", 7))
|
||||
cdata = "Status: 200 OK\r\n\r\n";
|
||||
else if (8 == len && 0 == memcmp(p, "auth-var", 8)) {
|
||||
/* Status: 200 OK to allow access is implied
|
||||
* if Status header is not included in response */
|
||||
cdata = "Variable-X-LIGHTTPD-FCGI-AUTH: "
|
||||
"LighttpdTestContent\r\n\r\n";
|
||||
p = NULL;
|
||||
}
|
||||
else {
|
||||
cdata = "Status: 403 Forbidden\r\n\r\n";
|
||||
p = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
cdata = "Status: 200 OK\r\n\r\n";
|
||||
}
|
||||
else {
|
||||
cdata = "Status: 500 Internal Foo\r\n\r\n";
|
||||
p = NULL;
|
||||
}
|
||||
|
||||
if (cdata && 0 != fcgi_puts(req_id, cdata, strlen(cdata), stream))
|
||||
return -1;
|
||||
|
||||
if (NULL == p)
|
||||
cdata = NULL;
|
||||
else if (9 == len && 0 == memcmp(p, "path_info", 9))
|
||||
cdata = fcgi_getenv(r, rlen, "PATH_INFO", 9, &len);
|
||||
else if (11 == len && 0 == memcmp(p, "script_name", 11))
|
||||
cdata = fcgi_getenv(r, rlen, "SCRIPT_NAME", 11, &len);
|
||||
else if (len > 4 && 0 == memcmp(p, "env=", 4))
|
||||
cdata = fcgi_getenv(r, rlen, p+4, len-4, &len);
|
||||
else if (8 == len && 0 == memcmp(p, "auth-var", 8))
|
||||
cdata = fcgi_getenv(r, rlen, "X_LIGHTTPD_FCGI_AUTH", 20, &len);
|
||||
else {
|
||||
cdata = "test123";
|
||||
len = sizeof("test123")-1;
|
||||
}
|
||||
|
||||
if (cdata && 0 != fcgi_puts(req_id, cdata, (size_t)len, stream))
|
||||
return -1;
|
||||
|
||||
/*(XXX: always sending appStatus 0)*/
|
||||
FCGI_EndRequestRecord endrec;
|
||||
fcgi_end_request_rec(&endrec, req_id, 0, FCGI_REQUEST_COMPLETE);
|
||||
if (1 != fwrite(&endrec, sizeof(endrec), 1, stream))
|
||||
return -1; /* error writing FCGI_END_REQUEST; ignore */
|
||||
|
||||
return -2; /* done */
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fcgi_dispatch_packet (FILE *stream, ssize_t offset, uint32_t len)
|
||||
{
|
||||
FCGI_Header * const h = (FCGI_Header *)(buf+offset);
|
||||
int req_id = (h->requestIdB1 << 8) | h->requestIdB0;
|
||||
int type = h->type;
|
||||
|
||||
if (type > FCGI_MAXTYPE) {
|
||||
FCGI_UnknownTypeRecord unkrec;
|
||||
fcgi_unknown_type_rec(&unkrec, req_id, type);
|
||||
if (1 != fwrite(&unkrec, sizeof(unkrec), 1, stream))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (0 == req_id) {
|
||||
/* not implemented: FCGI_GET_VALUES
|
||||
* FCGI_GET_VALUES_RESULT
|
||||
* FCGI_MAX_CONNS: 1
|
||||
* FCGI_MAX_REQS: 1
|
||||
* FCGI_MPXS_CONNS: 0
|
||||
* ...
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* XXX: save role from FCGI_BEGIN_REQUEST; should keep independent state */
|
||||
static int role;
|
||||
|
||||
switch (type) {
|
||||
case FCGI_BEGIN_REQUEST:
|
||||
role = (buf[offset+FCGI_HEADER_LEN] << 8)
|
||||
| buf[offset+FCGI_HEADER_LEN+1];
|
||||
return 0; /* ignore; could save req_id and match further packets */
|
||||
case FCGI_ABORT_REQUEST:
|
||||
return -2; /* done */
|
||||
case FCGI_END_REQUEST:
|
||||
return -1; /* unexpected; this server is not sending FastCGI requests */
|
||||
case FCGI_PARAMS:
|
||||
return fcgi_process_params(stream, req_id, role,
|
||||
buf+offset+FCGI_HEADER_LEN, len);
|
||||
case FCGI_STDIN:
|
||||
/* XXX: TODO read and discard request body
|
||||
* (currently ignored in these FastCGI unit tests)
|
||||
* (make basic effort to read body; ignore any timeouts or errors) */
|
||||
return -1; /* unexpected; this server is not expecting request body */
|
||||
case FCGI_STDOUT:
|
||||
return -1; /* unexpected; this server is not sending FastCGI requests */
|
||||
case FCGI_STDERR:
|
||||
return -1; /* unexpected; this server is not sending FastCGI requests */
|
||||
case FCGI_DATA:
|
||||
return -1; /* unexpected; this server is not sending FastCGI requests */
|
||||
case FCGI_GET_VALUES:
|
||||
return 0; /* ignore; not implemented */
|
||||
case FCGI_GET_VALUES_RESULT:
|
||||
return 0; /* ignore; not implemented */
|
||||
default:
|
||||
return -1; /* unexpected */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ssize_t
|
||||
fcgi_recv_packet (FILE * const stream, ssize_t sz)
|
||||
{
|
||||
ssize_t offset = 0;
|
||||
while (sz - offset >= (ssize_t)FCGI_HEADER_LEN) {
|
||||
FCGI_Header * const h = (FCGI_Header *)(buf+offset);
|
||||
uint32_t pad = h->paddingLength;
|
||||
uint32_t len = (h->contentLengthB1 << 8) | h->contentLengthB0;
|
||||
if (sz - offset < (ssize_t)(FCGI_HEADER_LEN + len + pad))
|
||||
break;
|
||||
int rc = fcgi_dispatch_packet(stream, offset, len);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
offset += (ssize_t)(FCGI_HEADER_LEN + len + pad);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fcgi_recv (const int fd, FILE * const stream)
|
||||
{
|
||||
ssize_t rd = 0, offset = 0;
|
||||
|
||||
/* XXX: remain blocking */
|
||||
/*fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);*/
|
||||
|
||||
do {
|
||||
struct pollfd pfd = { fd, POLLIN, 0 };
|
||||
switch (poll(&pfd, 1, 10)) { /* 10ms timeout */
|
||||
default: /* 1; the only pfd has revents */
|
||||
break;
|
||||
case -1: /* error */
|
||||
case 0: /* timeout */
|
||||
pfd.revents |= POLLERR;
|
||||
break;
|
||||
}
|
||||
if (!(pfd.revents & POLLIN))
|
||||
break;
|
||||
|
||||
do {
|
||||
rd = recv(fd, buf+offset, sizeof(buf)-offset, MSG_DONTWAIT);
|
||||
} while (rd < 0 && errno == EINTR);
|
||||
|
||||
if (rd > 0) {
|
||||
offset += rd;
|
||||
rd = fcgi_recv_packet(stream, offset);
|
||||
if (rd < 0)
|
||||
return (-2 == rd) ? 0 : -1; /*(-2 indicates done)*/
|
||||
if (rd > 0) {
|
||||
offset -= rd;
|
||||
if (offset)
|
||||
memmove(buf, buf+rd, offset);
|
||||
}
|
||||
}
|
||||
else if (0 == rd || (errno != EAGAIN && errno != EWOULDBLOCK))
|
||||
break;
|
||||
} while (offset < (ssize_t)sizeof(buf));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
int fd;
|
||||
fcntl(FCGI_LISTENSOCK_FILENO, F_SETFL,
|
||||
fcntl(FCGI_LISTENSOCK_FILENO, F_GETFL) & ~O_NONBLOCK);
|
||||
|
||||
do {
|
||||
fd = accept(FCGI_LISTENSOCK_FILENO, NULL, NULL);
|
||||
if (fd < 0)
|
||||
continue;
|
||||
/* XXX: skip checking FCGI_WEB_SERVER_ADDRS; not implemented */
|
||||
|
||||
/* uses stdio to retain prior behavior of output buffering (default)
|
||||
* and flushing with fflush() at specific points */
|
||||
FILE *stream = fdopen(fd, "r+");
|
||||
if (NULL == stream) {
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
fcgi_recv(fd, stream);
|
||||
fflush(stream);
|
||||
fclose(stream);
|
||||
} while (fd > 0 ? !finished : errno == EINTR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,16 +1,7 @@
|
|||
if conf_data.get('HAVE_FASTCGI_H') or conf_data.get('HAVE_FASTCGI_FASTCGI_H')
|
||||
libfcgi = compiler.find_library('fcgi', required: false)
|
||||
if libfcgi.found()
|
||||
executable('fcgi-auth',
|
||||
sources: 'fcgi-auth.c',
|
||||
dependencies: common_flags + [ libfcgi ],
|
||||
)
|
||||
executable('fcgi-responder',
|
||||
sources: 'fcgi-responder.c',
|
||||
dependencies: common_flags + [ libfcgi ],
|
||||
)
|
||||
endif
|
||||
endif
|
||||
executable('fcgi-responder',
|
||||
sources: 'fcgi-responder.c',
|
||||
dependencies: common_flags,
|
||||
)
|
||||
|
||||
executable('scgi-responder',
|
||||
sources: 'scgi-responder.c',
|
||||
|
|
|
@ -239,14 +239,14 @@ EOF
|
|||
}
|
||||
|
||||
SKIP: {
|
||||
skip "no fcgi-auth, fcgi-responder found", 15
|
||||
unless (-x $tf->{BASEDIR}."/tests/fcgi-auth" || -x $tf->{BASEDIR}."/tests/fcgi-auth.exe")
|
||||
&& (-x $tf->{BASEDIR}."/tests/fcgi-responder" || -x $tf->{BASEDIR}."/tests/fcgi-responder.exe");
|
||||
skip "no fcgi-responder found", 15
|
||||
unless ( -x $tf->{BASEDIR}."/tests/fcgi-responder"
|
||||
|| -x $tf->{BASEDIR}."/tests/fcgi-responder.exe");
|
||||
|
||||
$tf->{CONFIGFILE} = 'fastcgi-responder.conf';
|
||||
ok($tf->start_proc == 0, "Starting lighttpd with $tf->{CONFIGFILE}") or die();
|
||||
$t->{REQUEST} = ( <<EOF
|
||||
GET /index.html?ok HTTP/1.0
|
||||
GET /index.html?auth-ok HTTP/1.0
|
||||
Host: auth.example.org
|
||||
EOF
|
||||
);
|
||||
|
@ -254,7 +254,7 @@ EOF
|
|||
ok($tf->handle_http($t) == 0, 'FastCGI - Auth');
|
||||
|
||||
$t->{REQUEST} = ( <<EOF
|
||||
GET /index.html?fail HTTP/1.0
|
||||
GET /index.html?auth-fail HTTP/1.0
|
||||
Host: auth.example.org
|
||||
EOF
|
||||
);
|
||||
|
@ -262,7 +262,7 @@ EOF
|
|||
ok($tf->handle_http($t) == 0, 'FastCGI - Auth');
|
||||
|
||||
$t->{REQUEST} = ( <<EOF
|
||||
GET /expire/access.txt?ok HTTP/1.0
|
||||
GET /expire/access.txt?auth-ok HTTP/1.0
|
||||
Host: auth.example.org
|
||||
EOF
|
||||
);
|
||||
|
@ -270,7 +270,7 @@ EOF
|
|||
ok($tf->handle_http($t) == 0, 'FastCGI - Auth in subdirectory');
|
||||
|
||||
$t->{REQUEST} = ( <<EOF
|
||||
GET /index.fcgi?varfail HTTP/1.0
|
||||
GET /index.fcgi?auth-varfail HTTP/1.0
|
||||
Host: auth.example.org
|
||||
EOF
|
||||
);
|
||||
|
@ -278,7 +278,7 @@ EOF
|
|||
ok($tf->handle_http($t) == 0, 'FastCGI - Auth Fail with FastCGI responder afterwards');
|
||||
|
||||
$t->{REQUEST} = ( <<EOF
|
||||
GET /index.fcgi?var HTTP/1.0
|
||||
GET /index.fcgi?auth-var HTTP/1.0
|
||||
Host: auth.example.org
|
||||
EOF
|
||||
);
|
||||
|
|
|
@ -160,42 +160,47 @@ scgi_process (const int fd)
|
|||
cl -= rd;
|
||||
}
|
||||
|
||||
/*(from fcgi-responder.c, substituting scgi_getenv() for getenv())*/
|
||||
{
|
||||
if (NULL != (p = scgi_getenv(r, rlen, "QUERY_STRING"))) {
|
||||
if (0 == strcmp(p, "lf")) {
|
||||
printf("Status: 200 OK\n\n");
|
||||
} else if (0 == strcmp(p, "crlf")) {
|
||||
printf("Status: 200 OK\r\n\r\n");
|
||||
} else if (0 == strcmp(p, "slow-lf")) {
|
||||
printf("Status: 200 OK\n");
|
||||
fflush(stdout);
|
||||
printf("\n");
|
||||
} else if (0 == strcmp(p,"slow-crlf")) {
|
||||
printf("Status: 200 OK\r\n");
|
||||
fflush(stdout);
|
||||
printf("\r\n");
|
||||
} else if (0 == strcmp(p, "die-at-end")) {
|
||||
printf("Status: 200 OK\r\n\r\n");
|
||||
finished = 1;
|
||||
} else {
|
||||
printf("Status: 200 OK\r\n\r\n");
|
||||
}
|
||||
} else {
|
||||
printf("Status: 500 Internal Foo\r\n\r\n");
|
||||
}
|
||||
|
||||
if (0 == strcmp(p, "path_info")) {
|
||||
printf("%s", scgi_getenv(r, rlen, "PATH_INFO"));
|
||||
} else if (0 == strcmp(p, "script_name")) {
|
||||
printf("%s", scgi_getenv(r, rlen, "SCRIPT_NAME"));
|
||||
} else if (0 == strcmp(p, "var")) {
|
||||
p = scgi_getenv(r, rlen, "X_LIGHTTPD_FCGI_AUTH");
|
||||
printf("%s", p ? p : "(no value)");
|
||||
} else {
|
||||
printf("test123");
|
||||
}
|
||||
/*(similar to fcgi-responder.c:fcgi_process_params())*/
|
||||
const char *cdata = NULL;
|
||||
if (NULL != (p = scgi_getenv(r, rlen, "QUERY_STRING"))) {
|
||||
if (0 == strcmp(p, "lf"))
|
||||
cdata = "Status: 200 OK\n\n";
|
||||
else if (0 == strcmp(p, "crlf"))
|
||||
cdata = "Status: 200 OK\r\n\r\n";
|
||||
else if (0 == strcmp(p, "slow-lf")) {
|
||||
printf("Status: 200 OK\n");
|
||||
fflush(stdout);
|
||||
cdata = "\n";
|
||||
}
|
||||
else if (0 == strcmp(p,"slow-crlf")) {
|
||||
printf("Status: 200 OK\r\n");
|
||||
fflush(stdout);
|
||||
cdata = "\r\n";
|
||||
}
|
||||
else if (0 == strcmp(p, "die-at-end")) {
|
||||
cdata = "Status: 200 OK\r\n\r\n";
|
||||
finished = 1;
|
||||
}
|
||||
else
|
||||
cdata = "Status: 200 OK\r\n\r\n";
|
||||
}
|
||||
else {
|
||||
cdata = "Status: 500 Internal Foo\r\n\r\n";
|
||||
p = NULL;
|
||||
}
|
||||
|
||||
if (cdata) printf("%s", cdata);
|
||||
|
||||
if (NULL == p)
|
||||
cdata = NULL;
|
||||
else if (0 == strcmp(p, "path_info"))
|
||||
cdata = scgi_getenv(r, rlen, "PATH_INFO");
|
||||
else if (0 == strcmp(p, "script_name"))
|
||||
cdata = scgi_getenv(r, rlen, "SCRIPT_NAME");
|
||||
else
|
||||
cdata = "test123";
|
||||
|
||||
if (cdata) printf("%s", cdata);
|
||||
|
||||
fflush(stdout);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue