summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorGlenn Strauss <gstrauss@gluelogic.com>2021-07-01 14:03:05 -0400
committerGlenn Strauss <gstrauss@gluelogic.com>2023-05-03 23:11:34 -0400
commit79752c5ffe45734261ec49f1d3537a95fe5b1895 (patch)
tree93c71e45dbcd56fedc2e3fa852e1cf81905cac2c /tests
parentde8bf2863d602113ad0b5d26a83c561b2c4ab85a (diff)
downloadlighttpd-git-79752c5ffe45734261ec49f1d3537a95fe5b1895.tar.gz
[tests] _WIN32 fcgi-responder.c, scgi-responder.c
Diffstat (limited to 'tests')
-rw-r--r--tests/fcgi-responder.c115
-rw-r--r--tests/scgi-responder.c126
2 files changed, 209 insertions, 32 deletions
diff --git a/tests/fcgi-responder.c b/tests/fcgi-responder.c
index 6dbc1c01..2d18c592 100644
--- a/tests/fcgi-responder.c
+++ b/tests/fcgi-responder.c
@@ -4,9 +4,10 @@
* - 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
+ * - expect recv data for request headers every 25ms or less (or fail test)
* - no read timeouts for request body; might block reading request body
* - no write timeouts; might block writing response
+ * - no retry if partial send
*
* Copyright(c) 2020 Glenn Strauss gstrauss()gluelogic.com All rights reserved
* License: BSD 3-clause (same as lighttpd)
@@ -14,23 +15,48 @@
#if defined(__sun)
#define __EXTENSIONS__
#endif
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#define VC_EXTRALEAN
+#define _CRT_SECURE_NO_WARNINGS
+#ifdef _MSC_VER
+#pragma comment(lib, "ws2_32.lib")
+#pragma warning(disable:4267)
+#pragma warning(disable:5105) /* warning in winbase.h; good job MS */
+#endif
+#endif
#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 <stdio.h>
#include <stdint.h>
#include <string.h>
-#include <unistd.h>
+#ifndef _WIN32
+#include <stdio.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <unistd.h>
#ifdef HAVE_SIGNAL /* XXX: must be defined; config.h not included here */
#include <signal.h>
#endif
+#else /* _WIN32 */
+#include <io.h>
+#include <winsock2.h>
+#include <basetsd.h> /* SSIZE_T */
+#define ssize_t SSIZE_T
+#define poll WSAPoll
+/* fdopen() is not valid on _WIN32 SOCKET type; emulate fwrite(),
+ * though note that the following does not handle partial send() */
+typedef uintptr_t FILE;
+#define fwrite(ptr,sz,n,stream) \
+ (send((SOCKET)(stream), (const char *)(ptr), (int)((sz)*(n)), 0) \
+ == (int)((sz)*(n)) ? (n) : 0)
+#define fflush(x) do { } while (0)
+#endif /* _WIN32 */
#ifndef MSG_DONTWAIT
#define MSG_DONTWAIT 0
@@ -42,6 +68,26 @@ static int finished;
static unsigned char buf[65536];
+#ifdef _WIN32
+static int
+sock_nb_set (SOCKET fd, unsigned int nb)
+{
+ u_long l = nb;
+ return ioctlsocket(fd, FIONBIO, &l);
+}
+#else
+#if 0 /*(unused)*/
+static int
+sock_nb_set (int fd, unsigned int nb)
+{
+ return nb
+ ? fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK)
+ : fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK);
+}
+#endif
+#endif
+
+
static void
fcgi_header (FCGI_Header * const header, const unsigned char type, const int request_id, const int contentLength, const unsigned char paddingLength)
{
@@ -91,7 +137,7 @@ fcgi_puts (const int req_id, const char * const str, size_t len, FILE * const st
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);
+ fcgi_header(&header, FCGI_STDOUT, req_id, (int)part, 0);
if (1 != fwrite(&header, sizeof(header), 1, stream))
return -1;
if (part != fwrite(str+offset, 1, part, stream))
@@ -137,7 +183,7 @@ fcgi_getenv(const unsigned char * const r, const uint32_t rlen, const char * con
memcpy(s, name, nlen);
s[nlen] = '\0';
char *e = getenv(s);
- if (e) *len = strlen(e);
+ if (e) *len = (int)strlen(e);
return e;
}
@@ -308,17 +354,22 @@ fcgi_recv_packet (FILE * const stream, ssize_t sz)
}
+#ifdef _WIN32
+static int
+fcgi_recv (const SOCKET fd, FILE * const stream)
+#else
static int
fcgi_recv (const int fd, FILE * const stream)
+#endif
{
ssize_t rd = 0, offset = 0;
/* XXX: remain blocking */
- /*fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);*/
+ /*sock_nb_set(fd, 1);*/
do {
struct pollfd pfd = { fd, POLLIN, 0 };
- switch (poll(&pfd, 1, 10)) { /* 10ms timeout */
+ switch (poll(&pfd, 1, 25)) { /* 25ms timeout */
default: /* 1; the only pfd has revents */
break;
case -1: /* error */
@@ -330,8 +381,13 @@ fcgi_recv (const int fd, FILE * const stream)
break;
do {
- rd = recv(fd, buf+offset, sizeof(buf)-offset, MSG_DONTWAIT);
- } while (rd < 0 && errno == EINTR);
+ rd = recv(fd, (char *)buf+offset, sizeof(buf)-offset, MSG_DONTWAIT);
+ }
+ #ifdef _WIN32
+ while (rd < 0 && WSAGetLastError() == WSAEINTR);
+ #else
+ while (rd < 0 && errno == EINTR);
+ #endif
if (rd > 0) {
offset += rd;
@@ -344,7 +400,11 @@ fcgi_recv (const int fd, FILE * const stream)
memmove(buf, buf+rd, offset);
}
}
+ #ifdef _WIN32
+ else if (0 == rd || WSAGetLastError() != WSAEWOULDBLOCK)
+ #else
else if (0 == rd || (errno != EAGAIN && errno != EWOULDBLOCK))
+ #endif
break;
} while (offset < (ssize_t)sizeof(buf));
@@ -355,6 +415,35 @@ fcgi_recv (const int fd, FILE * const stream)
int
main (void)
{
+ #ifdef _WIN32
+
+ WSADATA wsaData;
+ WORD wVersionRequested = MAKEWORD(2, 2);
+ if (0 != WSAStartup(wVersionRequested, &wsaData))
+ return -1;
+
+ /* FCGI_LISTENSOCK_FILENO == STDIN_FILENO == 0 */
+ SOCKET lfd = (SOCKET)GetStdHandle(STD_INPUT_HANDLE);
+ sock_nb_set(lfd, 0);
+
+ SOCKET fd;
+ do {
+ fd = accept(lfd, NULL, NULL);
+ if (fd == INVALID_SOCKET)
+ continue;
+ /* XXX: skip checking FCGI_WEB_SERVER_ADDRS; not implemented */
+
+ /* fdopen() is not valid on _WIN32 SOCKET; pass (FILE *)fd through */
+ fcgi_recv(fd, (FILE *)(uintptr_t)fd);
+ } while (fd != INVALID_SOCKET
+ ? 0 == closesocket(fd) && !finished
+ : WSAGetLastError() == WSAEINTR);
+
+ WSACleanup();
+ return 0;
+
+ #else
+
int fd;
fcntl(FCGI_LISTENSOCK_FILENO, F_SETFL,
fcntl(FCGI_LISTENSOCK_FILENO, F_GETFL) & ~O_NONBLOCK);
@@ -383,4 +472,6 @@ main (void)
} while (fd > 0 ? !finished : errno == EINTR);
return 0;
+
+ #endif
}
diff --git a/tests/scgi-responder.c b/tests/scgi-responder.c
index 9ec86dd5..aa1b0aa5 100644
--- a/tests/scgi-responder.c
+++ b/tests/scgi-responder.c
@@ -3,34 +3,79 @@
* - listens on STDIN_FILENO (socket on STDIN_FILENO must be set up by caller)
* - processes a single SCGI request at a time
* - arbitrary limitation: reads request headers netstring up to 64k in size
- * - expect recv data for request headers netstring every 10ms or less
+ * - expect recv data for request headers netstring every 25ms or less (or fail)
* - no read timeouts for request body; might block reading request body
* - no write timeouts; might block writing response
+ * - no retry if partial send
*
* Copyright(c) 2017 Glenn Strauss gstrauss()gluelogic.com All rights reserved
* License: BSD 3-clause (same as lighttpd)
*/
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#define VC_EXTRALEAN
+#define _CRT_SECURE_NO_WARNINGS
+#ifdef _MSC_VER
+#pragma comment(lib, "ws2_32.lib")
+#pragma warning(disable:4267)
+#pragma warning(disable:5105) /* warning in winbase.h; good job MS */
+#endif
+#endif
#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 <stdio.h>
#include <string.h>
+
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <poll.h>
#include <unistd.h>
+#else
+#include <io.h>
+#include <winsock2.h>
+#include <basetsd.h> /* SSIZE_T */
+#define ssize_t SSIZE_T
+#define poll WSAPoll
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#endif
+#endif
#ifndef MSG_DONTWAIT
#define MSG_DONTWAIT 0
#endif
+#ifndef MSG_NOSIGNAL
+#define MSG_NOSIGNAL 0
+#endif
+
static int finished;
static char buf[65536];
+#ifdef _WIN32
+static int
+sock_nb_set (SOCKET fd, unsigned int nb)
+{
+ u_long l = nb;
+ return ioctlsocket(fd, FIONBIO, &l);
+}
+#else
+static int
+sock_nb_set (int fd, unsigned int nb)
+{
+ return nb
+ ? fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK)
+ : fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK);
+}
+#endif
+
+
static char *
scgi_getenv(char *r, const unsigned long rlen, const char * const name)
{
@@ -52,20 +97,24 @@ scgi_getenv(char *r, const unsigned long rlen, const char * const name)
}
+#ifdef _WIN32
+static void
+scgi_process (const SOCKET fd)
+#else
static void
scgi_process (const int fd)
+#endif
{
ssize_t rd = 0, offset = 0;
char *p = NULL, *r;
unsigned long rlen;
long long cl;
- assert(fd == STDOUT_FILENO); /*(required for response sent with printf())*/
- fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
+ sock_nb_set(fd, 1);
do {
struct pollfd pfd = { fd, POLLIN, 0 };
- switch (poll(&pfd, 1, 10)) { /* 10ms timeout */
+ switch (poll(&pfd, 1, 25)) { /* 25ms timeout */
default: /* 1; the only pfd has revents */
break;
case -1: /* error */
@@ -77,14 +126,23 @@ scgi_process (const int fd)
break;
do {
rd = recv(fd, buf+offset, sizeof(buf)-offset, MSG_DONTWAIT);
- } while (rd < 0 && errno == EINTR);
+ }
+ #ifdef _WIN32
+ while (rd < 0 && WSAGetLastError() == WSAEINTR);
+ #else
+ while (rd < 0 && errno == EINTR);
+ #endif
if (rd > 0)
offset += rd;
else if (0 == rd) {
p = memchr(buf, ':', offset);
break;
}
+ #ifdef _WIN32
+ else if (WSAGetLastError() == WSAEWOULDBLOCK)
+ #else
else if (errno == EAGAIN || errno == EWOULDBLOCK)
+ #endif
continue;
else
break;
@@ -96,11 +154,11 @@ scgi_process (const int fd)
return; /* invalid netstring (and rlen == ULONG_MAX is too long)*/
if (rlen > sizeof(buf) - (p - buf) - 2)
return; /* netstring longer than arbitrary limit we accept here */
- rlen += (p - buf) + 2;
+ rlen += (unsigned long)(p - buf) + 2;
while ((ssize_t)rlen < offset) {
struct pollfd pfd = { fd, POLLIN, 0 };
- switch (poll(&pfd, 1, 10)) { /* 10ms timeout */
+ switch (poll(&pfd, 1, 25)) { /* 25ms timeout */
default: /* 1; the only pfd has revents */
break;
case -1: /* error */
@@ -126,7 +184,7 @@ scgi_process (const int fd)
return; /* timeout or error receiving netstring */
if (buf[rlen-1] != ',')
return; /* invalid netstring */
- rlen -= (p - buf) + 2;
+ rlen -= (unsigned long)(p - buf) + 2;
r = p+1;
/* not checking for empty headers in SCGI request (empty values allowed) */
@@ -145,7 +203,7 @@ scgi_process (const int fd)
if (*p != '\0' || p == r+sizeof("CONTENT_LENGTH") || cl < 0 || 0 != errno)
return; /* invalid CONTENT_LENGTH */
- fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK);
+ sock_nb_set(fd, 0);
/* read,discard request body (currently ignored in these SCGI unit tests)
* (make basic effort to read body; ignore any timeouts or errors here) */
@@ -168,13 +226,13 @@ scgi_process (const int fd)
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 = "Status: 200 OK\n";
+ send(fd, cdata, strlen(cdata), MSG_NOSIGNAL);
cdata = "\n";
}
else if (0 == strcmp(p,"slow-crlf")) {
- printf("Status: 200 OK\r\n");
- fflush(stdout);
+ cdata = "Status: 200 OK\r\n";
+ send(fd, cdata, strlen(cdata), MSG_NOSIGNAL);
cdata = "\r\n";
}
else if (0 == strcmp(p, "die-at-end")) {
@@ -189,7 +247,9 @@ scgi_process (const int fd)
p = NULL;
}
- if (cdata) printf("%s", cdata);
+ /*(note: *not* buffering to send response header and body together)*/
+
+ if (cdata) send(fd, cdata, strlen(cdata), MSG_NOSIGNAL);
if (NULL == p)
cdata = NULL;
@@ -198,15 +258,38 @@ scgi_process (const int fd)
else
cdata = "test123";
- if (cdata) printf("%s", cdata);
-
- fflush(stdout);
+ if (cdata) send(fd, cdata, strlen(cdata), MSG_NOSIGNAL);
}
int
main (void)
{
+ #ifdef _WIN32
+
+ WSADATA wsaData;
+ WORD wVersionRequested = MAKEWORD(2, 2);
+ if (0 != WSAStartup(wVersionRequested, &wsaData))
+ return -1;
+
+ SOCKET lfd = (SOCKET)GetStdHandle(STD_INPUT_HANDLE);
+ sock_nb_set(lfd, 0);
+
+ SOCKET fd;
+ do {
+ fd = accept(lfd, NULL, NULL);
+ if (fd == INVALID_SOCKET)
+ continue;
+ scgi_process(fd);
+ } while (fd != INVALID_SOCKET
+ ? 0 == closesocket(fd) && !finished
+ : WSAGetLastError() == WSAEINTR);
+
+ WSACleanup();
+ return 0;
+
+ #else
+
int fd;
fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) & ~O_NONBLOCK);
close(STDOUT_FILENO); /*(so that accept() returns fd to STDOUT_FILENO)*/
@@ -220,4 +303,7 @@ main (void)
} while (fd > 0 ? 0 == close(fd) && !finished : errno == EINTR);
return 0;
+
+ #endif
+
}