the initial C code for the new HTTP test server
authorDaniel Stenberg <daniel@haxx.se>
Thu, 7 Feb 2002 09:39:15 +0000 (09:39 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 7 Feb 2002 09:39:15 +0000 (09:39 +0000)
tests/server/Makefile [new file with mode: 0644]
tests/server/getpart.c [new file with mode: 0644]
tests/server/sws.c [new file with mode: 0644]

diff --git a/tests/server/Makefile b/tests/server/Makefile
new file mode 100644 (file)
index 0000000..64b11d4
--- /dev/null
@@ -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 (file)
index 0000000..b5355e6
--- /dev/null
@@ -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 (file)
index 0000000..854818c
--- /dev/null
@@ -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;
+}
+