diff options
author | Daniel Stenberg <daniel@haxx.se> | 2002-02-07 09:39:15 +0000 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2002-02-07 09:39:15 +0000 |
commit | 3d4511daf3cc54c487af7167cf0f574d50654c9a (patch) | |
tree | 48bd6474e4911d3bd9e90b5f9bb8f869c80ae2be | |
parent | 4748b40ad968898bde53b7e59ac1b2e7674578fa (diff) |
the initial C code for the new HTTP test server
-rw-r--r-- | tests/server/Makefile | 18 | ||||
-rw-r--r-- | tests/server/getpart.c | 132 | ||||
-rw-r--r-- | tests/server/sws.c | 324 |
3 files changed, 474 insertions, 0 deletions
diff --git a/tests/server/Makefile b/tests/server/Makefile new file mode 100644 index 000000000..64b11d42e --- /dev/null +++ b/tests/server/Makefile @@ -0,0 +1,18 @@ +CC = gcc +OPTIM = -O2 +DEF = -DDEFAULT_PORT=7676 +CFLAGS = -g -Wall $(OPTIM) $(DEF) + +.PHONY: all clean + +TARGET = sws +OBJS= sws.o getpart.o + +all: $(TARGET) + +$(TARGET): $(OBJS) + $(CC) $(LDFLAGS) -o $@ $^ + +clean: + -rm -f $(OBJS) *~ $(TARGET) core logfile + diff --git a/tests/server/getpart.c b/tests/server/getpart.c new file mode 100644 index 000000000..b5355e69e --- /dev/null +++ b/tests/server/getpart.c @@ -0,0 +1,132 @@ + +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <stdlib.h> + +#define EAT_SPACE(ptr) while( ptr && *ptr && isspace(*ptr) ) ptr++ +#define EAT_WORD(ptr) while( ptr && *ptr && !isspace(*ptr) && ('>' != *ptr)) ptr++ + +char *spitout(FILE *stream, char *main, char *sub, int *size) +{ + char buffer[8192]; /* big enough for anything */ + char cmain[128]=""; /* current main section */ + char csub[128]=""; /* current sub section */ + char *ptr; + char *end; + char display = 0; + + char *string; + int stringlen=0; + int stralloc=256; + + enum { + STATE_OUTSIDE, + STATE_INMAIN, + STATE_INSUB, + STATE_ILLEGAL + } state = STATE_OUTSIDE; + + string = (char *)malloc(stralloc); + + while(fgets(buffer, sizeof(buffer), stream)) { + + ptr = buffer; + + /* pass white spaces */ + EAT_SPACE(ptr); + + if('<' != *ptr) { + if(display) { + int len; + printf("=> %s", buffer); + + len = strlen(buffer); + + if((len + stringlen) > stralloc) { + char *newptr= realloc(string, stralloc*2); + if(newptr) { + string = newptr; + stralloc *= 2; + } + else + return NULL; + } + strcpy(&string[stringlen], buffer); + stringlen += len; + } + continue; + } + + ptr++; + EAT_SPACE(ptr); + + if('/' == *ptr) { + /* end of a section */ + ptr++; + EAT_SPACE(ptr); + + end = ptr; + EAT_WORD(end); + *end = 0; + + if((state == STATE_INSUB) && + !strcmp(csub, ptr)) { + /* this is the end of the currently read sub section */ + state--; + csub[0]=0; /* no sub anymore */ + } + else if((state == STATE_INMAIN) && + !strcmp(cmain, ptr)) { + /* this is the end of the currently read main section */ + state--; + cmain[0]=0; /* no main anymore */ + } + } + else { + /* this is the beginning of a section */ + end = ptr; + EAT_WORD(end); + + *end = 0; + switch(state) { + case STATE_OUTSIDE: + strcpy(cmain, ptr); + state = STATE_INMAIN; + break; + case STATE_INMAIN: + strcpy(csub, ptr); + state = STATE_INSUB; + break; + } + } + + if((STATE_INSUB == state) && + !strcmp(cmain, main) && + !strcmp(csub, sub)) { + printf("* %s\n", buffer); + display = 1; /* start displaying */ + } + else { + printf("%d (%s/%s): %s\n", state, cmain, csub, buffer); + display = 0; /* no display */ + } + } + + *size = stringlen; + return string; +} + +#ifdef TEST +int main(int argc, char **argv) +{ + if(argc< 3) { + printf("./moo main sub\n"); + } + else { + int size; + char *buffer = spitout(stdin, argv[1], argv[2], &size); + } + return 0; +} +#endif diff --git a/tests/server/sws.c b/tests/server/sws.c new file mode 100644 index 000000000..854818c7b --- /dev/null +++ b/tests/server/sws.c @@ -0,0 +1,324 @@ +/* sws.c: simple (silly?) web server */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <getopt.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <assert.h> + +#ifndef DEFAULT_PORT +#define DEFAULT_PORT 8642 +#endif + +#ifndef DEFAULT_LOGFILE +#define DEFAULT_LOGFILE "/dev/null" +#endif + +#define DOCBUFSIZE 4 +#define BUFFERSIZE (DOCBUFSIZE * 1024) + +#define VERSION "SWS/0.1" + +#define TEST_DATA_PATH "../data/test%d" + +static char *doc404 = "HTTP/1.1 404 Not Found\n" + "Server: " VERSION "\n" + "Connection: close\n" + "Content-Type: text/html\n" + "\n" + "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n" + "<HTML><HEAD>\n" + "<TITLE>404 Not Found</TITLE>\n" + "</HEAD><BODY>\n" + "<H1>Not Found</H1>\n" + "The requested URL was not found on this server.\n" + "<P><HR><ADDRESS>" VERSION "</ADDRESS>\n" "</BODY></HTML>\n"; + +static volatile int sigpipe, sigterm; +static FILE *logfp; + + +static void logmsg(const char *msg) +{ + time_t t = time(NULL); + struct tm *curr_time = localtime(&t); + char loctime[80]; + + strcpy(loctime, asctime(curr_time)); + loctime[strlen(loctime) - 1] = '\0'; + fprintf(logfp, "%s: pid %d: %s\n", loctime, getpid(), msg); + fprintf(stderr, "%s: pid %d: %s\n", loctime, getpid(), msg); + fflush(logfp); +} + + +static void sigpipe_handler(int sig) +{ + sigpipe = 1; +} + + +static void sigterm_handler(int sig) +{ + char logbuf[100]; + snprintf(logbuf, 100, "Got signal %d, terminating", sig); + logmsg(logbuf); + sigterm = 1; +} + +int ProcessRequest(char *request) +{ + char *line=request; + long contentlength=-1; + +#define END_OF_HEADERS "\r\n\r\n" + + char *end; + end = strstr(request, END_OF_HEADERS); + + if(!end) + /* we don't have a complete request yet! */ + return 0; + + do { + if(!strncasecmp("Content-Length:", line, 15)) + contentlength = strtol(line, &line, 10); + + line = strchr(line, '\n'); + if(line) + line++; + } while(line); + + if(contentlength > -1 ) { + if(contentlength <= strlen(end+strlen(END_OF_HEADERS))) + return 1; /* done */ + else + return 0; /* not complete yet */ + } + return 1; /* done */ +} + + +#define REQBUFSIZ 4096 +#define MAXDOCNAMELEN 1024 +#define REQUEST_KEYWORD_SIZE 256 +static int get_request(int sock) +{ + char reqbuf[REQBUFSIZ], doc[MAXDOCNAMELEN]; + char request[REQUEST_KEYWORD_SIZE]; + unsigned int offset = 0; + int prot_major, prot_minor; + + while (offset < REQBUFSIZ) { + int got = recv(sock, reqbuf + offset, REQBUFSIZ - offset, 0); + if (got <= 0) { + if (got < 0) { + perror("recv"); + return -1; + } + logmsg("Connection closed by client"); + return -1; + } + offset += got; + + reqbuf[offset] = 0; + + if(ProcessRequest(reqbuf)) + break; + } + + if (offset >= REQBUFSIZ) { + logmsg("Request buffer overflow, closing connection"); + return -1; + } + reqbuf[offset]=0; + + logmsg("Got request:"); + logmsg(reqbuf); + + if (sscanf(reqbuf, "%s %s HTTP/%d.%d", + request, + doc, + &prot_major, + &prot_minor) == 4) { + char *ptr; + int test_no=0; + + /* find the last slash */ + ptr = strrchr(doc, '/'); + + /* get the number after it */ + if(ptr) { + test_no = strtol(ptr+1, &ptr, 10); + + logmsg("Found test number in PATH"); + } + else + logmsg("Did not find test number in PATH"); + + return test_no; + } + + logmsg("Got illegal request"); + fprintf(stderr, "Got illegal request\n"); + return -1; +} + + +static int send_doc(int sock, int doc) +{ + int written; + int count; + char *buffer; + char *ptr; + FILE *stream; + + char filename[256]; + + if(doc < 0) { + buffer = doc404; + ptr = NULL; + stream=NULL; + } + else { + sprintf(filename, TEST_DATA_PATH, doc); + + stream=fopen(filename, "rb"); + if(!stream) { + logmsg("Couldn't open test file"); + return 0; + } + + ptr = buffer = spitout(stream, "reply", "data", &count); + } + + do { + written = send(sock, buffer, count, 0); + if (written < 0) { + fclose(stream); + return -1; + } + count -= written; + buffer += written; + } while(count>0); + + if(ptr) + free(ptr); + if(stream) + fclose(stream); + + return 0; +} + + +static void usage(const char *me) +{ + fprintf(stderr, "Usage: %s [ OPTIONS ]\n", me); + fprintf(stderr, + "-p NUM --port=NUM accept requests on port NUM (default %d)\n", + DEFAULT_PORT); + fprintf(stderr, + "-l FILE --logfile=FILE log requests to file FILE (default %s)\n", + DEFAULT_LOGFILE); + fprintf(stderr, + "-f NUM --fork=NUM fork NUM server processes (default 0)\n"); + fprintf(stderr, "-h --help this screen\n"); + exit(1); +} + + +int main(int argc, char *argv[]) +{ + struct sockaddr_in me; + int sock, msgsock, flag; + unsigned short port = DEFAULT_PORT; + char *logfile = DEFAULT_LOGFILE; + int c, longind; + + if(argc>1) + port = atoi(argv[1]); + + logfile = "logfile"; + + logfp = fopen(logfile, "a"); + if (!logfp) { + perror(logfile); + exit(1); + } + + signal(SIGPIPE, sigpipe_handler); + signal(SIGINT, sigterm_handler); + signal(SIGTERM, sigterm_handler); + + siginterrupt(SIGPIPE, 1); + siginterrupt(SIGINT, 1); + siginterrupt(SIGTERM, 1); + + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + perror("opening stream socket"); + fprintf(logfp, "Error opening socket -- aborting\n"); + fclose(logfp); + exit(1); + } + + flag = 1; + if (setsockopt + (sock, SOL_SOCKET, SO_REUSEADDR, (const void *) &flag, + sizeof(int)) < 0) { + perror("setsockopt(SO_REUSEADDR)"); + } + + me.sin_family = AF_INET; + me.sin_addr.s_addr = INADDR_ANY; + me.sin_port = htons(port); + if (bind(sock, (struct sockaddr *) &me, sizeof me) < 0) { + perror("binding stream socket"); + fprintf(logfp, "Error binding socket -- aborting\n"); + fclose(logfp); + exit(1); + } + + /* start accepting connections */ + listen(sock, 5); + + printf("*** %s listening on port %u ***\n", VERSION, port); + + while (!sigterm) { + int doc; + + msgsock = accept(sock, NULL, NULL); + + if (msgsock == -1) { + if (sigterm) { + break; + } + /* perror("accept"); */ + continue; + } + + logmsg("New client connected"); + + doc = get_request(msgsock); + if (doc > 0) + send_doc(msgsock, doc); + else + send_doc(msgsock, -1); + + close(msgsock); + } + + close(sock); + fclose(logfp); + + return 0; +} + |