diff options
-rw-r--r-- | netcon/tiny-web-server.c | 253 |
1 files changed, 0 insertions, 253 deletions
diff --git a/netcon/tiny-web-server.c b/netcon/tiny-web-server.c deleted file mode 100644 index ca9ef0b7..00000000 --- a/netcon/tiny-web-server.c +++ /dev/null @@ -1,253 +0,0 @@ -/* - * tiny.c - a minimal HTTP server that serves static and - * dynamic content with the GET method. Neither - * robust, secure, nor modular. Use for instructional - * purposes only. - * Dave O'Hallaron, Carnegie Mellon - * - * usage: tiny <port> - */ - -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> -#include <string.h> -#include <netdb.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/mman.h> -#include <sys/wait.h> -#include <netinet/in.h> -#include <arpa/inet.h> - -#define BUFSIZE 1024 -#define MAXERRS 16 - -extern char **environ; /* the environment */ - -/* - * error - wrapper for perror used for bad syscalls - */ -void error(char *msg) { - perror(msg); - exit(1); -} - -/* - * cerror - returns an error message to the client - */ -void cerror(FILE *stream, char *cause, char *errno, - char *shortmsg, char *longmsg) { - fprintf(stream, "HTTP/1.1 %s %s\n", errno, shortmsg); - fprintf(stream, "Content-type: text/html\n"); - fprintf(stream, "\n"); - fprintf(stream, "<html><title>Tiny Error</title>"); - fprintf(stream, "<body bgcolor=""ffffff"">\n"); - fprintf(stream, "%s: %s\n", errno, shortmsg); - fprintf(stream, "<p>%s: %s\n", longmsg, cause); - fprintf(stream, "<hr><em>The Tiny Web server</em>\n"); -} - -int main(int argc, char **argv) { - - /* variables for connection management */ - int parentfd; /* parent socket */ - int childfd; /* child socket */ - int portno; /* port to listen on */ - int clientlen; /* byte size of client's address */ - int optval; /* flag value for setsockopt */ - struct sockaddr_in serveraddr; /* server's addr */ - struct sockaddr_in clientaddr; /* client addr */ - - /* variables for connection I/O */ - FILE *stream; /* stream version of childfd */ - char buf[BUFSIZE]; /* message buffer */ - char method[BUFSIZE]; /* request method */ - char uri[BUFSIZE]; /* request uri */ - char version[BUFSIZE]; /* request method */ - char filename[BUFSIZE];/* path derived from uri */ - char filetype[BUFSIZE];/* path derived from uri */ - char cgiargs[BUFSIZE]; /* cgi argument list */ - char *p; /* temporary pointer */ - int is_static; /* static request? */ - struct stat sbuf; /* file status */ - int fd; /* static content filedes */ - int pid; /* process id from fork */ - int wait_status; /* status from wait */ - - /* check command line args */ - if (argc != 2) { - fprintf(stderr, "usage: %s <port>\n", argv[0]); - exit(1); - } - portno = atoi(argv[1]); - - /* open socket descriptor */ - parentfd = socket(AF_INET, SOCK_STREAM, 0); - if (parentfd < 0) - error("ERROR opening socket"); - - /* allows us to restart server immediately */ - optval = 1; - setsockopt(parentfd, SOL_SOCKET, SO_REUSEADDR, - (const void *)&optval , sizeof(int)); - - /* bind port to socket */ - bzero((char *) &serveraddr, sizeof(serveraddr)); - serveraddr.sin_family = AF_INET; - serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); - serveraddr.sin_port = htons((unsigned short)portno); - if (bind(parentfd, (struct sockaddr *) &serveraddr, - sizeof(serveraddr)) < 0) - error("ERROR on binding"); - - /* get us ready to accept connection requests */ - if (listen(parentfd, 5) < 0) /* allow 5 requests to queue up */ - error("ERROR on listen"); - - /* - * main loop: wait for a connection request, parse HTTP, - * serve requested content, close connection. - */ - clientlen = sizeof(clientaddr); - while (1) { - - /* wait for a connection request */ - childfd = accept(parentfd, (struct sockaddr *) &clientaddr, &clientlen); - if (childfd < 0) - error("ERROR on accept"); - - /* open the child socket descriptor as a stream */ - if ((stream = fdopen(childfd, "r+")) == NULL) - error("ERROR on fdopen"); - - /* get the HTTP request line */ - fgets(buf, BUFSIZE, stream); - printf("%s", buf); - sscanf(buf, "%s %s %s\n", method, uri, version); - - /* tiny only supports the GET method */ - if (strcasecmp(method, "GET")) { - cerror(stream, method, "501", "Not Implemented", - "Tiny does not implement this method"); - fclose(stream); - close(childfd); - continue; - } - - /* read (and ignore) the HTTP headers */ - fgets(buf, BUFSIZE, stream); - printf("%s", buf); - while(strcmp(buf, "\r\n")) { - fgets(buf, BUFSIZE, stream); - printf("%s", buf); - } - - /* parse the uri [crufty] */ - if (!strstr(uri, "cgi-bin")) { /* static content */ - is_static = 1; - strcpy(cgiargs, ""); - strcpy(filename, "."); - strcat(filename, uri); - if (uri[strlen(uri)-1] == '/') - strcat(filename, "index.html"); - } - else { /* dynamic content */ - is_static = 0; - p = index(uri, '?'); - if (p) { - strcpy(cgiargs, p+1); - *p = '\0'; - } - else { - strcpy(cgiargs, ""); - } - strcpy(filename, "."); - strcat(filename, uri); - } - - /* make sure the file exists */ - if (stat(filename, &sbuf) < 0) { - cerror(stream, filename, "404", "Not found", - "Tiny couldn't find this file"); - fclose(stream); - close(childfd); - continue; - } - - /* serve static content */ - if (is_static) { - if (strstr(filename, ".html")) - strcpy(filetype, "text/html"); - else if (strstr(filename, ".gif")) - strcpy(filetype, "image/gif"); - else if (strstr(filename, ".jpg")) - strcpy(filetype, "image/jpg"); - else - strcpy(filetype, "text/plain"); - - /* print response header */ - fprintf(stream, "HTTP/1.1 200 OK\n"); - fprintf(stream, "Server: Tiny Web Server\n"); - fprintf(stream, "Content-length: %d\n", (int)sbuf.st_size); - fprintf(stream, "Content-type: %s\n", filetype); - fprintf(stream, "\r\n"); - fflush(stream); - - /* Use mmap to return arbitrary-sized response body */ - fd = open(filename, O_RDONLY); - p = mmap(0, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - fwrite(p, 1, sbuf.st_size, stream); - munmap(p, sbuf.st_size); - } - - /* serve dynamic content */ - else { - /* make sure file is a regular executable file */ - if (!(S_IFREG & sbuf.st_mode) || !(S_IXUSR & sbuf.st_mode)) { - cerror(stream, filename, "403", "Forbidden", - "You are not allow to access this item"); - fclose(stream); - close(childfd); - continue; - } - - /* a real server would set other CGI environ vars as well*/ - setenv("QUERY_STRING", cgiargs, 1); - - /* print first part of response header */ - sprintf(buf, "HTTP/1.1 200 OK\n"); - write(childfd, buf, strlen(buf)); - sprintf(buf, "Server: Tiny Web Server\n"); - write(childfd, buf, strlen(buf)); - - /* create and run the child CGI process so that all child - output to stdout and stderr goes back to the client via the - childfd socket descriptor */ - pid = fork(); - if (pid < 0) { - perror("ERROR in fork"); - exit(1); - } - else if (pid > 0) { /* parent process */ - wait(&wait_status); - } - else { /* child process*/ - close(0); /* close stdin */ - dup2(childfd, 1); /* map socket to stdout */ - dup2(childfd, 2); /* map socket to stderr */ - if (execve(filename, NULL, environ) < 0) { - perror("ERROR in execve"); - } - } - } - - /* clean up */ - fclose(stream); - close(childfd); - - } -} - |