summaryrefslogtreecommitdiff
path: root/tests/scgi-responder.c
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/scgi-responder.c
parentde8bf2863d602113ad0b5d26a83c561b2c4ab85a (diff)
downloadlighttpd-git-79752c5ffe45734261ec49f1d3537a95fe5b1895.tar.gz
[tests] _WIN32 fcgi-responder.c, scgi-responder.c
Diffstat (limited to 'tests/scgi-responder.c')
-rw-r--r--tests/scgi-responder.c126
1 files changed, 106 insertions, 20 deletions
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
+
}