Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* $begin tinymain */
- /*
- * tiny.c - A simple, iterative HTTP/1.0 Web server that uses the
- * GET method to serve static and dynamic content.
- */
- #include "csapp.h"
- // DEBUG Value
- // Used for reading debug statements
- #define DEBUG 1
- void doit(int fd);
- void read_requesthdrs(rio_t *rp);
- int parse_uri(char *uri, char *filename, char *cgiargs);
- void serve_static(int fd, char *filename, int filesize);
- void get_filetype(char *filename, char *filetype);
- void serve_dynamic(int fd, char *filename, char *cgiargs);
- void clienterror(int fd, char *cause, char *errnum,
- char *shortmsg, char *longmsg);
- void reaper(int sig);
- int main(int argc, char **argv)
- {
- int listenfd, connfd, port, clientlen;
- struct sockaddr_in clientaddr;
- /* Check command line args */
- if (argc != 2) {
- fprintf(stderr, "usage: %s <port>\n", argv[0]);
- exit(1);
- }
- port = atoi(argv[1]);
- listenfd = Open_listenfd(port);
- while (1) {
- clientlen = sizeof(clientaddr);
- connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen);
- doit(connfd);
- Close(connfd);
- }
- }
- /* $end tinymain */
- /*
- * doit - handle one HTTP request/response transaction
- */
- /* $begin doit */
- void doit(int fd)
- {
- int is_static;
- struct stat sbuf;
- char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE];
- char filename[MAXLINE], cgiargs[MAXLINE];
- rio_t rio;
- /* Read request line and headers */
- Rio_readinitb(&rio, fd);
- Rio_readlineb(&rio, buf, MAXLINE);
- sscanf(buf, "%s %s %s", method, uri, version);
- // Print out each Request made from the client
- printf("REQUEST: \n %s", buf);
- if (strcasecmp(method, "GET")) {
- clienterror(fd, method, "501", "Not Implemented",
- "Tiny does not implement this method");
- return;
- }
- read_requesthdrs(&rio);
- /* Parse URI from GET request */
- is_static = parse_uri(uri, filename, cgiargs);
- if (stat(filename, &sbuf) < 0) {
- clienterror(fd, filename, "404", "Not found",
- "Tiny couldn't find this file");
- return;
- }
- if (is_static) { /* Serve static content */
- if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode)) {
- clienterror(fd, filename, "403", "Forbidden",
- "Tiny couldn't read the file");
- return;
- }
- serve_static(fd, filename, sbuf.st_size);
- }
- else { /* Serve dynamic content */
- if (!(S_ISREG(sbuf.st_mode)) || !(S_IXUSR & sbuf.st_mode)) {
- clienterror(fd, filename, "403", "Forbidden",
- "Tiny couldn't run the CGI program");
- return;
- }
- serve_dynamic(fd, filename, cgiargs);
- }
- }
- /* $end doit */
- /*
- * read_requesthdrs - read and parse HTTP request headers
- */
- /* $begin read_requesthdrs */
- void read_requesthdrs(rio_t *rp)
- {
- char buf[MAXLINE];
- Rio_readlineb(rp, buf, MAXLINE);
- // Print out the request headers
- printf("REQUEST HEADERS: \n %s", buf);
- while(strcmp(buf, "\r\n"))
- {
- Rio_readlineb(rp, buf, MAXLINE);
- // Print out each line of the headers
- // untill you find a blank line.
- printf("%s", buf);
- }
- return;
- }
- /* $end read_requesthdrs */
- /*
- * parse_uri - parse URI into filename and CGI args
- * return 0 if dynamic content, 1 if static
- */
- /* $begin parse_uri */
- int parse_uri(char *uri, char *filename, char *cgiargs)
- {
- char *ptr;
- if (!strstr(uri, "cgi-bin")) { /* Static content */
- strcpy(cgiargs, "");
- strcpy(filename, ".");
- strcat(filename, uri);
- if (uri[strlen(uri)-1] == '/')
- strcat(filename, "home.html");
- return 1;
- }
- else { /* Dynamic content */
- ptr = index(uri, '?');
- if (ptr) {
- strcpy(cgiargs, ptr+1);
- *ptr = '\0';
- }
- else
- strcpy(cgiargs, "");
- strcpy(filename, ".");
- strcat(filename, uri);
- return 0;
- }
- }
- /* $end parse_uri */
- /*
- * serve_static - copy a file back to the client
- */
- /* $begin serve_static */
- void serve_static(int fd, char *filename, int filesize)
- {
- int srcfd;
- char *srcp, filetype[MAXLINE], buf[MAXBUF];
- /* Send response headers to client */
- get_filetype(filename, filetype);
- sprintf(buf, "HTTP/1.0 200 OK\r\n");
- sprintf(buf, "%sServer: Tiny Web Server\r\n", buf);
- sprintf(buf, "%sContent-length: %d\r\n", buf, filesize);
- sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, filetype);
- Rio_writen(fd, buf, strlen(buf));
- // Print out the Response headers.
- printf("RESPONSE LINE & HEADERS: \n %s", buf);
- /* Send response body to client */
- srcfd = Open(filename, O_RDONLY, 0);
- srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);
- Close(srcfd);
- Rio_writen(fd, srcp, filesize);
- Munmap(srcp, filesize);
- }
- /*
- * get_filetype - derive file type from file name
- */
- void get_filetype(char *filename, char *filetype)
- {
- 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/jpeg");
- else if (strstr(filename, ".mpeg"))
- strcpy(filetype, "video/mpeg");
- else if (strstr(filename, ".png"))
- strcpy(filetype, "image/png");
- else
- strcpy(filetype, "text/plain");
- }
- /* $end serve_static */
- /*
- * serve_dynamic - run a CGI program on behalf of the client
- */
- /* $begin serve_dynamic */
- void serve_dynamic(int fd, char *filename, char *cgiargs)
- {
- char buf[MAXLINE], *emptylist[] = { NULL };
- // SIGCHLD signal handler
- if (signal(SIGCHLD, reaper) == SIG_ERR)
- unix_error("signal error");
- /* Return first part of HTTP response */
- sprintf(buf, "HTTP/1.0 200 OK\r\n");
- Rio_writen(fd, buf, strlen(buf));
- sprintf(buf, "Server: Tiny Web Server\r\n");
- Rio_writen(fd, buf, strlen(buf));
- if (Fork() == 0) { /* child */
- /* Real server would set all CGI vars here */
- setenv("QUERY_STRING", cgiargs, 1);
- Dup2(fd, STDOUT_FILENO); /* Redirect stdout to client */
- Execve(filename, emptylist, environ); /* Run CGI program */
- }
- // Now handled by signal handler, reaper()
- // Wait(NULL); /* Parent waits for and reaps child */
- }
- /* $end serve_dynamic */
- /*
- * clienterror - returns an error message to the client
- */
- /* $begin clienterror */
- void clienterror(int fd, char *cause, char *errnum,
- char *shortmsg, char *longmsg)
- {
- char buf[MAXLINE], body[MAXBUF];
- /* Build the HTTP response body */
- sprintf(body, "<html><title>Tiny Error</title>");
- sprintf(body, "%s<body bgcolor=""ffffff"">\r\n", body);
- sprintf(body, "%s%s: %s\r\n", body, errnum, shortmsg);
- sprintf(body, "%s<p>%s: %s\r\n", body, longmsg, cause);
- sprintf(body, "%s<hr><em>The Tiny Web server</em>\r\n", body);
- /* Print the HTTP response */
- sprintf(buf, "HTTP/1.0 %s %s\r\n", errnum, shortmsg);
- Rio_writen(fd, buf, strlen(buf));
- sprintf(buf, "Content-type: text/html\r\n");
- Rio_writen(fd, buf, strlen(buf));
- sprintf(buf, "Content-length: %d\r\n\r\n", strlen(body));
- Rio_writen(fd, buf, strlen(buf));
- Rio_writen(fd, body, strlen(body));
- }
- /* $end clienterror */
- /*
- * SIGCHLD signal handler
- */
- void reaper(int sig)
- {
- pid_t pid;
- while((pid = waitpid(-1, NULL, 0)) > 0 )
- if DEBUG
- printf("Handler reaped child %d\n", (int)pid);
- if( errno != ECHILD)
- unix_error("waitpid error");
- return;
- }
Add Comment
Please, Sign In to add comment